mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-27 08:49:47 +00:00
## Summary At 16 px the title bar's hexagon was too small for its C and n to read. Compared in the Windows and macOS title bars on light and dark palettes at 16, 20 and 24 px, 20 px reads clearly, stays close to the menu text and leaves margins in macOS's 28 px bar (24 px nearly filled it). ## Validation - `brand-logo` browser test expects the 20 px title bar logo; `macos-titlebar` still finds it centred and clear of the traffic lights. - `dev-docs/UI_CONVENTIONS.md` records the size.
15 lines
4.5 KiB
Markdown
15 lines
4.5 KiB
Markdown
# UI conventions
|
|
|
|
Shared renderer rules for dialogs, utility windows, icon toggles, surfaces and scrollbars.
|
|
|
|
## Agent conventions
|
|
|
|
- Authentication recovery uses `lib/auth-recovery.ts` and `components/auth-recovery-dialog.tsx`: confirm CodeNomad auth status before showing an expired-login form, reconnect in place to preserve drafts, and never replay failed mutations. Its shared window styles live in `styles/components/auth-recovery.css`.
|
|
- Confirmation dialogs (`components/alert-dialog.tsx`) keep Kobalte's initial focus on Cancel, so Enter never confirms by reflex, while the confirm button stays the filled primary action. Alert-dialog buttons show the accent focus ring on any `:focus` (`styles/components/alert-dialog.css`), including the initial focus of a mouse-opened dialog, so the ring marks the button Enter acts on. Prompts focus their input, where Enter submits. Covered by `tests/browser/alert-dialog.test.ts`.
|
|
- Persistent command/search utility windows use `components/dismissible-window.tsx`: non-modal, no scrim, outside interactions keep them open, and explicit toggles use `.icon-toggle` with `aria-expanded`/`aria-controls`. Keep search state scoped to its instance/session and close it when that view becomes inactive.
|
|
- The `.icon-toggle` active state (`aria-pressed`/`aria-expanded`/`data-active`) is one shared rule in `styles/utilities.css`: one uniform partial accent tint for every palette (an ink of accent leaning 20% toward `--text-on-accent`, then 10% toward `--surface-base`, at 40% opacity, 50% on hover) over the surface beneath, primary-text icon, disabled toggles excluded. It is for icon toggles only: text list rows select through `--list-item-highlight-*` instead (Mission past runs). The only active override is `.tool-call-output-rail`, which keeps its compact output-rail toggles transparent. `tests/browser/icon-toggle-active.test.ts` samples real active toggles on every ready-made palette over the session header (search), sessions sidebar header, right-panel tab bar, user and assistant message cards (speech button), interruption dock header and transcript canvas (overlay windows share the canvas colour): OKLab ΔE ≥ 8 from the surface on the header and ≥ 5 elsewhere, ≥ 6 from the header's idle hover, ≥ 1.4 from active to active hover, icon ≥ 3:1 on both fills.
|
|
- Movable utility windows opt into `DismissibleWindow.draggable` and mark their existing top bar with `data-window-drag-handle`; keep drag geometry shared and controls interactive. `--window-visible-height` bounds their height to the visual viewport; native scrolling and a sticky existing top bar keep results, pagination and drag/close controls reachable.
|
|
- Appearance mode and the saved light/dark selections are independent (`lib/appearance-preferences.ts`). Message/tool cards use the muted surface; preferences use the same secondary surface as the main panels. Show a subtle local rollover with `--surface-hover-overlay` over the preserved selected background, never by substituting a generic panel or the secondary surface; right-panel canvas button rollover overrides live in `styles/panels/control-hover.css`.
|
|
- `index.css` re-anchors `box-sizing: border-box` on every `details > :not(summary)`: the component library resets elements to `box-sizing: inherit`, so folded content would inherit content-box from the browser's own details slot and overflow full-width controls. Keep that rule rather than patching individual disclosures.
|
|
- In-app logos render `components/brand-logo.tsx`: the hexagon cropped to its bounds, black (`CodeNomad-Logo-OnLight.svg`) on light palettes and white (`CodeNomad-Logo-OnDark.svg`) on dark ones, picked in CSS from the palette's appearance; the always-dark loading screen uses the white one. The square app icon (`CodeNomad-Icon.png`) stays out of the page; it serves the browser tab and its badge. Large logos (home page, empty states, loading screen) follow their title, never the window: 4rem tall beside a `text-3xl` title, 3.2rem beside the narrow session column's 1.5rem title, and 5.3rem beside the loading screen's larger title; the title bar's is 20px, the smallest size at which its letters read, which still leaves room in macOS's 28px bar. Resize the logo whenever its title's size changes.
|
|
- Keep the global scrollbar-width default at zero specificity (`:where(...)` in `src/index.css`) so component visibility rules win. The timeline shares the transcript's standard native scrollbar (geometry, rail ownership and thumb drags: `dev-docs/SESSION_HISTORY_NAVIGATION.md`); validate with the full stylesheet and real thumb gestures on mixed-height transcripts.
|