Commit Graph

113 Commits

Author SHA1 Message Date
adlee-was-taken
117716f6cf fix(ext/popup): replace emoji typeIcon with glyph constants in item-list 2026-05-03 21:37:23 -04:00
adlee-was-taken
c5e8b52e12 fix(ext/popup): replace inline ⤴ vault-tab button with GLYPH_VAULT_TAB 2026-05-03 21:37:23 -04:00
adlee-was-taken
33d2a4a311 feat(ext/setup): wizard Style C progress track, glyph mode icons, recovery QR banner
- Replace dot-based progress indicator with colored horizontal segment track
  (completed=green, active=gold, pending=border) via renderProgressTrack()
- Add SETUP_STEP_NAMES constant for track segment titles
- Update Step 0 mode cards with glyph icons (◈ create, ⌥ attach)
- Add recovery QR banner in Step 5 (new-vault only, verifiedHandle present)
  with Generate now / Skip buttons wired in attachStep5()
- Add CSS for .setup-progress-track, .setup-progress-segment variants,
  and .recovery-qr-banner to styles.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 21:17:05 -04:00
adlee-was-taken
4851857070 feat(ext/settings): settings-security.ts three-state recovery QR + devices component
- Add settings-security.ts with renderSecuritySection / teardownSecuritySection
- Three states: amber warning (no QR), green status (QR set up), modal overlay (show/print SVG)
- Device list with inline revoke; passphrase collected via prompt()
- QR payload never written to chrome.storage; only recovery_qr_generated_at timestamp stored
- Add generate_recovery_qr / unwrap_recovery_qr message types to messages.ts + POPUP_ONLY_TYPES
- Add SW handlers in popup-only.ts delegating to wasm_generate_recovery_qr / wasm_unwrap_recovery_qr
- Declare wasm_generate_recovery_qr and wasm_unwrap_recovery_qr in wasm.d.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 21:06:43 -04:00
adlee-was-taken
631e9af470 fix(ext/login): constrain lower form sections to .form-grid envelope (P3)
Notes, custom-fields disclosure, attachments disclosure, and form-actions
in fullscreen logins now sit inside a .form-lower wrapper with the same
max-width: 960px; margin: 0 auto envelope as .form-grid above. Removes
the visual rhythm break at the 2-col -> full-width transition.

Popup keeps its current single-column behavior (gated on surface flag).
2026-05-02 19:07:33 -04:00
adlee-was-taken
b2fc56709a feat(ext/settings): Display section with color pickers + swatch + reset
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:03:23 -04:00
adlee-was-taken
b928ed407b feat(ext): apply color scheme on popup + vault startup
Import applyColorScheme in popup.ts and vault.ts, await it at boot,
and register a chrome.storage.onChanged listener so live color-picker
changes take effect without a reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 18:55:28 -04:00
adlee-was-taken
6bca0b3526 feat(ext/popup/item-detail): colorize revealed password field
Add data-field-kind attribute to renderConcealedRow so wireFieldHandlers
can distinguish password fields from other concealed rows (TOTP secrets,
CVV, PIN, private keys). Apply colorizePassword() on reveal when kind is
"password"; plain textContent otherwise. Pass kind through renderSections
for custom-section password fields.
2026-05-02 18:49:56 -04:00
adlee-was-taken
f45c275566 feat(ext/generator): colorize live password preview 2026-05-02 18:49:56 -04:00
adlee-was-taken
3e4312ca6f feat(ext/popup/field-history): colorize revealed password entries
Import colorizePassword and post-process .revealed value cells after
innerHTML render, replacing escaped-HTML text with colored spans via
the valueStore plaintext lookup.
2026-05-02 18:47:12 -04:00
adlee-was-taken
518b41e9cd style(ext): add password-coloring CSS rules + custom property defaults 2026-05-02 17:19:06 -04:00
adlee-was-taken
2df636e454 fix(ext/login): dispatch input event after regenerate sets password (B1)
Programmatic input.value = newPassword does not fire input events, so
the strength-meter listener at shared/form-affordances/password-tools.ts:65
never re-rates the new value — meter stays stuck on the prior reading.

Extract applyGeneratedPassword(input, value) helper that sets value, type,
then dispatches new InputEvent('input', { bubbles: true }). Vitest covers
the dispatch + a sanity check that bubbling listeners fire.
2026-05-02 16:46:06 -04:00
adlee-was-taken
648dcf386e feat(ext/shared): centralize error-message copy in ERROR_COPY map
Replaces the popup's regex-chain humanizeError with a total lookup over
every error code returned by extension/src/service-worker/router/. A
generated test discovers codes via grep so the registry can't drift.
The popup keeps its small set of regex translators for Rust/serde error
phrasing that doesn't go through the router's error vocabulary.

