diff --git a/web/src/components/AuthFooter.tsx b/web/src/components/AuthFooter.tsx
index 6553af5bc..0ad7b4ff4 100644
--- a/web/src/components/AuthFooter.tsx
+++ b/web/src/components/AuthFooter.tsx
@@ -1,6 +1,8 @@
import { observer } from "mobx-react-lite";
+import { useState } from "react";
import { cn } from "@/lib/utils";
import { workspaceStore } from "@/store";
+import { loadTheme } from "@/utils/theme";
import LocaleSelect from "./LocaleSelect";
import ThemeSelect from "./ThemeSelect";
@@ -9,10 +11,22 @@ interface Props {
}
const AuthFooter = observer(({ className }: Props) => {
+ // Local state for login page theme since we can't persist to server
+ const [localTheme, setLocalTheme] = useState(workspaceStore.state.theme || "default");
+
+ const handleThemeChange = (theme: string) => {
+ // Update local state
+ setLocalTheme(theme);
+ // Update workspace store for immediate UI feedback
+ workspaceStore.state.setPartial({ theme });
+ // Apply theme to DOM
+ loadTheme(theme);
+ };
+
return (
workspaceStore.state.setPartial({ locale })} />
- workspaceStore.state.setPartial({ theme })} />
+
);
});
diff --git a/web/src/components/Settings/PreferencesSection.tsx b/web/src/components/Settings/PreferencesSection.tsx
index 978343e74..df237e023 100644
--- a/web/src/components/Settings/PreferencesSection.tsx
+++ b/web/src/components/Settings/PreferencesSection.tsx
@@ -47,7 +47,10 @@ const PreferencesSection = observer(() => {
-
{t("setting.preference-section.theme")}
+
+ {t("setting.preference-section.theme")}
+ Your personal theme preference (overrides default)
+
diff --git a/web/src/components/Settings/WorkspaceSection.tsx b/web/src/components/Settings/WorkspaceSection.tsx
index 6d0830812..d44052a91 100644
--- a/web/src/components/Settings/WorkspaceSection.tsx
+++ b/web/src/components/Settings/WorkspaceSection.tsx
@@ -81,7 +81,10 @@ const WorkspaceSection = observer(() => {
{t("setting.system-section.title")}
-
Theme
+
+ Default Theme
+ Sets the default theme for all users
+
updatePartialSetting({ theme: value })}
diff --git a/web/src/components/ThemeSelect.tsx b/web/src/components/ThemeSelect.tsx
index 3e0a1a4e2..24d69eb7c 100644
--- a/web/src/components/ThemeSelect.tsx
+++ b/web/src/components/ThemeSelect.tsx
@@ -1,12 +1,14 @@
+import { observer } from "mobx-react-lite";
import { Moon, Palette, Sun, Wallpaper } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { workspaceStore } from "@/store";
+import { workspaceStore, userStore } from "@/store";
import { THEME_OPTIONS } from "@/utils/theme";
interface ThemeSelectProps {
value?: string;
onValueChange?: (theme: string) => void;
className?: string;
+ showEffectiveTheme?: boolean;
}
const THEME_ICONS: Record = {
@@ -16,8 +18,13 @@ const THEME_ICONS: Record = {
whitewall: ,
};
-const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {}) => {
+const ThemeSelect = observer(({ value, onValueChange, className, showEffectiveTheme = false }: ThemeSelectProps = {}) => {
const currentTheme = value || workspaceStore.state.theme || "default";
+
+ // Calculate effective theme (user preference overrides workspace default)
+ const effectiveTheme = userStore.state.userGeneralSetting?.theme || workspaceStore.state.theme || "default";
+
+ const displayTheme = showEffectiveTheme ? effectiveTheme : currentTheme;
const handleThemeChange = (newTheme: Theme) => {
if (onValueChange) {
@@ -32,6 +39,9 @@ const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {})
+ {showEffectiveTheme && effectiveTheme !== currentTheme && (
+ (effective: {effectiveTheme})
+ )}
@@ -40,12 +50,15 @@ const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {})
{THEME_ICONS[option.value]}
{option.label}
+ {showEffectiveTheme && option.value === effectiveTheme && (
+ ✓
+ )}
))}
);
-};
+});
export default ThemeSelect;