From b88eaaeeec96da021169aca37c2ed46e2eea37e2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Mon, 13 Apr 2026 17:34:49 +0300 Subject: [PATCH] feat(options/appearance): group and add icons to theme selector --- .../src/translations/en/translation.json | 15 ++-- .../type_widgets/options/appearance.tsx | 82 +++++++++++++++---- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 7b6a16c753..dad15c29f6 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -1234,12 +1234,15 @@ "title": "User Interface", "theme_label": "Application theme", "override_theme_fonts_label": "Override theme fonts", - "auto_theme": "Legacy (Follow system color scheme)", - "light_theme": "Legacy (Light)", - "dark_theme": "Legacy (Dark)", - "triliumnext": "Trilium (Follow system color scheme)", - "triliumnext-light": "Trilium (Light)", - "triliumnext-dark": "Trilium (Dark)", + "auto_theme": "Follow system color scheme", + "light_theme": "Light", + "dark_theme": "Dark", + "triliumnext": "Follow system color scheme", + "triliumnext-light": "Light", + "triliumnext-dark": "Dark", + "modern_themes": "Modern", + "legacy_themes": "Legacy", + "custom_themes": "Custom", "layout": "Layout", "layout-vertical-title": "Vertical", "layout-horizontal-title": "Horizontal", diff --git a/apps/client/src/widgets/type_widgets/options/appearance.tsx b/apps/client/src/widgets/type_widgets/options/appearance.tsx index c6de5ff760..cd2acfa13e 100644 --- a/apps/client/src/widgets/type_widgets/options/appearance.tsx +++ b/apps/client/src/widgets/type_widgets/options/appearance.tsx @@ -11,10 +11,10 @@ import server from "../../../services/server"; import { isElectron, isMobile, reloadFrontendApp, restartDesktopApp } from "../../../services/utils"; import { VerticalLayoutIcon } from "../../buttons/global_menu"; import Button from "../../react/Button"; +import Dropdown from "../../react/Dropdown"; import FormCheckbox from "../../react/FormCheckbox"; import FormGroup from "../../react/FormGroup"; import FormList, { FormListHeader, FormListItem } from "../../react/FormList"; -import FormSelect from "../../react/FormSelect"; import { FormTextBoxWithUnit } from "../../react/FormTextBox"; import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; import Icon from "../../react/Icon"; @@ -31,16 +31,20 @@ const MIN_CONTENT_WIDTH = 640; interface Theme { val: string; title: string; + icon?: string; noteId?: string; } -const BUILTIN_THEMES: Theme[] = [ - { val: "next", title: t("theme.triliumnext") }, - { val: "next-light", title: t("theme.triliumnext-light") }, - { val: "next-dark", title: t("theme.triliumnext-dark") }, - { val: "auto", title: t("theme.auto_theme") }, - { val: "light", title: t("theme.light_theme") }, - { val: "dark", title: t("theme.dark_theme") } +const MODERN_THEMES: Theme[] = [ + { val: "next", title: t("theme.triliumnext"), icon: "bx bx-sun bx-flip-horizontal" }, + { val: "next-light", title: t("theme.triliumnext-light"), icon: "bx bx-sun" }, + { val: "next-dark", title: t("theme.triliumnext-dark"), icon: "bx bx-moon" } +]; + +const LEGACY_THEMES: Theme[] = [ + { val: "auto", title: t("theme.auto_theme"), icon: "bx bx-sun bx-flip-horizontal" }, + { val: "light", title: t("theme.light_theme"), icon: "bx bx-sun" }, + { val: "dark", title: t("theme.dark_theme"), icon: "bx bx-moon" } ]; interface FontFamilyEntry { @@ -115,26 +119,70 @@ export default function AppearanceSettings() { function UserInterface() { const [ theme, setTheme ] = useTriliumOption("theme", true); - const [ themes, setThemes ] = useState([]); + const [ customThemes, setCustomThemes ] = useState([]); const [ newLayout, setNewLayout ] = useTriliumOptionBool("newLayout"); const [ layoutOrientation, setLayoutOrientation ] = useTriliumOption("layoutOrientation", true); useEffect(() => { server.get("options/user-themes").then((userThemes) => { - setThemes([ - ...BUILTIN_THEMES, - ...userThemes - ]); + // Add placeholder icon for custom themes + setCustomThemes(userThemes.map(t => ({ ...t, icon: "bx bx-palette" }))); }); }, []); + // Find current theme for display + const allThemes = [...MODERN_THEMES, ...LEGACY_THEMES, ...customThemes]; + const currentTheme = allThemes.find(t => t.val === theme); + const currentThemeLabel = currentTheme?.title ?? theme ?? ""; + const currentThemeIcon = currentTheme?.icon ?? "bx bx-palette"; + return ( - + + + {currentThemeLabel} + } + > + + {MODERN_THEMES.map(t => ( + setTheme(t.val)} + > + {t.title} + + ))} + + {LEGACY_THEMES.map(t => ( + setTheme(t.val)} + > + {t.title} + + ))} + {customThemes.length > 0 && ( + <> + + {customThemes.map(t => ( + setTheme(t.val)} + > + {t.title} + + ))} + + )} + {!isMobile() && <>