Subsumes B2 — fullscreen consumer lands in the next commit.
2026-05-02 16:26:01 -04:00
adlee-was-taken
b270dfedb4 feat(ext/vault): sticky save bar in fullscreen forms
The form pane gets a flex column layout: scrollable content above,
sticky save bar at bottom. Bar uses translucent fill with backdrop-blur
and a 24px gradient fade so content scrolls under it. Save / cancel
buttons reuse the form's existing handlers via externalActions flag.
2026-05-02 15:05:09 -04:00
adlee-was-taken
a28b456191 feat(ext/login): add surface flag for two-column fullscreen form
renderForm() takes an optional { surface: 'popup' | 'fullscreen' }
parameter. When 'fullscreen', the Identity and Credentials field
groups render as glass cards inside a .form-grid (two columns,
stacks at <=720px). Popup keeps its single-column layout.
2026-05-02 15:01:35 -04:00
adlee-was-taken
7371eff0bb feat(ext/popup): polish unlock view with logo lockup + glass card
Restructures the unlock screen so the form sits in a glass card with
a primary 'unlock vault' button. Logo, brand, and tagline are grouped
as a lockup. Open-vault and settings are demoted to secondary buttons.
Body gets the .surface-backdrop wrapper.
2026-05-02 14:21:04 -04:00
adlee-was-taken
308ef2c974 feat(ext): add GLYPH_NEXT and replace ASCII arrows with ▸
Replaces the ASCII rightwards arrow → with U+25B8 ▸ in settings-vault
buttons. Matches the existing ▾/▸ disclosure-glyph family.
2026-05-02 14:17:55 -04:00
adlee-was-taken
60d7c074c3 style(ext): add .btn-primary and .btn-secondary classes
Two-tier button hierarchy. .btn-primary uses patina gold fill; .btn-secondary
is a ghost button with muted border. Existing .btn class kept for
backwards compatibility.
2026-05-02 13:33:18 -04:00
adlee-was-taken
91536ee50d style(ext): add .glass card class
Translucent fill, soft border, inner highlight, drop shadow. Used for
the unlock card, setup step cards, and form section panels.
2026-05-02 13:32:55 -04:00
adlee-was-taken
da61529de6 style(ext): add .surface-backdrop class
Subtle radial top-glow + 18px grid texture. Used as the backdrop for
the login popup, setup wizard, and fullscreen vault shell.
2026-05-02 13:32:39 -04:00
adlee-was-taken
479e5848f5 style(ext/popup): add patina palette tokens
Replaces bright amber #d2ab43 with patina gold #a88a4a as the new base.
Keeps --accent as alias for backwards compatibility. Adds --bg-card
and --border-soft for upcoming glass card class.
2026-05-02 13:29:22 -04:00
adlee-was-taken
c67d484152 feat(extension): update devices UI for new auth model
- Show revoked devices in collapsible section with strikethrough styling
- Fetch revoked.json via new list_revoked message + router case
- Registration flow uses register_device WASM API (private keys internal)
- Display revoked_by and timestamp for each revoked entry
- Update setup wizard to use new register_device API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:29:31 -04:00
adlee-was-taken
315967f4a1 Merge feature/fullscreen-ux-phase-2a: smart-input affordances
Phase 2A of the fullscreen UX redesign — 8 form-level smart-input
affordances (URL fill-from-tab + hostname chip, group autocomplete,
password reveal + strength bar, TOTP live preview + QR decode, notes
monospace toggle), shared between popup and fullscreen vault tabs via
the new extension/src/shared/form-affordances/ module set.

CLI parity:
- relicario rate <passphrase> (zxcvbn score / guess estimate)
- relicario completions <SHELL> (bash/zsh/fish via clap_complete)
- --group <TAB> dynamic enumeration via .relicario/groups.cache
  (plaintext leak surface; opt out with RELICARIO_NO_GROUPS_CACHE=1)
