8.9 KiB
Sidebar Aesthetics Plan
Apply the design rules from ~/lt/aesthetics/WEB.md to the Nostr sidebar webview in src/ui/sidebar.ts.
Context
WEB.md defines a minimalist web aesthetic:
- Monochrome first: black, white, one red accent, plus one muted grey. No other hues.
- Monospaced by default: one fixed-width family for body, buttons, inputs, labels.
- Minimal CSS surface: few variables, few classes, reuse shell styles.
- Readable over clever: 1px borders, single radius token, no gradients/shadows as decoration.
- Grayscale media: images desaturated at rest, color returns on hover.
- Dark mode = swapped variables, not swapped styles.
- Spacing ladder: 5, 10, 15, 20, 40 px only.
- Transitions: 0.2s for interactive feedback; 0.5s max for slide-outs.
- Accessibility: tab-reachable, accent focus ring, alt text, reduced-motion respected.
The current sidebar is a VS Code webview that leans on --vscode-* theme variables with a generic VS Code look: mixed monospace/sans, blue-ish buttons, 2px radii, ad-hoc spacing (6px, 8px, 12px, 16px), no grayscale on avatars, no transitions.
Reconciliation: WEB.md tokens vs VS Code theme
The sidebar lives inside VS Code, so it must respect the user's light/dark theme. We map the WEB.md four-token palette onto VS Code theme variables so the monochrome+accent system still tracks the active theme:
| WEB.md token | Sidebar value |
|---|---|
--primary-color |
var(--vscode-foreground) |
--secondary-color |
var(--vscode-sideBar-background) |
--accent-color |
var(--vscode-statusBarItem-errorBackground, #ff0000) — red, used only for hover/active/focus/destructive |
--muted-color |
var(--vscode-descriptionForeground) |
--border-color |
var(--vscode-panel-border, var(--muted-color)) |
This keeps the "monochrome + one red scalpel" intent while remaining theme-aware. The accent resolves to red in most themes; where a theme overrides the error background we still get a single semantic accent.
Changes
All changes are confined to the inline <style> and HTML structure inside NostrSidebarProvider.getHtml(). No host-side TypeScript logic changes are required.
1. Variable block (:root)
Replace the current ad-hoc :root with the reconciled token set plus the WEB.md minimums:
--font-family: var(--vscode-editor-font-family), "Courier", monospace;(monospace everywhere)--primary-color,--secondary-color,--accent-color,--muted-color,--border-coloras in the table above.--border-radius: 5px;(single token, replaces the current 2px)--border-width: 1px;and--border: var(--border-width) solid var(--border-color);--avatar-size-md: 32px;(identity avatar)--image-grayscale: 100%;and--image-grayscale-hover: 20%;- Spacing ladder documented as a comment:
5, 10, 15, 20, 40.
2. Typography
* { font-family: var(--font-family); box-sizing: border-box; }- Body uses
var(--font-family)andvar(--vscode-font-size). - Section headings (
h2) keep11px,font-weight: 600, uppercase,letter-spacing: 0.5px, colorvar(--muted-color)— already close to WEB.md's "UI chrome 14px / compact 12px" guidance; we keep 11px for the uppercase label style. - Relay URLs and npub already use the editor font; ensure all inputs/buttons/selects also inherit
var(--font-family).
3. Buttons
Adopt the WEB.md .btn model adapted to the sidebar's full-width buttons:
- Default:
color: var(--primary-color); background: var(--secondary-color); border: 1px solid var(--primary-color); border-radius: var(--border-radius); padding: 8px 10px; font-weight: bold; cursor: pointer; transition: border-color 0.2s, background-color 0.2s, color 0.2s; :hover→border-color: var(--accent-color);(never fill red on hover).:active→background: var(--accent-color); color: var(--secondary-color); border-color: var(--accent-color);:disabled→opacity: 0.5; cursor: not-allowed;(no recolor)..secondary→ swap to muted border:border-color: var(--muted-color); color: var(--muted-color);hover still goes to accent border.- Remove the old
--btn-bg/--btn2-bgblue button styling.
4. Inputs / select
- Share border, radius, padding with buttons so they line up.
border: var(--border); border-radius: var(--border-radius); padding: 8px 10px; background: var(--vscode-inputBackground); color: var(--vscode-inputForeground);:focus→outline: none; border-color: var(--accent-color);(accent focus ring, per WEB.md §7 and §14).- Labels (
.field-label) stay muted grey, above inputs, smaller than input text.
5. Avatar / images
- Global
img { filter: grayscale(var(--image-grayscale)); transition: filter 0.2s; }andimg:hover { filter: grayscale(var(--image-grayscale-hover)); }. .avatarand.avatar-placeholderuse--avatar-size-md: 32px,border-radius: var(--border-radius)by default (square-with-radius per WEB.md §8; round variant only if we later opt in via999px).- Avatar
alttext set to the profile name or"avatar"(currentlyalt="avatar"— keep, but prefer name when available).
6. Spacing normalization
Migrate current values onto the ladder:
| Current | New |
|---|---|
margin-bottom: 16px (section) |
20px |
margin: 0 0 8px 0 (h2) |
0 0 10px 0 |
padding: 6px 10px (button) |
8px 10px |
margin-bottom: 6px (button) |
10px |
padding: 4px 6px (input) |
8px 10px |
margin: 4px 0 2px (label) |
5px 0 |
padding: 12px (body) |
10px (or 15px) |
gap: 6px (relay row) |
10px |
gap: 8px (identity row) |
10px |
7. Relay list and identity block
- Relay rows: keep flex row,
gap: 10px,padding: 5px 0, monospace URL withtext-overflow: ellipsis; white-space: nowrap;(already present). - Identity block: treat as a single card —
border: var(--border); border-radius: var(--border-radius); padding: 10px; margin-bottom: 15px;containing the avatar row, name, npub, backend label, and Sign Out button. This matches WEB.md §9 card conventions (1px border, 5–10px radius, 12px-ish padding, vertical flex). - Empty-state text stays italic muted grey (WEB.md allows italic for empty-state).
8. Transitions and reduced motion
- Add
transition: border-color 0.2s, background-color 0.2s, color 0.2s, filter 0.2s;to buttons, inputs, checkboxes, and images. - Add
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }.
9. Accessibility pass
- Ensure every button/input/select has visible focus: accent border on inputs; for buttons add
:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 1px; }. - Relay checkboxes remain native (WEB.md §7: don't reinvent).
- Confirm tab order: Actions → Relays → Fetch button → Identity fields → Sign In/Out.
- Avatar
alttext uses profile name when available, else"avatar".
10. CSP
No CSP change needed. style-src 'unsafe-inline' already permits the inline styles; img-src https: data: already permits avatar loading. We are not adding any external resources.
Out of scope
- No changes to host-side message handling, state shape, or commands.
- No new files; everything stays in
sidebar.ts. - No layout shell refactor (the sidebar is a single pane, not the five-region web shell from WEB.md §4 — that section informs token choices, not structure).
- No dark-mode class toggle: VS Code drives light/dark via theme variables, which our token mapping already honors.
Verification
- Build the extension (
npm run buildviaesbuild.mjs) and load it in VS Code. - Open the Nostr sidebar and confirm:
- All text is monospaced.
- Buttons are outlined monochrome; hover shows red border; click flashes red fill.
- Inputs show red border on focus.
- Avatar (when signed in with a profile picture) is grayscale until hover.
- Spacing feels even (no 6/8/12/16 oddities).
- Disabled buttons are dimmed, not recolored.
- Toggle a light and a dark VS Code theme; confirm the palette tracks correctly and the accent stays red.
- Tab through the sidebar; confirm visible focus rings and logical order.
- Enable OS reduced-motion; confirm no transitions animate.
Mermaid overview
flowchart LR
A[WEB.md rules] --> B[Token mapping]
B --> C[Typography: monospace]
B --> D[Buttons: outline + red hover/active]
B --> E[Inputs: accent focus]
B --> F[Avatar: grayscale + hover reveal]
B --> G[Spacing ladder 5/10/15/20/40]
B --> H[Transitions 0.2s + reduced-motion]
C --> I[sidebar.ts inline style + HTML]
D --> I
E --> I
F --> I
G --> I
H --> I
I --> J[Build + manual verify in VS Code]