Files
relicario/docs/superpowers/specs/2026-04-24-relicario-gen-ux-redesign-design.md
adlee-was-taken 9add305a10 docs(spec): generator UX redesign — inline panel + trigger
Replaces the right-anchored popover (which clips off the popup edge)
with an inline panel that injects into the form below the password row.
Trigger becomes a  icon button (gold-bg). "save default" demoted to
secondary link; single gold "use" CTA. Bundles label-casing polish
(drop CAPS LOCK, gold required marker) since .label is shared.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:06:56 -04:00

13 KiB
Raw Blame History

Generator UX redesign + adjacent popup polish — design

Date: 2026-04-24 Scope: Replace the right-anchored popover that opens from the password generator trigger with an inline panel that lives inside the form. Swap the "gen" text button for a icon button. Tighten the label/affordance treatment in the touched screens (login form + vault settings) along the way. Backgrounds, palette, and other unrelated UI stay untouched.

Goal

The current popover (β₂, commit 8a16482) positions itself by anchoring its left edge to the trigger button's left edge, but the trigger sits on the right side of the password input row. Combined with the popover's min-width: 300px inside a 360 px Chrome popup, the popover always overflows the popup boundary by ~180220 px. In manual testing it appears as a clipped card with cut-off labels and inaccessible buttons.

A surgical clamp-fix (~10 lines) would patch the symptom but leave the underlying UX awkward — even when fully visible, the popover floats over the form, hides what you were filling out, and crams two primary actions ("save default" + "use this value") next to each other. The user's feedback was explicit: "we may gotta plan some ui overhauls here, like an emoji instead of 'gen' and a cleaner UI approach for sure." This redesign replaces the popover pattern entirely instead of patching it.

Visual identity

Trigger button

  • Icon: (U+2728 sparkles emoji). Reads as "auto-generate / freshly minted." Visually rhymes with the sparkle dot on the new logo's gem (commit a3f13fd).
  • Color: deep gold #7c5719 background, #fff3cf text — matches primary-button styling from the palette refresh.
  • Hover state: background #aa812a (mid gold).
  • Active state (panel open): background #aa812a (visually distinct from idle so the user can tell at a glance whether the panel is open).
  • Layout: stays in the existing .inline-row pattern next to the password input; replaces the current <button class="btn" id="gen-btn">gen</button> with <button class="gen-trigger" id="gen-btn" aria-expanded="false">✨</button>.
  • Tooltip: title="generate password" for hover.
  • Width: ~38 px (single emoji glyph fits without padding noise).

Inline panel (replaces popover)

