Files

48 lines
2.3 KiB
HTML

{{ define "nav-theme-toggle" }}
<details class="dropdown dropdown-end">
<summary data-theme-toggle class="btn btn-ghost btn-circle list-none" aria-label="Theme settings" aria-haspopup="menu">
<svg class="icon size-5" data-theme-icon aria-hidden="true"><use href="/icons.svg#sun"></use></svg>
</summary>
<ul data-theme-menu role="group" aria-label="Select theme" class="dropdown-content menu bg-base-200 text-base-content rounded-box z-50 w-40 p-2 shadow-lg">
<li role="none">
<button type="button" role="radio" aria-checked="false" class="theme-option" data-value="system">
{{ icon "sun-moon" "size-4" }}
<span>System</span>
{{ icon "check" "size-4 ml-auto text-secondary theme-check invisible" }}
</button>
</li>
<li role="none">
<button type="button" role="radio" aria-checked="false" class="theme-option" data-value="light">
{{ icon "sun" "size-4" }}
<span>Light</span>
{{ icon "check" "size-4 ml-auto text-secondary theme-check invisible" }}
</button>
</li>
<li role="none">
<button type="button" role="radio" aria-checked="false" class="theme-option" data-value="dark">
{{ icon "moon" "size-4" }}
<span>Dark</span>
{{ icon "check" "size-4 ml-auto text-secondary theme-check invisible" }}
</button>
</li>
</ul>
</details>
<script>
// Sync aria-checked on the theme radios before JS has a chance to hydrate
// the full menu. Without this, screen readers pre-hydration announce all
// three options as "not selected." Runs inline so it executes right after
// the menu renders.
(function() {
try {
var pref = localStorage.getItem('theme') || 'system';
document.querySelectorAll('.theme-option').forEach(function(btn) {
var on = btn.dataset.value === pref;
btn.setAttribute('aria-checked', on ? 'true' : 'false');
var check = btn.querySelector('.theme-check');
if (check) check.classList.toggle('invisible', !on);
});
} catch (e) { /* localStorage unavailable; leave defaults */ }
})();
</script>
{{ end }}