- --totp-qr <path> on add login + edit (rqrr decode)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 22:37:18 -04:00
adlee-was-taken
b450ecd1cc ext(login): wire 8 smart-input affordances into renderForm()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:32:14 -04:00
adlee-was-taken
e6eb698c4c ext(affordances): wireNotesMonoToggle with chrome.storage.local persistence 2026-05-01 22:23:56 -04:00
adlee-was-taken
bd8102c9ad ext(affordances): wireTotpQr (jsqr lazy-load) for QR -> otpauth:// fill
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:14:05 -04:00
adlee-was-taken
c91b31a7ca ext(affordances): wireTotpPreview live ticker 2026-05-01 19:56:55 -04:00
adlee-was-taken
7bd1a9dd7d ext(affordances): wirePasswordStrength via scheduleRate
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 19:50:18 -04:00
adlee-was-taken
61dbb4d3a3 ext(affordances): wireHostnameChip with debounced URL parse 2026-05-01 18:06:15 -04:00
adlee-was-taken
39ae2ecbf3 style: capitalize "Relicario" in prose / UI / CLI help
Brand name uses capital R in user-facing text — extension UI strings,
CLI clap help / descriptions / error prose, markdown docs. Lowercase
preserved for the binary command, crate names, npm package, file
paths, env vars, and code identifiers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:29:10 -04:00
adlee-was-taken
4be0bcff83 ext(affordances): wireFillFromTab + .glyph-btn CSS 2026-05-01 17:07:01 -04:00
adlee-was-taken
ef7bd5b848 refactor(ext/popup): renderFormHeader takes options object
Whole-branch review recommendation: switch renderFormHeader's signature
from positional (titleText) to options ({ titleText }) so Phase 3 can
add 'dirty' (and any future hooks like a save-keybinding hint) without
touching all 7 call sites in lockstep with the unsaved-guard work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 14:33:29 -04:00
adlee-was-taken
1454cd8165 refactor(ext/popup): extract renderFormHeader + .form-header CSS
Code-review feedback on Task 8: the conditional empty
<div style="margin-bottom:16px;"> spacer was an inline-styled magic
number and the 6-line header pattern was duplicated across all 7 typed
forms.

Now:
- .form-header class owns the bottom margin in both stylesheets.
- :has(+ .form-subtitle) selector drops the margin when a subtitle
  follows, so spacing tokens stay in CSS instead of inline styles.
- renderFormHeader(titleText) shared helper collapses the 6-line
  duplication to a one-liner per form. item-form.ts (type-selection
  screen) is unaffected — it uses a different header structure.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 14:26:16 -04:00
adlee-was-taken
381e8ed496 feat(ext): static 'esc to cancel' subtitle in fullscreen form headers
All seven type forms plus the type-selection screen now show a small
'esc to cancel' subtitle under the heading when rendered in the
fullscreen vault tab (isInTab() === true). The subtitle is suppressed
in the popup, where esc has the more general meaning of closing the
popup. .form-subtitle class is shared between popup and vault
stylesheets so future hooks can reuse it.

Dynamic dirty-state ('unsaved · esc to cancel') wiring is deferred to
Phase 3 (unsaved-changes guard).

Plan 2026-04-30 fullscreen UX phase 1 task 8.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 14:17:59 -04:00
adlee-was-taken
38ba31768a refactor(ext/test): extract TYPED_FORMS shared list for it.each tests
Code-review feedback on Task 7: the same Array<[name, renderForm]> of
all 7 typed forms appeared in three test files (required-pill,
popout-button, popout-button-fullscreen). A new typed form would have
required updating all three.

Now defined once in __tests__/_typed-forms.ts. Future typed-form
additions get regression coverage automatically.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 14:14:21 -04:00
adlee-was-taken
71ad91592d feat(ext/popup): hide popout-to-tab button in fullscreen forms
The ⤴ popout button is meaningless when the form is already in
vault.html — gate it on !isInTab(). Affects all seven type forms plus
the type-selection screen. Regression tests cover both popup (button
present) and fullscreen (button absent) contexts via it.each across
all 7 forms.

Plan 2026-04-30 fullscreen UX phase 1 task 7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 21:01:47 -04:00
adlee-was-taken
05b1fae9f4 style(ext/popup): replace settings nav emoji with shared glyphs
▦ trash and ⌬ devices in the popup settings panel now match the
fullscreen sidebar's glyph language. Lowercased labels match the brand.

Plan 2026-04-30 fullscreen UX phase 1 task 6.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:57:00 -04:00
adlee-was-taken
a634b6c745 refactor(ext): broaden required-pill test + drop dead .label .req CSS
Code-review feedback on Task 4:
- Test expanded from login-only to it.each across all 7 type forms
  (14 assertions total). A future revert to <span class="req">*</span>
  in any form now fails CI.
- .label .req rule removed from popup/styles.css and vault/vault.css —
  zero consumers after the REQUIRED_PILL_HTML migration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:52:26 -04:00
adlee-was-taken
e2381ed2ec refactor(ext/popup): migrate required-field markers to REQUIRED_PILL_HTML
Replaces ten <span class="req">*</span> sites across all seven type
forms with the shared REQUIRED_PILL_HTML snippet ('required' badge).
Adds a regression test pinning the new HTML in the login form.

