SPB Git

Repository Public MIT Selected

DESIGN.md 9.8 KB

# SPB Git 3.0 — design system "Monograph"

SPB Git shares the visual language of www.spboucher.ai: an editorial monograph, not a dashboard. Warm paper, ink, one indigo accent, hairlines, square corners, generous white space. Colour carries meaning (links, active state, additions/deletions, languages) and is never decoration.

# 1. Direction (the fifteen lines)

  1. Paper and ink. The page is warm paper with a faint graph grid in the top corner; surfaces are a slightly lighter sheet.
  2. One accent, indigo (oklch(0.44 0.155 268) on paper). No gradients, no glow, no second brand colour.
  3. Three voices: Fraunces for names, titles and numerals; Inter for text; IBM Plex Mono for labels, metadata and code.
  4. Labels are small uppercase mono with wide tracking (10.5–11 px, 0.14–0.2 em). Sections open with a short rule and a numbered eyebrow ("01 SELECTED").
  5. Square corners everywhere; 2 px only softens small controls. Borders are 1 px hairlines; a 2 px ink rule opens a block of figures or a document.
  6. No shadows at rest. A card lifts 1 px on hover; only dialogs cast a shadow.
  7. Figures are set like a table of statistics: rule, "01", serif numeral, mono caption — never rounded stat tiles.
  8. Lists are typographic indexes and ledgers (hairlines, aligned columns, tabular numerals), not grids of identical cards.
  9. The primary action is ink on paper (black button, paper text), inverted in the dark themes. Secondary actions are outlined; tertiary are text.
  10. Code is quiet: house syntax themes "paper" and "ink" (ink text, grey italic comments, indigo keywords, sienna strings, ochre constants, teal functions, plum types).
  11. A README is a document page: a sheet with a measured column and an "On this page" outline beside it.
  12. Captions speak like a paper: "Fig. 1 — clone over HTTPS".
  13. Motion is short (120–280 ms) and functional; everything honours prefers-reduced-motion.
  14. Mobile first: the base styles are the phone layout; nothing scrolls sideways except code, diffs, the calendar and tab strips, inside their own block.
  15. One icon set (Lucide, ISC, stroke 1.75) and one monogram: the black "SB" tile.

# 2. Tokens (src/web/assets/css/tokens.css)

Semantic only; components never use raw colours.

Group Tokens
Surfaces --bg (paper) · --surface-0 (sheet, cards, code) · --surface-1..3 (bands, hover, tracks) · --bg-elev (dialogs) · --glass, --nav-bg
Ink --fg · --fg-bright · --fg-muted · --fg-faint (all ≥ 4.5:1 on --bg and --surface-0) · --ink / --on-ink (primary button, monogram, selected states)
Lines --border (hairline) · --border-strong (controls) · --rule (2 px ink rules) · --grid-line
Accent --accent · --accent-hover · --accent-soft · --accent-line
Status --ok · --warn · --danger (+ -soft) · --ember (rare warm marker)
Diff --add-bg · --add-bg-strong · --add-text · --del-bg · --del-bg-strong · --del-text · --hunk-bg
Code --code-bg · --code-head; syntax colours come from the shiki themes (--shiki-light, --shiki-dark)
Calendar --heat-0..4 — a single indigo ramp
Space --space-1..11 = 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 88 px
Geometry --radius 2 px (controls) · --radius-lg 0 (cards) · --touch 44 px · --header-h 60/54 px · --container 1200 px · --measure 860 px
Motion --dur-fast 120 ms · --dur 180 ms · --dur-slow 280 ms · --ease · --ease-out

# Themes

Theme Paper Ink Accent Use
light oklch(0.972 0.006 85) oklch(0.245 0.016 75) oklch(0.44 0.155 268) the paper of spboucher.ai (default when the OS is light)
dark oklch(0.185 0.008 75) oklch(0.925 0.01 85) oklch(0.77 0.105 268) its night edition (default when the OS is dark)
midnight #000 oklch(0.955 0.004 270) oklch(0.82 0.1 268) true black, maximum contrast, for OLED screens

theme-boot.js resolves auto | light | dark | midnight from localStorage['spbgit-theme'] before first paint. Every theme is checked with scripts/qa/axe.py (WCAG 2.1 AA).

# 3. Type

