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:
134
docs/superpowers/specs/2026-05-02-phase-2b-form-layout-design.md
Normal file
134
docs/superpowers/specs/2026-05-02-phase-2b-form-layout-design.md
Normal 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.
|
||||
Reference in New Issue
Block a user