fix(ui): move theme checkmark when theme changes in Appearance menu
The checkmark in the Appearance theme menu was rendered server-side (if user.Theme == opt.Name), so it never moved after switching themes in the browser. - Always render the check for every theme option, hidden by default, using a new themeCheckClass(name, current) helper that returns the hidden class unless the option is the active theme. - Give each theme button a data-theme attribute and add updateThemeIndicators() to web/src/theme.ts, which reads the applied theme from the body class (theme-<name>) and toggles the hidden class on each check accordingly. - Call updateThemeIndicators() from changeTheme (before the async save and on failure), initializeTheme, and loadUserTheme so the menu stays in sync with the applied theme. - Add unit test for themeCheckClass (templates/utils_test.go) and regenerate templ output.
This commit is contained in:
@@ -41,6 +41,7 @@ const loadTheme = (): void => {
|
||||
// Change: Remove DOM element lookup, accept theme as parameter
|
||||
const changeTheme = async (theme: string): Promise<void> => {
|
||||
applyTheme(theme);
|
||||
updateThemeIndicators();
|
||||
|
||||
// Save to server if logged in
|
||||
const token = localStorage.getItem(TOKEN_STORAGE_KEY);
|
||||
@@ -78,6 +79,7 @@ const loadUserTheme = async (): Promise<void> => {
|
||||
const data = await response.json();
|
||||
if (data.theme) {
|
||||
applyTheme(data.theme as string);
|
||||
updateThemeIndicators();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -85,10 +87,26 @@ const loadUserTheme = async (): Promise<void> => {
|
||||
}
|
||||
};
|
||||
|
||||
// Update the active-theme checkmark in the Appearance menu to follow the
|
||||
// theme currently applied to <body>. Each theme button carries its theme name
|
||||
// in data-theme and a .theme-check element that is shown for the active theme
|
||||
// and hidden for the rest.
|
||||
const updateThemeIndicators = (): void => {
|
||||
const match = document.body.className.match(/theme-([\w-]+)/);
|
||||
const current = match ? match[1] : DEFAULT_THEME;
|
||||
document.querySelectorAll<HTMLElement>(".theme-btn").forEach((btn) => {
|
||||
const check = btn.querySelector(".theme-check");
|
||||
if (!check) return;
|
||||
const theme = btn.getAttribute("data-theme");
|
||||
check.classList.toggle("hidden", theme !== current);
|
||||
});
|
||||
};
|
||||
|
||||
// Initialize theme system
|
||||
const initializeTheme = (): void => {
|
||||
loadTheme();
|
||||
loadUserTheme();
|
||||
updateThemeIndicators();
|
||||
|
||||
// Set theme select value to current theme
|
||||
const themeSelect = document.getElementById(
|
||||
@@ -210,6 +228,7 @@ Alpine.data("theme", () => ({
|
||||
loadTheme,
|
||||
loadUserTheme,
|
||||
loadWoodPaneling,
|
||||
updateThemeIndicators,
|
||||
updateWoodPanelingIndicators,
|
||||
}));
|
||||
|
||||
@@ -221,6 +240,7 @@ export {
|
||||
loadTheme,
|
||||
loadUserTheme,
|
||||
loadWoodPaneling,
|
||||
updateThemeIndicators,
|
||||
updateWoodPanelingIndicators,
|
||||
};
|
||||
export type { ThemeType };
|
||||
|
||||
Reference in New Issue
Block a user