import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { invoke } from '@tauri-apps/api/core'; import { LayoutGrid, Maximize2, Palette, Sliders, Type, ZoomIn } from 'lucide-react'; import { useAuthStore } from '../../store/authStore'; import { LIBRARY_GRID_MAX_COLUMNS_MAX, LIBRARY_GRID_MAX_COLUMNS_MIN, } from '../../store/authStoreDefaults'; import type { SeekbarStyle, WindowButtonStyle } from '../../store/authStoreTypes'; import { useFontStore, FontId } from '../../store/fontStore'; import { useThemeStore } from '../../store/themeStore'; import { IS_LINUX, IS_WINDOWS } from '../../utils/platform'; import SettingsSubSection from '../SettingsSubSection'; import { SettingsGroup } from './SettingsGroup'; import { SettingsToggle } from './SettingsToggle'; import { SettingsSubCard, SettingsField, SettingsValue } from './SettingsSubCard'; import { SettingsSegmented, type SegmentedOption } from './SettingsSegmented'; import { SeekbarPreview } from '@/features/waveform'; import WindowButtonPreview from '../WindowButtonPreview'; export function AppearanceTab() { const { t } = useTranslation(); const auth = useAuthStore(); const theme = useThemeStore(); const fontStore = useFontStore(); const [isTilingWm, setIsTilingWm] = useState(false); useEffect(() => { if (!IS_LINUX) return; invoke('is_tiling_wm_cmd').then(setIsTilingWm).catch(() => {}); }, []); return ( <> } >
{t('settings.libraryGridMaxColumnsPerfHint')}
auth.setLibraryGridMaxColumns(Number(e.target.value))} aria-valuemin={LIBRARY_GRID_MAX_COLUMNS_MIN} aria-valuemax={LIBRARY_GRID_MAX_COLUMNS_MAX} aria-valuenow={auth.libraryGridMaxColumns} /> {auth.libraryGridMaxColumns}
} >
{!IS_WINDOWS && ( <>
)} {IS_LINUX && !isTilingWm && ( {auth.useCustomTitlebar && ( <>
{(['dots', 'dotsGlyph', 'flat', 'pill', 'outline', 'glyph'] as WindowButtonStyle[]).map(style => ( auth.setWindowButtonStyle(style)} /> ))}
)} )}
} >
{(() => { const presets = [80, 90, 100, 110, 125, 150]; const currentPct = Math.round(fontStore.uiScale * 100); // Snap a legacy off-preset value to the closest preset so one // button is always marked active. const activePct = presets.includes(currentPct) ? currentPct : presets.reduce( (best, p) => (Math.abs(p - currentPct) < Math.abs(best - currentPct) ? p : best), presets[0], ); const options: SegmentedOption[] = presets.map(p => ({ id: String(p), label: `${p}%`, })); return ( fontStore.setUiScale(parseInt(id, 10) / 100)} /> ); })()}
} >
{( [ // Accessibility-first: OpenDyslexic at the top so dyslexic // readers don't have to scroll past 14 sans-serifs to find it. { id: 'opendyslexic', label: 'OpenDyslexic', stack: "'OpenDyslexic', sans-serif", hint: t('settings.fontHintOpenDyslexic') }, { id: 'inter', label: 'Inter', stack: "'Inter Variable', sans-serif" }, { id: 'outfit', label: 'Outfit', stack: "'Outfit Variable', sans-serif" }, { id: 'dm-sans', label: 'DM Sans', stack: "'DM Sans Variable', sans-serif" }, { id: 'nunito', label: 'Nunito', stack: "'Nunito Variable', sans-serif" }, { id: 'rubik', label: 'Rubik', stack: "'Rubik Variable', sans-serif" }, { id: 'space-grotesk', label: 'Space Grotesk', stack: "'Space Grotesk Variable', sans-serif" }, { id: 'figtree', label: 'Figtree', stack: "'Figtree Variable', sans-serif" }, { id: 'manrope', label: 'Manrope', stack: "'Manrope Variable', sans-serif" }, { id: 'plus-jakarta-sans', label: 'Plus Jakarta Sans', stack: "'Plus Jakarta Sans Variable', sans-serif" }, { id: 'lexend', label: 'Lexend', stack: "'Lexend Variable', sans-serif" }, { id: 'geist', label: 'Geist', stack: "'Geist Variable', sans-serif" }, { id: 'jetbrains-mono', label: 'JetBrains Mono', stack: "'JetBrains Mono Variable', monospace" }, { id: 'golos-text', label: 'Golos Text', stack: "'Golos Text Variable', sans-serif" }, { id: 'unbounded', label: 'Unbounded', stack: "'Unbounded Variable', sans-serif" }, ] as { id: FontId; label: string; stack: string; hint?: string }[] ).map(f => ( ))}
} >
{(['truewave', 'pseudowave', 'linedot', 'bar', 'thick', 'segmented', 'neon', 'pulsewave', 'particletrail', 'liquidfill', 'retrotape'] as SeekbarStyle[]).map(style => ( auth.setSeekbarStyle(style)} /> ))}
} >
{(['large', 'small'] as const).map(size => ( ))}
); }