When is clicked, a panel injects into the form's DOM between the password row and the next form-group (e.g., the totp-secret row). Other fields below shift down. The panel:

  • Lives at the form's full available width (no positioning math, no clipping).
  • Has a subtle gold border (1px solid #aa812a) to feel attached to the trigger.
  • Auto-generates a preview the moment it opens, using VaultSettings.generator_defaults as the initial knob state.

Panel composition (top to bottom):

  1. Kind toggle — pill-style two-button switch: random / passphrase. Active button: gold-bg.
  2. Common knobs (always visible):
    • For random: length slider (848, default 20), four character-class checkboxes (a-z / A-Z / 0-9 / !@#).
    • For passphrase (BIP39): word_count slider (310, default 4), separator text input (1 char), capitalization radio (lower / upper / title).
  3. Preview row — generated value in monospace gold (#f1cf6e), with a regenerate button.
  4. more ▾ disclosure — when expanded, shows the rarely-used knobs:
    • For random: symbol charset (safe / full toggle).
    • For passphrase: nothing extra (separator and capitalization moved to common).
    • For both: an empty placeholder when no advanced knobs apply (so the disclosure always renders for consistency, even if collapsed-only).
  5. Action row:
    • ↑ save these as default — small underlined link, left-aligned, #8b949e color → #d2ab43 on hover. Writes current knobs to VaultSettings.generator_defaults via the existing update_vault_settings message; shows a brief "saved" toast next to the link; panel stays open. Demoted from primary button because most of the time the user just wants this password, not to change global defaults.
    • cancel — secondary button (transparent bg, gray border).
    • use — primary CTA: gold bg #7c5719, #fff3cf text. Commits the current preview value into the password input and closes the panel.

Adjacent polish (scope B)

Touched only in screens we're already modifying (login form + vault settings):

  • Form labels: .label class drops text-transform: uppercase and reduces letter-spacing from 0.5px to 0.02em. Lowercase labels match the panel's knob labels and feel less shouty. Font weight goes 600 → 500 for slightly less visual weight; color stays #8b949e.
  • Required marker: the existing * next to required-field labels picks up gold (#aa812a) instead of inheriting label gray, so it actually reads as a marker.
  • Button styles: primary form buttons (cancel/save at the bottom of the login form) already use the palette refresh; nothing to change there.

These polish changes apply to ALL form labels in the login form and vault settings (not just the password row), since the .label class is shared. Other forms that use .label (SecureNote, Identity, Card, Key, Totp, Document-coming-soon) will pick up the lowercase treatment automatically — that's a deliberate choice, not a side effect: the CAPS LOCK feel was a project-wide rough edge that's worth fixing in this slice.

Behavior

Trigger Action
click toggle panel open/closed; auto-generate on first open using saved defaults
click ↻ regenerate preview (no commit)
change a knob debounced auto-regenerate (150 ms — same as existing)
click use commit current preview into password field, close panel
click cancel close panel without committing; password field unchanged
click ↑ save these as default write current knobs to VaultSettings.generator_defaults; show toast; panel stays open
press Escape (when panel open) close panel without committing
click again while panel open close panel (no commit)

The panel does NOT close on click-outside. The user might want to drag from the panel to verify the value or copy it before clicking use; closing on click-outside makes that fragile. Escape and explicit cancel/use are the dismissal paths.

Vault settings adaptation

The vault settings screen currently has a <button id="configure-gen">configure ▾</button> next to a generator-summary text line. After redesign:

  • The "configure ▾" button becomes a button matching the login form trigger.
  • When clicked, the same inline panel renders inside the vault-settings "generator" section (not as a popover).
  • One difference from the login-form context: the action row drops the cancel and use buttons since there's no password input to fill — instead, the panel is purely for inspecting/configuring defaults. The ↑ save these as default link becomes the only action in this context, and closes the panel just like in the login form.
  • The generator preview text line (generatorSummary(...)) stays above the panel even when expanded — it serves as a "current default" reference.

Files affected

Modified

  • extension/src/popup/components/generator-popover.ts — major rewrite. Probably gets renamed to generator-panel.ts (cleaner semantics). Same module, different positioning (inline DOM injection vs absolute-positioned popover) and different action set per context.
  • extension/src/popup/components/types/login.ts — replace gen-btn text content with ; update click handler to call the renamed module; drop the standalone close-on-blur logic if any.
  • extension/src/popup/components/settings-vault.ts — replace configure-gen button content with ; update click handler; render the inline panel in place rather than calling the popover open.
  • extension/src/popup/styles.css — add .gen-trigger rule (button styling); add .gen-panel and child rules (replacing .generator-popover rules). Modify .label rule to drop uppercase and tighten letter-spacing/weight; modify .label .req (or equivalent for the *) to gold. Remove the .generator-popover rules entirely once the new panel works (no need to keep old popover CSS around).

Renamed

  • extension/src/popup/components/generator-popover.tsextension/src/popup/components/generator-panel.ts. Test file follows: __tests__/generator-popover.test.ts__tests__/generator-panel.test.ts. Update imports in login.ts, settings-vault.ts, and the test file accordingly. Sequencing decision (git-mv first vs rewrite first) noted in open questions.

Updated tests

  • extension/src/popup/components/__tests__/generator-popover.test.ts (renamed): existing 7 tests cover knob → message-shape behavior. Most should survive verbatim — they're DOM-level, not positioning-level. Update test setup to mount the panel inline (in a parent container) rather than asserting on document.body children. Add 23 new tests:
    • Panel opens via aria-expanded toggling on the trigger
    • Panel auto-generates on first open
    • Escape key closes the panel

Markup unchanged but new selectors

  • The .inline-row pattern in login form stays. Just the button content/styling changes.

Acceptance

  • Clicking on the login form opens an inline panel below the password row.
  • Panel auto-generates a preview using current VaultSettings.generator_defaults.
  • Knob changes debounce-regenerate; ↻ button forces a regenerate.
  • use button commits preview into password input and closes panel.
  • cancel button closes panel without committing.
  • Escape key closes panel without committing.
  • Clicking again while panel open closes it.
  • ↑ save these as default link writes to VaultSettings.generator_defaults; toast appears; panel stays open.
  • Vault settings button opens the same panel inline (no popover); ↑ save these as default is the only action; toggles closed.
  • All form labels in login + vault settings are lowercase with reduced letter-spacing.
  • Required-field * marker is gold (#aa812a).
  • No element overflows the popup right edge in any state.
  • bun run test passes (existing 7 generator tests survive the rename + 2-3 new tests added → ~910 generator-panel tests; total still around 124127).
  • bunx tsc --noEmit clean.
  • bun run build:all clean (Chrome + Firefox).
  • No new automated tests for the visual polish (label casing, gold *) — visually verified.
  • Manual: walk through both contexts (login form + vault settings) on Chrome and Firefox.

Out of scope

  • The capture-prompt and ack-prompt content scripts (still use their own button styling — no change here).
  • The setup tab's strength-bar / advice-block (touched in logo-refresh palette swap; nothing more to do).
  • Other popup forms beyond their .label class picking up the lowercase treatment automatically (no per-type form rework).
  • Generator output strength visualization (zxcvbn meter inside the panel) — could be a future polish but not now.
  • Multi-preview / "show 3 candidates" pattern — keeping the single-preview + regenerate flow.
  • Animation/transitions on panel open-close — purely instant for now (a fade or slide-down can be added later as polish without breaking anything).
  • Click-outside-to-close — explicitly NOT included (see Behavior section reasoning).

Open questions deferred to plan

  • Module rename ordering: is it cleaner to (a) rewrite in-place keeping the generator-popover.ts filename then rename in a follow-up, or (b) git-mv first then rewrite? Plan ships (b) — git-mv preserves history, reviewers see "rename + edits" cleanly.
  • Test mounting strategy: existing tests document.body.appendChild(host) then assert. New panel mounts inside a parent. Plan: tests create a parent div, pass it as the mount target to a new openGeneratorPanel(opts) signature that takes { parent, anchor, initial, onPicked, onCancel }. The login-form caller passes the form element as parent.
  • The "more ▾" placeholder: for passphrase mode, all knobs are common and there's nothing in advanced. Plan: render the disclosure with text "(no advanced options for passphrase)" when expanded, OR hide the disclosure entirely in passphrase mode. Plan ships the hide-when-empty option — less visual noise.
  • save default toast: existing toast infrastructure in popup? If yes, reuse. If not, the smallest toast = a 1.5s fade-in/fade-out span next to the ↑ save these as default link saying "✓ saved". Plan picks based on what already exists.
  • Vault-settings panel — when no defaults exist: the very first time a vault is created, VaultSettings.generator_defaults should already be initialized (it is, per β₂). Confirm and document.