Add settings panel for theme and text size customization

This commit is contained in:
2026-01-31 12:39:25 +01:00
parent 560dd8e17e
commit 26ee0289ca

View File

@@ -75,6 +75,9 @@ export default function App() {
const [viewingVersion, setViewingVersion] = useState<HistoryEntry | null>(null); const [viewingVersion, setViewingVersion] = useState<HistoryEntry | null>(null);
const [selectedHistoryId, setSelectedHistoryId] = useState<string | null>(null); const [selectedHistoryId, setSelectedHistoryId] = useState<string | null>(null);
const [confirmState, setConfirmState] = useState<ConfirmState | null>(null); const [confirmState, setConfirmState] = useState<ConfirmState | null>(null);
const [settingsOpen, setSettingsOpen] = useState(false);
const [theme, setTheme] = useState<"default" | "light">("default");
const [textSize, setTextSize] = useState(16);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const bodyRef = useRef(body); const bodyRef = useRef(body);
@@ -86,6 +89,14 @@ export default function App() {
bodyRef.current = body; bodyRef.current = body;
}, [body]); }, [body]);
useEffect(() => {
document.body.dataset.theme = theme;
}, [theme]);
useEffect(() => {
document.documentElement.style.setProperty("--base-font-size", `${textSize}px`);
}, [textSize]);
const isViewingHistory = viewingVersion !== null; const isViewingHistory = viewingVersion !== null;
const isDirty = !isViewingHistory && body !== lastPersistedBody; const isDirty = !isViewingHistory && body !== lastPersistedBody;
const hasText = body.trim().length > 0; const hasText = body.trim().length > 0;
@@ -619,21 +630,32 @@ export default function App() {
}, [handleSaveVersion]); }, [handleSaveVersion]);
return ( return (
<div className={`app${sidebarCollapsed ? " app--sidebar-collapsed" : ""}`}> <div className={`app app--theme-${theme}${sidebarCollapsed ? " app--sidebar-collapsed" : ""}`}>
{!sidebarCollapsed ? ( {!sidebarCollapsed ? (
<aside className="sidebar"> <aside className="sidebar">
<div className="sidebar__header"> <div className="sidebar__header">
<div className="sidebar__title-row"> <div className="sidebar__title-row">
<div className="app-title">TextDB</div> <div className="app-title">TextDB</div>
<button <div className="sidebar__actions">
className="icon-button icon-button--ghost" <button
onClick={() => setSidebarCollapsed(true)} className="icon-button icon-button--ghost"
aria-label="Collapse sidebar" onClick={() => setSettingsOpen(true)}
title="Collapse sidebar" aria-label="Open settings"
type="button" title="Settings"
> type="button"
<span aria-hidden="true">&lt;</span> >
</button> <span aria-hidden="true"></span>
</button>
<button
className="icon-button icon-button--ghost"
onClick={() => setSidebarCollapsed(true)}
aria-label="Collapse sidebar"
title="Collapse sidebar"
type="button"
>
<span aria-hidden="true">&lt;</span>
</button>
</div>
</div> </div>
<input <input
className="search" className="search"
@@ -884,6 +906,63 @@ export default function App() {
)} )}
</main> </main>
{settingsOpen ? (
<div className="settings-overlay">
<div
className="settings-overlay__backdrop"
onClick={() => setSettingsOpen(false)}
/>
<div className="settings-panel" role="dialog" aria-modal="true">
<div className="settings-panel__header">
<div className="settings-panel__title">Settings</div>
<button
className="icon-button icon-button--ghost"
onClick={() => setSettingsOpen(false)}
aria-label="Close settings"
title="Close settings"
type="button"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="settings-panel__section">
<label className="settings-panel__label" htmlFor="theme-select">
Theme
</label>
<select
id="theme-select"
className="settings-panel__select"
value={theme}
onChange={(event) =>
setTheme(event.target.value as "default" | "light")
}
>
<option value="default">Default</option>
<option value="light">Bright</option>
</select>
</div>
<div className="settings-panel__section">
<label className="settings-panel__label" htmlFor="text-size">
Text size
</label>
<div className="settings-panel__slider-row">
<input
id="text-size"
className="settings-panel__range"
type="range"
min={12}
max={18}
step={1}
value={textSize}
onChange={(event) => setTextSize(Number(event.target.value))}
/>
<div className="settings-panel__value">{textSize}px</div>
</div>
</div>
</div>
</div>
) : null}
{confirmState ? ( {confirmState ? (
<div className="modal"> <div className="modal">
<div className="modal__overlay" onClick={() => setConfirmState(null)} /> <div className="modal__overlay" onClick={() => setConfirmState(null)} />