Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion web/src/components/AuthFooter.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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 (
<div className={cn("mt-4 flex flex-row items-center justify-center w-full gap-2", className)}>
<LocaleSelect value={workspaceStore.state.locale} onChange={(locale) => workspaceStore.state.setPartial({ locale })} />
<ThemeSelect value={workspaceStore.state.theme} onValueChange={(theme) => workspaceStore.state.setPartial({ theme })} />
<ThemeSelect value={localTheme} onValueChange={handleThemeChange} />
</div>
);
});
Expand Down
5 changes: 4 additions & 1 deletion web/src/components/Settings/PreferencesSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ const PreferencesSection = observer(() => {
</div>

<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.preference-section.theme")}</span>
<div className="flex flex-col">
<span>{t("setting.preference-section.theme")}</span>
<span className="text-xs text-muted-foreground">Your personal theme preference (overrides default)</span>
</div>
<ThemeSelect value={setting.theme} onValueChange={handleThemeChange} />
</div>

Expand Down
5 changes: 4 additions & 1 deletion web/src/components/Settings/WorkspaceSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ const WorkspaceSection = observer(() => {
<Separator />
<p className="font-medium text-foreground">{t("setting.system-section.title")}</p>
<div className="w-full flex flex-row justify-between items-center">
<span>Theme</span>
<div className="flex flex-col">
<span>Default Theme</span>
<span className="text-xs text-muted-foreground">Sets the default theme for all users</span>
</div>
<ThemeSelect
value={workspaceGeneralSetting.theme || "default"}
onValueChange={(value: string) => updatePartialSetting({ theme: value })}
Expand Down
19 changes: 16 additions & 3 deletions web/src/components/ThemeSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { observer } from "mobx-react-lite";

Check failure on line 1 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

Delete `import·{·observer·}·from·"mobx-react-lite";⏎`
import { Moon, Palette, Sun, Wallpaper } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";

Check failure on line 3 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

Insert `observer·}·from·"mobx-react-lite";⏎import·{·`
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<string, JSX.Element> = {
Expand All @@ -16,8 +18,13 @@
whitewall: <Wallpaper className="w-4 h-4" />,
};

const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {}) => {
const ThemeSelect = observer(({ value, onValueChange, className, showEffectiveTheme = false }: ThemeSelectProps = {}) => {
const currentTheme = value || workspaceStore.state.theme || "default";

Check failure on line 23 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

Delete `··`
// Calculate effective theme (user preference overrides workspace default)
const effectiveTheme = userStore.state.userGeneralSetting?.theme || workspaceStore.state.theme || "default";

Check failure on line 26 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

Delete `··`
const displayTheme = showEffectiveTheme ? effectiveTheme : currentTheme;

Check failure on line 27 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

'displayTheme' is assigned a value but never used

const handleThemeChange = (newTheme: Theme) => {
if (onValueChange) {
Expand All @@ -32,6 +39,9 @@
<SelectTrigger className={className}>
<div className="flex items-center gap-2">
<SelectValue placeholder="Select theme" />
{showEffectiveTheme && effectiveTheme !== currentTheme && (
<span className="text-xs text-muted-foreground">(effective: {effectiveTheme})</span>
)}
</div>
</SelectTrigger>
<SelectContent>
Expand All @@ -40,12 +50,15 @@
<div className="flex items-center gap-2">
{THEME_ICONS[option.value]}
<span>{option.label}</span>
{showEffectiveTheme && option.value === effectiveTheme && (

Check failure on line 53 in web/src/components/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / static-checks

Replace `(⏎················<span·className="text-xs·text-green-600">✓</span>⏎··············)` with `<span·className="text-xs·text-green-600">✓</span>`
<span className="text-xs text-green-600">✓</span>
)}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
);
};
});

export default ThemeSelect;
Loading