Files
ForgeLM/.planning/phases/01-hf-model-discovery/01-UI-SPEC.md
T

161 lines
8.7 KiB
Markdown

---
phase: 1
slug: draft-state-ownership
status: draft
shadcn_initialized: false
preset: none
created: 2026-03-28
---
# Phase 1 — UI Design Contract
> Visual and interaction contract for frontend phases. Generated by gsd-ui-researcher, verified by gsd-ui-checker.
---
## Design System
| Property | Value |
|----------|-------|
| Tool | none — existing hand-authored CSS remains the source of truth for Phase 1; shadcn init deferred by default because this phase only defines the contract and does not require component-library adoption |
| Preset | not applicable |
| Component library | none — preserve existing runtime drawer, status card, inline chips, segmented controls, and footer actions |
| Icon library | none required for Phase 1; use text labels and existing native controls before introducing new iconography |
| Font | "Segoe UI Variable", "SF Pro Display", "IBM Plex Sans", system-ui, sans-serif |
---
## Spacing Scale
Declared values (must be multiples of 4):
| Token | Value | Usage |
|-------|-------|-------|
| xs | 4px | Status dots, inline separators, badge internals |
| sm | 8px | Input-support gaps, chip gaps, tight action spacing |
| md | 16px | Default field spacing, card padding, inline validation offset |
| lg | 24px | Section padding, grouped control spacing |
| xl | 32px | Drawer section breaks, footer-to-body separation |
| 2xl | 48px | Major content breaks inside long settings drawers |
| 3xl | 64px | Reserved for page-level or modal-level spacing only |
Exceptions: minimum 44px input and button height for all primary interactive controls; destructive confirmation rows may use 12px vertical padding inside a 44px container.
---
## Typography
| Role | Size | Weight | Line Height |
|------|------|--------|-------------|
| Body | 16px | 400 | 1.5 |
| Label | 12px | 700 | 1.4 |
| Heading | 20px | 700 | 1.2 |
| Display | 28px | 700 | 1.1 |
---
## Color
| Role | Value | Usage |
|------|-------|-------|
| Dominant (60%) | #0a1016 | App background, drawer shell, page canvas |
| Secondary (30%) | #14202d | Cards, grouped sections, saved/live reference surfaces |
| Accent (10%) | #48a6ff | Draft-state badges, selected segmented controls, focused fields, primary save CTA, latest-valid async result indicators |
| Destructive | #f04040 | Discard/revert confirmations, inline invalid-state borders, blocking save errors |
Accent reserved for: dirty badges, active local-vs-remote selectors, selected model chips, the primary `Save changes` action, focus-visible outlines, and explicit live-vs-draft comparison labels; never use accent for all neutral buttons.
---
## Copywriting Contract
| Element | Copy |
|---------|------|
| Primary CTA | Save changes |
| Secondary footer action | Discard changes |
| Confirmation escape action | Keep editing |
| Empty state heading | No draft changes yet |
| Empty state body | Edit any runtime setting to start a draft. Live runtime values keep updating until you choose to save or discard. |
| Error state | Couldn't save your draft. Review the highlighted fields and try again — your unsaved changes are still here. |
| Destructive confirmation | Discard changes: Discard this draft and return to the last saved settings? / Revert to saved: Replace all unsaved edits with the last saved values. |
---
## State Presentation Contract
- The sticky drawer header is the first visual anchor on open: `Draft settings` title, dirty-state summary, and compact `Live now` status reference appear before any editable fields.
- Opening the settings drawer creates a draft from the latest saved baseline and labels the drawer as `Draft settings`.
- The current effective runtime state remains visible as `Live now` reference content in a secondary surface or read-only inline value for any field changed in the draft.
- Dirty fields show three signals together: draft accent border, `Draft` label, and saved/live reference value below the control; color alone is never the only indicator.
- Clean fields render with neutral borders and no draft badge.
- Closing the drawer with unsaved edits hides the drawer and preserves the draft for the same app session; do not show a discard prompt on close or backdrop click.
- `Discard changes` is the UI label for the Phase 1 full-form reset behavior locked in `01-CONTEXT.md`; `Revert to saved` is the destructive confirmation label for completing that same reset. Per-field undo is out of scope.
---
## Interaction Contract
- Polling continues every 3 seconds for operational state, but polling updates may affect only live status surfaces such as readiness, process state, health messaging, and managed-library metadata.
- Polling and async helpers must never overwrite dirty input values, selected folders, provider choice, or selected model while the draft is dirty.
- Folder pickers, file pickers, model rescans, and validation passes are field-scoped updates only; they may update the invoked field and its dependent helper text, not the whole form.
- If multiple async requests exist for the same field, only the latest response may update draft-facing UI; stale responses are ignored silently.
- When a drafted value becomes invalid after rescan or validation, preserve the typed or selected value, mark the field invalid inline, and disable `Save changes` until fixed.
- Resting footer actions for this phase are `Save changes` and `Discard changes`; selecting `Discard changes` expands an inline confirmation row with `Keep editing` and destructive `Revert to saved`. Local-runtime apply/start text remains separate and must always reflect whether saving is required first.
- Busy states disable the triggering button, preserve current field values, and replace button text with in-place progress copy such as `Saving...`, `Scanning...`, or `Searching...`.
- Error messaging appears inline near the affected field when possible; fall back to a single drawer-level error banner only for save failures or cross-field failures.
---
## Component Inventory
- Drawer shell: right-side fixed drawer, full-height, max width 560px, blurred backdrop, sticky header and footer.
- Primary focal point: sticky header block with `Draft settings` title, dirty-state summary, and `Live now` chip/status summary before the overview strip.
- Overview strip: three read-only summary cells for current status, endpoint, and saved model.
- Field groups: card-based sections with 16px internal padding and 18px corner radius.
- Segmented controls: two-option mode switch with clear active state and no icon-only affordances.
- Draft comparison rows: editable control on top, saved/live helper row beneath when dirty.
- Inline validation: destructive border plus one-line message directly under the affected field.
- Confirmation pattern: inline footer confirmation row for discard/revert actions instead of a separate modal.
---
## Accessibility and Motion
- All interactive controls must meet a 44x44px minimum hit target.
- Keyboard order must follow visual order from overview to footer actions.
- `:focus-visible` keeps the 2px accent outline already established in `tauri-app/src/index.css`.
- Body copy and helper text must maintain at least 4.5:1 contrast against their surfaces.
- State changes use opacity, border, and background transitions only, with durations between 150ms and 200ms.
- Respect `prefers-reduced-motion`; suppress scale transforms and animated status pulses when reduced motion is enabled.
---
## Source Notes
- Locked from `D:\Documents\Github\ForgeLM\.planning\ROADMAP.md`: Phase 1 goal and success criteria require explicit live-versus-draft separation, explicit save/cancel/revert semantics, and draft-safe failure recovery.
- Locked from `D:\Documents\Github\ForgeLM\.planning\phases\01-hf-model-discovery\01-CONTEXT.md`: draft lifecycle, preserved close behavior, field-scoped async updates, stale-request ignoring, and invalid-draft preservation.
- Grounded in existing UI from `D:\Documents\Github\ForgeLM\tauri-app\src\index.css`, `D:\Documents\Github\ForgeLM\tauri-app\src\features\runtime\components\RuntimeSettingsDrawer.css`, `D:\Documents\Github\ForgeLM\tauri-app\src\features\runtime\components\RuntimeStatusCard.css`, and `D:\Documents\Github\ForgeLM\tauri-app\src\features\runtime\components\RuntimeSettingsDrawer.tsx`.
- Brand output conventions referenced from `C:\Users\Evandro\.config\opencode\get-shit-done\references\ui-brand.md`.
---
## Registry Safety
| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official | none | not applicable — shadcn not initialized |
| third-party | none | not applicable |
---
## Checker Sign-Off
- [ ] Dimension 1 Copywriting: PASS
- [ ] Dimension 2 Visuals: PASS
- [ ] Dimension 3 Color: PASS
- [ ] Dimension 4 Typography: PASS
- [ ] Dimension 5 Spacing: PASS
- [ ] Dimension 6 Registry Safety: PASS
**Approval:** pending