'use client'; import Link from 'next/link'; import { ChevronRight } from 'lucide-react'; import { cn } from '@/lib/utils'; /** * A titled group of rows. Settings is a list of lists. * * The gap below is 32px rather than 24px because these are the "blocks within a * screen" of §4, not siblings in a list — at 24px the group titles stopped * reading as titles and the page became one undifferentiated stack of boxes. */ export function SettingsGroup({ title, note, children, }: { title: string; note?: string; children: React.ReactNode; }) { return (

{title}

{children}
{note &&

{note}

}
); } /** Shared by every row shape below, so a group never looks stitched together. */ const rowClasses = 'flex w-full items-center gap-3 px-4 py-3.5 text-left'; const interactiveClasses = 'transition-colors duration-[120ms] ease-standard hover:bg-sunken'; /** * A read-only, navigational, or linking row. * * `href` and `onClick` are alternatives, and one of them must be present for the * row to draw a chevron. A row that shows the chevron and does nothing is the * worst state available here — it is indistinguishable from a broken link, so * the affordance is tied to the destination rather than set by hand. */ export function SettingsRow({ label, value, hint, href, onClick, danger, disabled, }: { label: string; value?: React.ReactNode; hint?: string; href?: string; onClick?: () => void; danger?: boolean; disabled?: boolean; }) { const interactive = Boolean(href ?? onClick) && !disabled; const inner = ( <> {label} {hint && {hint}} {value !== undefined && ( // Shrinkable and truncating, NOT shrink-0: an email long enough to need // the room used to take it from the label, which collapsed to nothing // while the value it was labelling ran on past the bezel. {value} )} {interactive && } ); if (href && !disabled) { return ( {inner} ); } if (onClick && !disabled) { return ( ); } return
{inner}
; } /** * A row carrying a switch. The label is the control's accessible name, so the * whole row is one tap target rather than a label and a separate 20px switch. */ export function SettingsToggle({ label, hint, checked, onChange, disabled, }: { label: string; hint?: string; checked: boolean; onChange: (next: boolean) => void; disabled?: boolean; }) { return ( ); }