Add theming system: custom palettes, per-user colour mode, admin appearance page
- 4 built-in themes (Default, Pastel, High Contrast, Ocean Blue) seeded as JSON files in /config/themes/ on startup; custom themes can be created, edited, and deleted via the new admin Appearance page - All theme tokens applied via JS inline CSS properties (no hardcoded CSS blocks) - New `color_mode` column on users table (migration dd6ad2f2c211); users can override the admin-set global default in Settings - Backend: GET/PATCH /settings/appearance, full CRUD on /settings/themes - Frontend: AdminAppearancePage with theme grid + colour pickers, SettingsPage replaces placeholder with mode selector, useTheme rewritten to fetch from API Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ export interface UserData {
|
||||
full_name: string | null;
|
||||
is_active: boolean;
|
||||
is_admin: boolean;
|
||||
color_mode: string | null;
|
||||
}
|
||||
|
||||
export const getMe = () => api.get<UserData>("/users/me").then((r) => r.data);
|
||||
@@ -202,6 +203,56 @@ export const renameCategory = (id: string, name: string) =>
|
||||
export const deleteCategory = (id: string) =>
|
||||
api.delete(`/documents/categories/${id}`);
|
||||
|
||||
// --- Appearance & Themes ---
|
||||
export interface ThemeColors {
|
||||
primary: string;
|
||||
primary_hover: string;
|
||||
accent: string;
|
||||
accent_hover: string;
|
||||
background: string;
|
||||
surface: string;
|
||||
border: string;
|
||||
text_primary: string;
|
||||
text_muted: string;
|
||||
}
|
||||
|
||||
export interface ThemeDefinition {
|
||||
id: string;
|
||||
label: string;
|
||||
builtin: boolean;
|
||||
light: ThemeColors;
|
||||
dark: ThemeColors;
|
||||
}
|
||||
|
||||
export interface AppearanceSettings {
|
||||
theme: string;
|
||||
default_mode: string;
|
||||
}
|
||||
|
||||
export const getAppearanceSettings = (): Promise<AppearanceSettings> =>
|
||||
api.get<AppearanceSettings>("/settings/appearance").then((r) => r.data);
|
||||
|
||||
export const updateAppearanceSettings = (data: AppearanceSettings): Promise<AppearanceSettings> =>
|
||||
api.patch<AppearanceSettings>("/settings/appearance", data).then((r) => r.data);
|
||||
|
||||
export const getThemes = (): Promise<ThemeDefinition[]> =>
|
||||
api.get<ThemeDefinition[]>("/settings/themes").then((r) => r.data);
|
||||
|
||||
export const createTheme = (data: Omit<ThemeDefinition, "builtin">): Promise<ThemeDefinition> =>
|
||||
api.post<ThemeDefinition>("/settings/themes", data).then((r) => r.data);
|
||||
|
||||
export const updateTheme = (
|
||||
id: string,
|
||||
data: { label?: string; light?: ThemeColors; dark?: ThemeColors }
|
||||
): Promise<ThemeDefinition> =>
|
||||
api.patch<ThemeDefinition>(`/settings/themes/${id}`, data).then((r) => r.data);
|
||||
|
||||
export const deleteTheme = (id: string): Promise<void> =>
|
||||
api.delete(`/settings/themes/${id}`).then((r) => r.data);
|
||||
|
||||
export const updateColorMode = (color_mode: string): Promise<UserData> =>
|
||||
api.patch<UserData>("/users/me/color-mode", { color_mode }).then((r) => r.data);
|
||||
|
||||
// --- Settings (admin only) ---
|
||||
export interface AIProviderUpdate {
|
||||
provider: string;
|
||||
|
||||
Reference in New Issue
Block a user