Use when creating or modifying UI components, styling, or visual elements related to Settings in OpenChamber.
This skill provides instructions for creating or redesigning Settings pages, informational panels, and configuration interfaces within the OpenChamber application.
Use this as source of truth for new settings UI work.
Theme Preferences or Scaling & Layout when controls are already self-explanatory.Always utilize the standard OpenChamber typography classes defined in packages/ui/src/lib/typography.ts.
typography-ui-header font-semibold text-foreground for the top-most title of a settings page/dialog.typography-ui-header font-medium text-foreground for settings sections (e.g. Notification Events, Session Defaults).typography-ui-header font-medium text-foreground (or font-normal if it reads too loud) for grouped controls inside a section (e.g. Default Tool Output, Diff Layout).typography-ui-label text-foreground. Add tabular-nums if displaying numbers or stats to ensure vertical alignment.font-normal when needed to override).typography-meta text-muted-foreground or typography-small text-muted-foreground for supplemental text.Main wrappers should generally use bg-background or bg-[var(--surface-background)]. Ensure adequate padding (e.g., px-5 py-6 or p-6).
Group related controls with vertical spacing, not mandatory cards.
space-y-3 between logical subsections.p-2 for subsection internal padding.bg-[var(--surface-elevated)] unless there is a clear reason.rounded-md, hover fills) unless there is explicit UX value.When removing cards/background wrappers, spacing must be rebalanced so header ownership stays clear.
mb-1 px-1pt-0 pb-2 px-2mb-8mb-3 style gaps after flattening a section; it makes headers look detached.If the page title already provides enough context, remove redundant local headers and place controls directly below the title.
mb-4 instead of larger section spacing).<div className="space-y-3">
<section className="p-2">...</section>
<section className="p-2">...</section>
</div>
Use for short option sets where button-style segmented choice reads best (e.g. Default Tool Output).
<div className="mt-1 flex flex-wrap items-center gap-1">
<ButtonSmall
variant="outline"
size="xs"
className={cn('!font-normal', isSelected ? 'border-[var(--primary-base)] text-[var(--primary-base)] bg-[var(--primary-base)]/10' : 'text-foreground')}
>
Collapsed
</ButtonSmall>
</div>
Use for mutually exclusive mode/layout settings (e.g. Diff Layout, Diff View Mode).
Radio component from @/components/ui/radio.py-0.5.text-foreground/50.<div role="radiogroup" aria-label="Diff layout" className="mt-1 space-y-0">
<div className="flex w-full items-center gap-2 py-0.5">
<Radio checked={selected} onChange={onSelect} ariaLabel="Diff layout: Dynamic" />
<span className={cn('typography-ui-label font-normal', selected ? 'text-foreground' : 'text-foreground/50')}>Dynamic</span>
</div>
</div>
Use shared Checkbox component from @/components/ui/checkbox for boolean toggles.
gap-2).py-1.5.<div
className="group flex cursor-pointer items-center gap-2 py-1.5"
role="button"
tabIndex={0}
>
<Checkbox checked={value} onChange={setValue} ariaLabel="Show Dotfiles" />
<span className="typography-ui-label text-foreground">Show Dotfiles</span>
</div>
Use consistent label/control columns across settings rows so controls align on a shared vertical line.
flex items-center gap-8w-56 shrink-0w-fit<div className="flex items-center gap-8 py-1.5">
<span className="typography-ui-label text-foreground w-56 shrink-0">Interface Font Size</span>
<div className="flex items-center gap-2 w-fit">...</div>
</div>
If a control is unavailable, disable the control only. Do not dim the label row by default.
When matching visual widths across different rows, compare full row footprint (control + adjacent action buttons), not just input width.
For theme controls in Appearance:
Color Mode header on first line; option chips below it.Light Theme and Dark Theme on one row where possible, wrapping on small widths.<div className="grid grid-cols-1 gap-2 py-1.5 md:grid-cols-[14rem_auto] md:gap-x-8 md:gap-y-2">
<div className="flex min-w-0 items-center gap-2">Light Theme ...</div>
<div className="flex min-w-0 items-center gap-2">Dark Theme ...</div>
</div>
Use compact stepper input (- value +) plus reset button.
NumberInput stepper style over slider + numeric combo in dense settings pages.gap-2).overflow-hidden on mobile for controls; packages/ui/src/styles/mobile.css forces .overflow-hidden { overflow-y: auto !important; }.
Use overflow-x-hidden overflow-y-hidden if you truly need clipping.packages/ui/src/styles/mobile.css enforces min-height: 36px on button. If you build custom segmented controls with <button>, ensure the container height can accommodate that (e.g. h-9).For "override unless empty" fields (e.g. agent Temperature/Top P), keep the value optional and provide a fallback for stepping.
<NumberInput
value={temperature}
fallbackValue={0.7}
onValueChange={setTemperature}
onClear={() => setTemperature(undefined)}
min={0}
max={2}
step={0.1}
inputMode="decimal"
emptyLabel="—"
/>
<div className="flex items-center gap-2 w-fit">
<NumberInput value={fontSize} onValueChange={setFontSize} min={50} max={200} step={5} />
<ButtonSmall variant="ghost" className="h-7 w-7 px-0">...</ButtonSmall>
</div>
Keep form controls in settings compact and aligned.
Input with className="h-7" in dense settings rows.SelectTrigger sizing (avoid size="lg" in settings).ButtonSmall with h-7 w-7 p-0.<div className="flex items-center gap-2">
<Input className="h-7" />
<ButtonSmall variant="outline" size="xs" className="h-7 w-7 p-0" aria-label="Browse">
<RiFolderLine className="h-4 w-4" />
</ButtonSmall>
</div>
For template-like settings (title/message pairs), use a simple grid and flat cells.
grid grid-cols-1 gap-2 md:grid-cols-2 md:gap-3section p-2Input className="h-7"For dense icon/color pickers in settings:
border/ring/subtle background), avoid transform jumps (scale-*).h-7 w-7) and spacing consistent (gap-2).Checkbox, Radio, ButtonSmall size="xs") instead of inline icon logic.visibleSettings subset (like OpenChamberVisualSettings) for multiple tabs (Appearance/Chat) instead of duplicating markup.font-semibold; section header = font-medium; control group header = font-medium (or font-normal if needed); option labels = non-bold.mt-1 px-2 with typography-meta text-muted-foreground/70 (and status token for errors).min-w-0 flex-1 truncate on text containers that sit next to buttons or icons to prevent layout breakage.var(--status-success)) rather than hardcoded hex values or generic Tailwind colors when indicating semantic states.