feat(options/appearance): display icon for custom themes

This commit is contained in:
Elian Doran
2026-04-13 17:37:39 +03:00
parent b88eaaeeec
commit 7180569357

View File

@@ -16,7 +16,7 @@ import FormCheckbox from "../../react/FormCheckbox";
import FormGroup from "../../react/FormGroup";
import FormList, { FormListHeader, FormListItem } from "../../react/FormList";
import { FormTextBoxWithUnit } from "../../react/FormTextBox";
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
import { useNote, useNoteIcon, useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
import Icon from "../../react/Icon";
import Modal from "../../react/Modal";
import Slider from "../../react/Slider";
@@ -47,6 +47,51 @@ const LEGACY_THEMES: Theme[] = [
{ val: "dark", title: t("theme.dark_theme"), icon: "bx bx-moon" }
];
interface CustomThemeItemProps {
theme: Theme;
selected: boolean;
onClick: () => void;
}
function CustomThemeItem({ theme, selected, onClick }: CustomThemeItemProps) {
const note = useNote(theme.noteId);
const noteIcon = useNoteIcon(note);
const icon = noteIcon ?? "bx bx-palette";
return (
<FormListItem
key={theme.val}
icon={icon}
selected={selected}
onClick={onClick}
>
{theme.title}
</FormListItem>
);
}
interface CurrentThemeDisplayProps {
theme: Theme | undefined;
fallbackLabel: string;
}
function CurrentThemeDisplay({ theme, fallbackLabel }: CurrentThemeDisplayProps) {
const note = useNote(theme?.noteId);
const noteIcon = useNoteIcon(note);
// For built-in themes, use the icon from the theme object
// For custom themes, use the note icon or fallback to palette
const icon = theme?.icon ?? noteIcon ?? "bx bx-palette";
const label = theme?.title ?? fallbackLabel;
return (
<>
<span className={icon} style={{ marginRight: "8px" }} />
{label}
</>
);
}
interface FontFamilyEntry {
value: FontFamily;
label?: string;
@@ -125,25 +170,19 @@ function UserInterface() {
useEffect(() => {
server.get<Theme[]>("options/user-themes").then((userThemes) => {
// Add placeholder icon for custom themes
setCustomThemes(userThemes.map(t => ({ ...t, icon: "bx bx-palette" })));
setCustomThemes(userThemes);
});
}, []);
// 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 (
<OptionsSection title={t("theme.title")}>
<OptionsRow name="theme" label={t("theme.theme_label")}>
<Dropdown
text={<>
<span className={currentThemeIcon} style={{ marginRight: "8px" }} />
{currentThemeLabel}
</>}
text={<CurrentThemeDisplay theme={currentTheme} fallbackLabel={theme ?? ""} />}
>
<FormListHeader text={t("theme.modern_themes")} />
{MODERN_THEMES.map(t => (
@@ -170,15 +209,13 @@ function UserInterface() {
{customThemes.length > 0 && (
<>
<FormListHeader text={t("theme.custom_themes")} />
{customThemes.map(t => (
<FormListItem
key={t.val}
icon={t.icon}
selected={theme === t.val}
onClick={() => setTheme(t.val)}
>
{t.title}
</FormListItem>
{customThemes.map(ct => (
<CustomThemeItem
key={ct.val}
theme={ct}
selected={theme === ct.val}
onClick={() => setTheme(ct.val)}
/>
))}
</>
)}