Plan 2026-04-30 fullscreen UX phase 1 task 4.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:46:07 -04:00
adlee-was-taken
e5875249bf style(ext/popup): add color tokens, focus ring, required-pill class
Establishes :root CSS custom properties (accent, surfaces, status, focus
ring) and applies the focus ring to inputs/buttons via :focus-visible.
Adds .req-pill class used by Task 4 to replace the bare-asterisk required
marker. Existing .label .req kept for backward compatibility during the
migration window.

Plan 2026-04-30 fullscreen UX phase 1 task 2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:36:26 -04:00
adlee-was-taken
66981588e7 feat(ext/vault): Import panel — LastPass CSV
New vault.html#import panel with a file picker, parse-preview
("N logins, M notes, K skipped — proceed?"), confirm/cancel
buttons, inline progress, and a post-import warnings list. The
popup's settings-vault view links to it via a new
"LastPass CSV →" button next to "Backup & restore →".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 18:43:35 -04:00
adlee-was-taken
419408bbad feat(ext): vault-tab Backup & Restore panel
Two cards — Export (passphrase + include-image checkbox → download)
and Restore (file picker + passphrase + new-remote form). Deep-linked
from settings-vault > 'Backup & restore →'.
2026-04-28 22:11:51 -04:00
adlee-was-taken
a7dbf35126 feat(ext): sync now button + device register from popup; vault tab parity
Closes three audit gaps in one pass:

1. Sync now button in the popup settings view (📤). Triggers the existing
   { type: 'sync' } SW message and surfaces success / failure inline. The
   SW message was already wired but had no UI entry point.

2. Device registration from the popup. The "Register this device" button
   on the devices view used to error out with a "not yet implemented"
   message; it now opens an inline name input (default = browser+OS), and
   on confirm sends a new register_this_device SW message that generates
   an ed25519 keypair via WASM, persists private_key + name to
   chrome.storage.local, and writes the public key to the remote
   devices.json. No setup-wizard detour.

3. Vault tab is now an authorized sender for popup-only SW messages. The
   router accepts vault.html alongside popup.html, so the fullscreen tab
   can drive the same flows. Test covers acceptance from the vault tab.

New SW message: register_this_device { name }. Added to PopupMessage and
POPUP_ONLY_TYPES, handled in router/popup-only.ts.

Tests: 5 new vitest cases (3 in settings.test.ts, 2 in devices.test.ts)
+ 1 router test for vault-tab acceptance. All 194 extension tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 21:13:05 -04:00
adlee-was-taken
f44aedfa76 feat(ext/setup): vault-presence probe + mode-mismatch banners on Step 2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:22:45 -04:00
adlee-was-taken
a182c1ac5a feat(ext/setup): Step 0 mode picker (new vs attach) + Step 1 back button
Replace the placeholder Step 0 with two clickable mode-card buttons (create
new vault / attach this device). Picking a card highlights it and enables
the next button; the back button on Step 1 returns to Step 0 without losing
state. Add .mode-card CSS using the existing dark palette (#30363d, #58a6ff).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:20:24 -04:00
adlee-was-taken
ce59223fc0 feat(ext): shared state host — decouple components from popup.ts
Introduce shared/state.ts as a service-locator so popup components
(item-detail, item-form, trash, devices, settings, etc.) work in both
the popup and vault tab bundles. Both entry points register themselves
as the host; components import from shared/state instead of popup.ts.
Vault.ts now delegates to the real popup components, removing ~300 lines
of placeholder renderers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 16:38:06 -04:00
adlee-was-taken
7e0950e364 feat(ext/popup): session expiry listener, open-vault links, Shift+F shortcut
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 15:46:32 -04:00
adlee-was-taken
9488670b1b fix(ext/popup): fix reversed search, remove auto-focus, Enter opens items
- Search no longer auto-focuses; use "/" to focus it
- Typing in search no longer re-renders the entire view, just the
  item list — fixes backwards text caused by cursor reset to pos 0
- Arrow keys also update list without full re-render
- Enter opens the selected item even when search is focused

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 02:10:23 -04:00
adlee-was-taken
446949c5ce fix(ext/popup): auto-popout for attachment types, keep login/note in popup
- Login and secure_note types stay in popup without attachment UI
- All other types (identity, card, key, totp, document) auto-redirect
  to full tab when selected
- Attachments only shown for login/secure_note when opened in tab

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:42:35 -04:00
adlee-was-taken
c59e6892d8 feat(ext/popup): add pop-out to tab for forms
Forms can now be opened in a full browser tab via the ⤴ button,
solving Chrome's popup closure on file picker interaction. Deep
linking via URL params preserves view, item type, and item ID.

Also removes the unused dropdown picker code from item-list.ts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:32:39 -04:00