docs(spec): Phase 2B form layout (fullscreen login)

Two-column CSS Grid for login forms, sticky save bar, and dirty-state
header subtitle. Other item types stay single-column with the polish
applied. Stacks to single column at <=720px viewport.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-02 12:55:07 -04:00
parent b1af0a11bc
commit 8bf21501a5

View File

@@ -0,0 +1,134 @@
# Phase 2B: Form Layout (Fullscreen Login)
**Date:** 2026-05-02
**Status:** Spec, awaiting review
**Surface:** Browser extension fullscreen vault UI (`extension/src/vault/`)
**Parent spec:** `docs/superpowers/specs/2026-04-30-relicario-fullscreen-ux-redesign-design.md` (Section A)
## Goal
Give the fullscreen login form a desktop-class layout: two-column field arrangement, sticky save bar, and a header that reflects dirty state and save shortcut. Other item types stay single-column for now.
## Non-goals
- Two-column layout for `secure_note`, `identity`, `card`, `key`, `totp`, `document` — single-column stays.
- Popup form changes — popup keeps its existing single-column layout.
- New affordances — Phase 2A already shipped the 8 smart inputs.
- Three-pane shell, keyboard nav, command palette — deferred to Phase 3.
## Layout
### Two-column grid (login only)
```
┌────────────────────────────────────────────────────────────┐
│ ◀ new login ⌘+S to save │
│ unsaved · esc to cancel │
├──────────────────────────┬─────────────────────────────────┤
│ IDENTITY │ CREDENTIALS │
│ title [required] │ username │
│ url + ⤓ │ password ⊙ ↻ │
│ group (autocomplete) │ strength: ████░ │
│ │ totp secret ◫ │
│ │ live: 492 837 · 23s │
├──────────────────────────┴─────────────────────────────────┤
│ NOTES │
│ ▾ custom sections ▸ attachments │
├────────────────────────────────────────────────────────────┤
│ STICKY SAVE BAR [cancel] [save] │
└────────────────────────────────────────────────────────────┘
```
### CSS rules
- Form pane content: `max-width: 960px`, `margin: 0 auto`.
- Two-column wrapper: `display: grid; grid-template-columns: 1fr 1fr; gap: 24px;`.
- Below 720px viewport: `grid-template-columns: 1fr` (single column stack). Use a single `@media (max-width: 720px)` query.
- Notes / custom sections / attachments live in a sibling block below the grid, full-width.
### Column assignment (login)
**Left column — IDENTITY:**
- title (required pill)
- url + `⤓` fill-from-tab button + hostname chip below
- group input + datalist autocomplete
**Right column — CREDENTIALS:**
- username
- password + `⊙` reveal + `↻` generate; strength bar renders directly below the input
- totp secret + `◫` QR button; live preview renders directly below the input
**Full-width below grid:**
- notes (with `≡` mono toggle)
- custom sections / fields disclosure
- attachments disclosure
The strength bar and TOTP preview already render inline in Phase 2A — no changes needed beyond ensuring they fit within the column width.
### Section headers
Each column gets a small uppercase section header per the parent spec's typography rules:
- `text-transform: uppercase; letter-spacing: 1px; font-weight: 500;`
- 1px bottom border in `var(--border-subtle)`.
- Color: `var(--text-muted)`.
## Sticky save bar
- Position: `sticky; bottom: 0;` inside the form pane's scroll container.
- Background: `var(--bg-pane)` with a 24px gradient fade above (`linear-gradient(to top, var(--bg-pane) 60%, transparent)`).
- Content: right-aligned `[cancel] [save]` buttons with 12px gap.
- The save button reflects validity state — disabled when required fields are empty.
- z-index: above form content, below modals/toasts.
The fade ensures content scrolling behind the bar stays visible without a hard cutoff.
## Header treatment
- Title (left): `new login` or `edit login`, body font, weight 500, size 18px.
- Subtitle (left, below title): one of:
- `unsaved · esc to cancel` when dirty
- `no changes` when pristine
- color: `var(--text-muted)`, size 12px.
- Hint (right): `⌘+S to save` (visual only, not a button), `var(--text-dim)`, size 12px. On non-mac, render `Ctrl+S`.
- Popout-to-tab `⤴` button: removed from fullscreen header (already done in Phase 1 visual baseline).
The dirty/pristine state is tracked by existing form state. Phase 2B adds a small subscriber that updates the subtitle text on each input change. No new state machine — just a derived boolean.
## Other item types
Single-column layout stays for `secure_note`, `identity`, `card`, `key`, `totp`, `document`. These types still get the new sticky save bar and header treatment. Only the column grid is login-specific.
## Files touched
| File | Change |
|------|--------|
| `extension/src/vault/vault.css` | Add `.form-grid`, `.form-section-header`, `.sticky-save-bar`, `.form-header` styles + 720px media query |
| `extension/src/popup/components/types/login.ts` | Wrap fields into Identity / Credentials column wrappers when rendered into the fullscreen surface |
| `extension/src/vault/vault.ts` | Wire dirty-state subscriber to header subtitle; render header treatment + sticky bar |
| `extension/src/vault/__tests__/` | Tests for two-column rendering, dirty subtitle transitions, sticky bar visibility |
The login renderer needs to know which surface it's rendering into (popup vs fullscreen). The simplest approach: add an optional `surface: 'popup' | 'fullscreen'` parameter to `renderForm()`. Default to `popup` to preserve existing behavior.
## Testing
Per-area tests using existing `vitest` + `happy-dom` setup:
1. **Layout test:** mount login form with `surface: 'fullscreen'`, assert grid layout is applied and Identity/Credentials columns contain the expected fields.
2. **Stack-down test:** simulate viewport ≤720px, assert single-column layout.
3. **Dirty subtitle test:** mount form, simulate input, assert subtitle changes from `no changes``unsaved · esc to cancel`. Assert reversion on reset.
4. **Sticky bar test:** assert save bar exists, has correct position style, and save button respects validity.
5. **Other-type non-regression:** mount `secure_note`, assert single-column layout (no grid).
No e2e infrastructure changes — manual QA with the rebuilt extension loaded in Chrome.
## CLI parity
This phase is purely visual / layout-shaped. No CLI counterpart. The CLI already accepts all login fields as flags (`--title`, `--username`, `--password`, etc.), which is its own form surface.
## Out of scope / deferred
- Two-column layout for non-login types (could come in a future phase; current single-column works fine for forms with fewer fields).
- Custom column-width adjustment by the user (drag divider). Fixed 1fr 1fr for now.
- Animated transitions on subtitle text change (just snap).
- Keyboard shortcut to actually save with ⌘+S — that arrives with Phase 3 keymap. The hint is purely a visual label until then.
- Diff view ("you changed 3 fields") — future enhancement.