diff --git a/apps/ui/src/components/views/project-settings-view/project-theme-section.tsx b/apps/ui/src/components/views/project-settings-view/project-theme-section.tsx index d0d7744f..dca0f7b2 100644 --- a/apps/ui/src/components/views/project-settings-view/project-theme-section.tsx +++ b/apps/ui/src/components/views/project-settings-view/project-theme-section.tsx @@ -10,7 +10,11 @@ import { } from '@/components/ui/select'; import { Palette, Moon, Sun, Type } from 'lucide-react'; import { darkThemes, lightThemes, type Theme } from '@/config/theme-options'; -import { UI_SANS_FONT_OPTIONS, UI_MONO_FONT_OPTIONS } from '@/config/ui-font-options'; +import { + UI_SANS_FONT_OPTIONS, + UI_MONO_FONT_OPTIONS, + DEFAULT_FONT_VALUE, +} from '@/config/ui-font-options'; import { cn } from '@/lib/utils'; import { useAppStore } from '@/store/app-store'; import type { Project } from '@/lib/electron'; @@ -27,13 +31,17 @@ export function ProjectThemeSection({ project }: ProjectThemeSectionProps) { setProjectFontMono, } = useAppStore(); const [activeTab, setActiveTab] = useState<'dark' | 'light'>('dark'); - const [fontSans, setFontSansLocal] = useState(project.fontFamilySans || ''); - const [fontMono, setFontMonoLocal] = useState(project.fontFamilyMono || ''); + const [fontSans, setFontSansLocal] = useState( + project.fontFamilySans || DEFAULT_FONT_VALUE + ); + const [fontMono, setFontMonoLocal] = useState( + project.fontFamilyMono || DEFAULT_FONT_VALUE + ); // Sync font state when project changes useEffect(() => { - setFontSansLocal(project.fontFamilySans || ''); - setFontMonoLocal(project.fontFamilyMono || ''); + setFontSansLocal(project.fontFamilySans || DEFAULT_FONT_VALUE); + setFontMonoLocal(project.fontFamilyMono || DEFAULT_FONT_VALUE); }, [project]); const projectTheme = project.theme as Theme | undefined; @@ -58,14 +66,14 @@ export function ProjectThemeSection({ project }: ProjectThemeSectionProps) { const handleFontSansChange = (value: string) => { setFontSansLocal(value); - // Empty string means default, so we pass null to clear the override - setProjectFontSans(project.id, value || null); + // 'default' means use theme default, so we pass null to clear the override + setProjectFontSans(project.id, value === DEFAULT_FONT_VALUE ? null : value); }; const handleFontMonoChange = (value: string) => { setFontMonoLocal(value); - // Empty string means default, so we pass null to clear the override - setProjectFontMono(project.id, value || null); + // 'default' means use theme default, so we pass null to clear the override + setProjectFontMono(project.id, value === DEFAULT_FONT_VALUE ? null : value); }; return ( @@ -214,8 +222,15 @@ export function ProjectThemeSection({ project }: ProjectThemeSectionProps) { {UI_SANS_FONT_OPTIONS.map((option) => ( - - {option.label} + + + {option.label} + ))} @@ -236,8 +251,15 @@ export function ProjectThemeSection({ project }: ProjectThemeSectionProps) { {UI_MONO_FONT_OPTIONS.map((option) => ( - - {option.label} + + + {option.label} + ))} diff --git a/apps/ui/src/config/ui-font-options.ts b/apps/ui/src/config/ui-font-options.ts index 5d40a198..98b77151 100644 --- a/apps/ui/src/config/ui-font-options.ts +++ b/apps/ui/src/config/ui-font-options.ts @@ -5,18 +5,21 @@ * Users must have the fonts installed on their system for them to work. */ +// Sentinel value for "use default font" - Radix Select doesn't allow empty strings +export const DEFAULT_FONT_VALUE = 'default'; + export interface UIFontOption { - value: string; // CSS font-family value (empty string means "use default") + value: string; // CSS font-family value ('default' means "use default") label: string; // Display label for the dropdown } /** * Sans/UI fonts for headings, labels, and general text * - * Empty value means "use the theme default" (Geist Sans for all themes) + * 'default' value means "use the theme default" (Geist Sans for all themes) */ export const UI_SANS_FONT_OPTIONS: readonly UIFontOption[] = [ - { value: '', label: 'Default (Geist Sans)' }, + { value: DEFAULT_FONT_VALUE, label: 'Default (Geist Sans)' }, { value: "'Inter', system-ui, sans-serif", label: 'Inter' }, { value: "'SF Pro', system-ui, sans-serif", label: 'SF Pro' }, { value: "'Source Sans 3', system-ui, sans-serif", label: 'Source Sans' }, @@ -28,10 +31,10 @@ export const UI_SANS_FONT_OPTIONS: readonly UIFontOption[] = [ /** * Mono/code fonts for code blocks, terminals, and monospaced text * - * Empty value means "use the theme default" (Geist Mono for all themes) + * 'default' value means "use the theme default" (Geist Mono for all themes) */ export const UI_MONO_FONT_OPTIONS: readonly UIFontOption[] = [ - { value: '', label: 'Default (Geist Mono)' }, + { value: DEFAULT_FONT_VALUE, label: 'Default (Geist Mono)' }, { value: "'JetBrains Mono', monospace", label: 'JetBrains Mono' }, { value: "'Fira Code', monospace", label: 'Fira Code' }, { value: "'SF Mono', Menlo, Monaco, monospace", label: 'SF Mono' }, @@ -48,7 +51,7 @@ export function getFontLabel( fontValue: string | undefined, options: readonly UIFontOption[] ): string { - if (!fontValue) return options[0].label; + if (!fontValue || fontValue === DEFAULT_FONT_VALUE) return options[0].label; const option = options.find((o) => o.value === fontValue); return option?.label ?? fontValue; } diff --git a/package-lock.json b/package-lock.json index 66065929..c542b728 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "automaker", - "version": "1.0.0", + "version": "0.12.0rc", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "automaker", - "version": "1.0.0", + "version": "0.12.0rc", "hasInstallScript": true, "workspaces": [ "apps/*", @@ -29,7 +29,7 @@ }, "apps/server": { "name": "@automaker/server", - "version": "0.11.0", + "version": "0.12.0", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@anthropic-ai/claude-agent-sdk": "0.1.76", @@ -80,7 +80,7 @@ }, "apps/ui": { "name": "@automaker/ui", - "version": "0.11.0", + "version": "0.12.0", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", "dependencies": {