'use client'; import type { ReactNode } from 'react'; import Link from 'next/link'; import * as Icons from '../Icons'; // Direct import from the theme module, not from '@/lib/config': the config // index pulls in `fs` and cannot be bundled into a client component. import { resolveTheme } from '@/lib/config/theme'; import type { SettingsYaml } from '@/lib/config/schema'; import type { Settings } from './types'; /** * One labelled block of related switches. * * The features panel was a single flat grid of identical cards, so nothing said * which switches belonged together — and a switch that publishes private notes * looked exactly like one that controls a fade (#510). */ export function FeatureGroup({ icon, title, description, chip, children, }: { icon: ReactNode; title: string; description: string; /** Short marker for a group that needs its own weight, e.g. what visitors see. */ chip?: string; children: ReactNode; }) { return (
{icon} {title} {chip && {chip}} {description}
{children}
); } /** * A switch inside a group panel. Deliberately lighter than a toggle card: these * are settings *of* the panel they sit in, and rendering them as peers of the * top-level cards is what hid the structure in the first place. */ export function SettingRow({ title, description, checked, onToggle, disabled, hint, indented, }: { title: string; description: string; checked: boolean; onToggle: () => void; /** A row whose parent switch is off — shown, but inert and explained. */ disabled?: boolean; hint?: string; indented?: boolean; }) { return ( ); } /** * One switch in a feature list: a single dense line instead of a card. Cards * gave every switch the same weight, so a fade and a whole page looked alike; * rows grouped by meaning let the group heading carry that weight instead. * The optional link sits beside the switch, not inside it — a link nested in * a button is invalid and swallows the click. */ export function FeatureRow({ icon, title, description, checked, onToggle, href, }: { icon: ReactNode; title: string; description: string; checked: boolean; onToggle: () => void; /** Where this feature is configured beyond on/off. */ href?: string; }) { return (
{/* Reserved even without a link, so every switch lines up in one column. */} {href ? ( Configure → ) : (
); } /** * The theme as the site resolves it. A preset name the form does not know (a * hand-edited typo) falls back to the default instead of taking the panel down. */ export function effectiveTheme(raw: Settings['theme']) { try { return resolveTheme(raw as SettingsYaml['theme']); } catch { return resolveTheme(undefined); } }