* fix(ui): make composer keyboard interactions consistent * docs(settings): refine description visibility guidance --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
90 lines
5.4 KiB
Markdown
90 lines
5.4 KiB
Markdown
---
|
|
name: settings-ui-patterns
|
|
description: Use when creating or modifying OpenChamber Settings pages, dialogs, controls, configuration surfaces, responsive Settings layouts, or Settings search behavior.
|
|
---
|
|
|
|
# Settings UI Patterns
|
|
|
|
## Required Companion Skills
|
|
|
|
- Load `theme-system` for colors, buttons, icons, and visual states.
|
|
- Load `locale-ui-patterns` for every visible string, tooltip, placeholder, and accessible label.
|
|
- Load `ui-api-decoupling` when a setting reads/writes runtime data or adds a capability.
|
|
|
|
When examples conflict, shared component/theme and localization contracts win. Stop on unresolved material conflicts.
|
|
|
|
## Canonical Direction
|
|
|
|
Settings are built from the shared primitives in
|
|
`packages/ui/src/components/sections/shared/SettingsSection.tsx`,
|
|
`SettingsPageLayout.tsx`, and `SettingsInfoHint.tsx`. Never hand-roll page
|
|
chrome, section headers, field rows, checkbox rows, or info tooltips with raw
|
|
divs — use the primitives, and extend them (in the shared file) when a new
|
|
shape is genuinely missing.
|
|
|
|
- Flat hierarchy through spacing and typography; no cards, boxed backgrounds, or row chrome.
|
|
- Secondary helper text is hidden behind an info icon (`info` prop) by default; the default view stays quiet.
|
|
- Controls have one standard size (`h-9` / select `size="settings"`) and capped widths — no full-bleed inputs.
|
|
- Layouts respond to the settings pane width via container queries (`@xl:` / `@3xl:`), never viewport `sm:`/`lg:` breakpoints (the pane is much narrower than the viewport inside the dialog).
|
|
- Checkbox/radio state comes before labels; selected states are subtle and never shift layout.
|
|
|
|
## Load References By Task
|
|
|
|
| Task | Required reference |
|
|
|---|---|
|
|
| Page skeleton, sections, hierarchy, nav placement, spacing, columns, responsiveness | `references/layout.md` |
|
|
| Field rows, checkboxes, radios, chips, selects, inputs, numeric steppers, info hints | `references/controls.md` |
|
|
| Adding/moving controls, pages, availability, anchors, or search entries | `references/search.md` |
|
|
|
|
Load each reference whose task branch applies; reference loading is complete when layout, control, and search implications are each classified.
|
|
|
|
## Quick Primitive Selection
|
|
|
|
| Need | Shared primitive |
|
|
|---|---|
|
|
| Page wrapper (title, description, save status, scrolling, `@container`) | `SettingsPageLayout` |
|
|
| Titled block with divider | `SettingsSection` (`divider={false}` for the first one) |
|
|
| Label left / control right | `SettingsFieldRow` |
|
|
| Label above control (two-column cells, wide controls) | `SettingsStackedField` |
|
|
| Boolean | `SettingsCheckboxRow` |
|
|
| Mutually exclusive list | `SettingsRadioGroup` + `SettingsRadioOption` |
|
|
| Short segmented options | `SettingsChipGroup` |
|
|
| Sub-cluster with a quiet L3 title inside a section | `SettingsControlGroup` |
|
|
| Two-column area on wide panes | `SettingsTwoColumn` |
|
|
| Helper text on demand (hover + tap) | `info` prop or `SettingsInfoHint` |
|
|
|
|
Do not introduce raw `<Tooltip>`-based info icons, direct Remixicon components, hardcoded user-facing strings, or one-off color/button systems. New icons: reference a Remix icon name in code, then run `bun run icons:generate` to add it to the sprite.
|
|
|
|
## Description Policy (info hints)
|
|
|
|
- Explanatory prose goes behind the info icon via the `info` prop by default.
|
|
- When labels alone cannot explain the differences, consequences, or conditions needed to choose a setting, use a title, a visible description, then checkbox or radio controls. Large-text paste modes and send shortcuts with expanded-composer exceptions need this explanation. Having multiple options or a group title alone does not require a description; see `references/controls.md` for composition.
|
|
- Stays visible: security/data-loss warnings, destructive consequences, required syntax/placeholder lists the user reads while typing, dynamic status, empty states, validation errors, active-flow wizard instructions.
|
|
- Mixed text: keep the warning sentence visible, move the explanation to `info`.
|
|
|
|
## Save Feedback
|
|
|
|
`SettingsPageLayout showSaveStatus` renders the shared quiet indicator: success is silent, "Saving…" appears only past ~500 ms, failures show "Save failed". Anything persisted through `updateDesktopSettings` reports automatically; page-specific APIs must call `reportSettingsSaveState` from `@/lib/persistence`. Never add per-page save badges or success toasts for ordinary setting writes.
|
|
|
|
## Settings Search Contract
|
|
|
|
Every stable Settings control addition or move must consider search in the same change:
|
|
|
|
- explicit registry item in `packages/ui/src/lib/settings/search.ts` when searchable;
|
|
- matching `data-settings-item` anchor (primitives accept `settingsItem`);
|
|
- localized title/description keys;
|
|
- availability matching actual render conditions;
|
|
- when a control moves to another page, update the item's `page` too.
|
|
|
|
Dynamic entity rows normally are not indexed. Load `references/search.md` for exact rules.
|
|
|
|
## Completion Criteria
|
|
|
|
- Built from shared primitives; no ad-hoc page/section/row markup.
|
|
- Description placement follows the policy above; warnings/syntax/status remain visible.
|
|
- Container-query (`@xl:`/`@3xl:`) responsiveness — no viewport breakpoints in pane content.
|
|
- Controls use the standard size and width caps; no stretched full-width inputs.
|
|
- Localized visible and accessibility text everywhere.
|
|
- Search registry, anchor, page, localization, and availability agree.
|
|
- Nearby Settings precedent and relevant tests remain consistent.
|