import { useState, useEffect } from 'react'; import { getConfig, updateConfig, ApiError } from '../../../lib/api'; import type { SiteConfig } from '../../../lib/types'; export default function Settings() { const [config, setConfig] = useState>({}); const [alert, setAlert] = useState<{ msg: string; type: 'success' | 'error' } | null>(null); useEffect(() => { getConfig() .then(setConfig) .catch(() => showAlert('Failed to load settings from server.', 'error')); }, []); function showAlert(msg: string, type: 'success' | 'error') { setAlert({ msg, type }); setTimeout(() => setAlert(null), 5000); } function update(key: keyof SiteConfig, value: string) { setConfig(prev => ({ ...prev, [key]: value })); } async function handleSubmit(e: React.FormEvent) { e.preventDefault(); try { await updateConfig(config); showAlert('Settings saved. Refresh to see changes.', 'success'); } catch (e) { showAlert(e instanceof ApiError ? `Error: ${e.message}` : 'Failed to save settings.', 'error'); } } return (
{alert && (
{alert.msg}
)}

Identity

update('title', v)} /> update('subtitle', v)} /> update('welcome_title', v)} /> update('welcome_subtitle', v)} />
update('favicon', v)} hint="Icon shown in browser tabs." />

Appearance

Salon and Salon Noir are tuned for the gallery aesthetic.