91 lines
2.3 KiB
Text
91 lines
2.3 KiB
Text
package modules
|
|
|
|
import (
|
|
"maot-shortner/web/templates/components/button"
|
|
"maot-shortner/web/templates/components/icon"
|
|
)
|
|
|
|
type ThemeSwitcherProps struct {
|
|
Class string
|
|
}
|
|
|
|
templ ThemeSwitcher(props ...ThemeSwitcherProps) {
|
|
{{ var p ThemeSwitcherProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
<script nonce={ templ.GetNonce(ctx) }>
|
|
(function() {
|
|
// Get current theme preference (system, light, or dark)
|
|
function getThemePreference() {
|
|
return localStorage.getItem('themePreference') || 'system';
|
|
}
|
|
|
|
// Apply theme based on preference
|
|
function applyTheme() {
|
|
const preference = getThemePreference();
|
|
let isDark = false;
|
|
|
|
if (preference === 'system') {
|
|
// Use system preference
|
|
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
} else {
|
|
// Use explicit preference
|
|
isDark = preference === 'dark';
|
|
}
|
|
|
|
document.documentElement.classList.toggle('dark', isDark);
|
|
|
|
// Dispatch event for compatibility
|
|
document.dispatchEvent(new CustomEvent('theme-changed'));
|
|
}
|
|
|
|
// Toggle between light and dark (system only on initial state)
|
|
function cycleTheme() {
|
|
const current = getThemePreference();
|
|
let next;
|
|
|
|
if (current === 'system') {
|
|
// First click from system state - determine based on current appearance
|
|
const isDarkNow = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
next = isDarkNow ? 'light' : 'dark';
|
|
} else {
|
|
// Toggle between light and dark
|
|
next = current === 'light' ? 'dark' : 'light';
|
|
}
|
|
|
|
localStorage.setItem('themePreference', next);
|
|
applyTheme();
|
|
}
|
|
|
|
// Initialize theme
|
|
applyTheme();
|
|
|
|
// Listen for system theme changes
|
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
if (getThemePreference() === 'system') {
|
|
applyTheme();
|
|
}
|
|
});
|
|
|
|
// Use event delegation for click handling
|
|
document.addEventListener('click', (e) => {
|
|
const themeSwitcher = e.target.closest('[data-theme-switcher]');
|
|
if (themeSwitcher) {
|
|
e.preventDefault();
|
|
cycleTheme();
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
@button.Button(button.Props{
|
|
Size: button.SizeIcon,
|
|
Variant: button.VariantGhost,
|
|
Class: p.Class,
|
|
Attributes: templ.Attributes{
|
|
"data-theme-switcher": "true",
|
|
},
|
|
}) {
|
|
@icon.Eclipse(icon.Props{Size: 20})
|
|
}
|
|
}
|