Role Family Size / weight Where
Masthead Fraunces 600, italic 400 for the name --text-hero clamp(40, 6vw, 70) / 1.04 front page
Page title Fraunces 600 --text-3xl clamp(30, 3.6vw, 40) search, about pages
Repository title Fraunces 600 (owner 400) clamp(30, 4.6vw, 50); 22–28 on sub-pages repository header
Section title Fraunces 600 --text-2xl 28 numbered sections
Numerals Fraunces 600, lining tabular 40 / 36 / 24 figure rows
Names in lists Fraunces 600 19–22 index rows, cards, results
Text Inter 400/500/600 --text-base 15 / 1.6; README 16 / 1.65 everything else
Label IBM Plex Mono 500, uppercase --text-2xs 10.5–11, tracking 0.14–0.2 em eyebrows, captions, tabs, nav, column heads
Meta IBM Plex Mono 400/500 11–12.5, tabular dates, sizes, SHAs, paths
Code IBM Plex Mono 400 (italic for comments) 12.75 / 1.7 blobs, diffs, blame, fences

Fonts are self-hosted and tracked in git (src/web/assets/fonts/, OFL, latin subset, from the @fontsource packages): Fraunces variable (opsz + wght) and italic 400, Inter variable, IBM Plex Mono 400/400i/500/600. Inter and Fraunces are preloaded; font-display: swap with metric-adjusted fallbacks (Inter Fallback, Fraunces Fallback, Plex Mono Fallback) so the swap does not move the layout. scripts/fetch-fonts.mjs only verifies/repairs the files.

# 4. Components (views/components/ui.njk, assets/css/app.css)

Component Markup Notes
Icon ui.icon(name, size) Lucide subset, generated path data; add the name to the macro before use; app.js carries the client-side subset (svgIcon)
Monogram .brand-mark "SB" in Plex Mono 600 on an ink tile; assets/img/logo.svg and the PNG icons are the same outlines
Eyebrow .eyebrow + .eyebrow-rule short accent rule, optional number, mono caps
Section head ui.sectionHead(id, no, eyebrow, title, sub, count) caller block = trailing control or link
Figure row ui.statStrip(items, cls) .stat-strip-hero (one rule per figure) · .stat-strip-repo (one rule for the row)
Label head .label-head mono caps over a 2 px rule: side lists, result groups
Button .btn · .btn-primary · .btn-ghost · .btn-sm · .seg 38/30 px, 44 px on touch; pressed/active = ink
Tag ui.chip(label, kind) square mono tag; topic, accent, ok, warn, danger
Tabs ui.tabs(items, active) mono caps, 2 px accent underline, scrolls inside its strip
Breadcrumbs / ref picker ui.breadcrumbs, ui.refSelect mono; native <select> for iOS
Card .card (+ .card-head, .card-pad) hairline sheet, no radius, no shadow
Feature card partials/repo-card.njk numbered plate ("No. 01"), lifts 1 px on hover
Index row partials/repo-row.njk CSS counter numbering, serif name, mono facts, sparkline
Ledger .ref-list, .rank-list, .activity-feed, .search-results hairline rows, mono meta
Plate / figure .plate, .figure-block + figcaption framed specimen with offset grid; captions "Fig. n — …"
File list partials/file-table.njk latest-commit strip, 40 px rows
Document .readme-section, .prose-layout, markdown.css sheet + outline (.readme-toc, .prose-nav)
Code .code-view, .diff-file, .blame-table sticky file header, line numbers behind a hairline
States ui.emptyState, ui.errorState, ui.skeleton, .notice dashed frame, serif title; notice = accent bar
Dialogs .sheet, .popover, .cmdk, .confirm, .toast bottom sheets under 768 px, ink-bordered panels above
Progress html.is-loading 2 px accent hairline while the next page loads

# 5. Rules

  • Run python3 -I scripts/qa/screens.py <url> <out> (must print OK — 0 failing) and python3 -I scripts/qa/axe.py <url> (0 violations) before any CSS change ships.
  • Every grid track is minmax(0, 1fr); scroll containers are bounded and keyboard-focusable.
  • Essential controls are ≥ 44 × 44 px on coarse pointers.
  • Cards with sticky headers use overflow: clip, never overflow: hidden.
  • No emoji or text glyphs as icons in the chrome; no gradient fills; no pill shapes.
  • Dates show a relative label with the exact instant in title (dateexact filter).
  • Repository authors' Markdown is content: badges keep their natural height, centred blocks stay centred, tables scroll inside themselves.
  • Bump package.json on every release: assets are cache-busted with ?v=<version>.
  • Print: README, files and prose print as plain documents (@media print in app.css).

# 6. Screenshots

docs/screenshots/v3/ holds eight before/after pairs of the 2.0 → 3.0 redesign (before-<page>-<width>-<theme>.png / after-…, development data) and the production views taken after the deployment (prod-*.png). The 1.1 and 2.0 sets (docs/screenshots/baseline/, docs/screenshots/v2/) were removed from the tree in 3.0; they remain in the git history (commit 7864e4d).

Files main
Menu

Theme