Redesign popup UI, rename thresholds panel to Settings, surface errors on main screen

UX changes:
- Settings load/save errors now surface as a dismissible banner on the
  main popup screen, not only inside the collapsed panel. Settings are
  fetched eagerly (like lock state/connection status already were)
  instead of lazily on first expand, so a load failure is visible
  immediately.
- The "Adjust loss thresholds" toggle/panel is renamed to "Settings"
  (with "Loss thresholds" as a subsection heading, since that's the
  only setting today), and gains a "Done" affordance to collapse it
  back rather than only being expandable.
- Lock status is now the visual hero (a bordered status card with an
  icon), rather than one item in a flat list alongside connection
  status and account actions.

Visual changes:
- style.css rewritten around CSS custom-property design tokens
  (spacing/radius/font-size scale, semantic colors) with explicit
  light and dark palettes, instead of hardcoded hex colors reused
  as-is across both color schemes.
- Popup widened 280px -> 320px for breathing room; card-based grouping
  (status, settings) replaces the previous flat stack of sections.

No wire-protocol or messaging-contract changes.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
This commit is contained in:
2026-09-08 13:20:05 +02:00
co-authored by claude
parent 5cfb0f0b53
commit 9a774a38d4
3 changed files with 359 additions and 139 deletions
+2 -2
View File
@@ -62,7 +62,7 @@ Planned structure:
intervention-interface.ts
observer.ts - generic MutationObserver watching for adapter-declared selectors (SPA-safe)
content-index.ts - wires adapter + intervention + background messages together
/popup - status, reason for lock, threshold settings link
/popup - status, reason for lock, Settings panel (loss thresholds)
/notifications - toast/banner injected into page or via browser notification API
/shared
messaging.ts - typed message contracts between background <-> content scripts <-> popup
@@ -93,7 +93,7 @@ Note the naming mismatch with the wire protocol below: the frontend's internal `
- `src/background/wallet-auth.ts` — `handleWalletConnected()` runs the REST auth flow (`POST /auth/nonce` → Phantom signature → `POST /auth/verify` → session token) once a content script reports a connected wallet. Also `requestWalletReconnect()` (silent reconnect after the backend invalidates a session), `requestWalletDisconnect()` (sign-out), `requestAccountSwitch()` (explicit account switch) — all three just message whichever tabs are on a supported site; `wallet-connect.ts` in the content script does the actual work.
- `src/background/ws-client.ts` — the WS client described above: connects to `/ws?token=...`. `connectWsClient()` returns a controller with `reconnectNow()` so the background script can short-circuit the backoff wait right after a fresh token arrives. Auth failures (`4001` close, `auth_expired`/`session_revoked` errors) do **not** auto-retry with backoff — they call `onAuthExpired()` instead, since retrying with a known-bad token can't succeed; only real disconnects (network drop, backgrounded browser) use the protocol's suggested backoff schedule.
- `src/background/connection-status.ts` — separate from lock state; the popup surfaces this (connecting/connected/disconnected/auth-error) alongside the lock state so a broken connection isn't silently indistinguishable from "unlocked".
- `src/background/settings-client.ts` — `GET`/`PATCH /me/settings` (per-user loss-detection thresholds; see backend/CLAUDE.md, "Account settings"), same direct-fetch-with-bearer-token shape as `wallet-auth.ts`. Popup -> background dispatch is `osias:get-settings`/`osias:update-settings` in `background.ts`, responses shaped `{ settings } | { error }` (`SettingsResult` in `shared/messaging.ts`). The popup's "Loss thresholds" panel (`entrypoints/popup/App.tsx`) is the only place percent fields (`near_full_exit_fraction` and both loss thresholds) get converted between the backend's fractional wire representation and the whole-number percentages shown in the form — same "convert only at the seam" rule as `LockScope`'s kebab/snake split below.
- `src/background/settings-client.ts` — `GET`/`PATCH /me/settings` (per-user loss-detection thresholds; see backend/CLAUDE.md, "Account settings"), same direct-fetch-with-bearer-token shape as `wallet-auth.ts`. Popup -> background dispatch is `osias:get-settings`/`osias:update-settings` in `background.ts`, responses shaped `{ settings } | { error }` (`SettingsResult` in `shared/messaging.ts`). Settings are fetched eagerly in `App`'s mount effect (same pattern as lock state/connection status) rather than lazily on first expand, so a load/save error surfaces immediately as a dismissible banner on the popup's main screen instead of being invisible until the user opens the collapsed "Settings" panel (`entrypoints/popup/App.tsx`'s `SettingsPanel`, a purely presentational form fed by `App`'s state). That panel is the only place percent fields (`near_full_exit_fraction` and both loss thresholds) get converted between the backend's fractional wire representation and the whole-number percentages shown in the form — same "convert only at the seam" rule as `LockScope`'s kebab/snake split below.
### Wallet auth (Phantom) — implemented