Skip to content

Module redesign: Archival Technical Minimalism (paper spec sheets)#21

Open
iblh wants to merge 18 commits into
masterfrom
feat/archival-technical-redesign
Open

Module redesign: Archival Technical Minimalism (paper spec sheets)#21
iblh wants to merge 18 commits into
masterfrom
feat/archival-technical-redesign

Conversation

@iblh

@iblh iblh commented Jun 26, 2026

Copy link
Copy Markdown
Owner

A component-level redesign of the dashboard modules toward Archival Technical Minimalism / Paper Instrument UI (Dieter Rams discipline, technical spec sheets, instrument panels) — not a token/color pass. The core fix is structural: modules that report data previously stacked nested bordered sub-cards and bordered "badges"; they now read like a printed spec sheet built from a small set of shared primitives. Net effect removes ~313 lines of boxy per-module markup while adding one reusable primitives module.

The new visual system — web/src/components/Tree/specPrimitives.tsx

Shared, token-driven (so dark mode follows), documented in DESIGN_SPEC.md:

  • SpecCaption — mono uppercase block header on a single hairline rule (the only internal header).
  • SpecRow / SpecRows — label-left / tabular-nums-value-right ledger with faint dividers; two side-by-side = a fact sheet.
  • SpecMetric — gauge cell: tiny label + tabular value over a 1px bar on a hairline track; tone (moss→amber→rust) only under load.
  • MetaChip / MetaChipGroup — borderless metadata chips, label/value split by one hairline (replaces bordered badges).
  • Sparkline — the single trend language (1.25px non-scaling polyline + optional 8% area fill), tone carries meaning. No chart libraries. Unifies three previously-duplicated sparkline implementations.

Per module

  • Server (largest change): removed ServerUsageCard / ServerLoadCard / ServerFactChips / ServerTrendPanel (each a bordered sub-card). Now a clean header on a rule → 3-up CPU/Mem/Disk gauge strip → two-column facts ledger (mem/disk/uptime · net↓/↑/cores·temp) → one 24h telemetry strip of three labeled sparklines. Status is a bare online/stale dot, not a pill. Preserves status/stale, all metrics, load, trends, and edit/drag.
  • Media: provider key stats render as a borderless two-column ledger under the status line (replaces the bordered badge grid); libraries use MetaChips; recent covers drop the grey border+fill for a faint hairline ring so the original artwork reads cleanly; now-playing/queue thumbnails + progress bars match. Plex/Radarr/Sonarr (and Jellyfin/Emby) share one shape regardless of which stats each returns.
  • Weather: forecast becomes a per-day ledger (weekday · condition · right-aligned tabular hi/lo) — condition text readable without noise; location/humidity move to a mono caption.
  • Calendar: printed-grid feel — mono tabular day numbers, quiet weekday rail, precise solid-ink current-day marker (inverse text, theme-safe) replacing the heavy bordered box.
  • Markets: same list layout; adopts the shared Sparkline (tone follows direction) + tabular nums.
  • Posts: mono technical tabs with a solid-ink active underline over the baseline and a smooth hairline hover fade; preserves the sliding hover rail and edit-mode tab composition (stacked sources shown as one composed module).
  • Edit mode: verified WYSIWYG — controls layer in-place (grips, "+", trash), layout does not reshape.

Validation

  • npm run lint ✓ · npm run test:unit ✓ (13/13) · npm run build
  • Browser-inspected (local macOS Chrome): normal + edit mode, all modules, dark mode (no regression — calendar marker correctly inverts), empty/baseline Server state, light & restored-system themes. Draft edits discarded (no live dashboard mutation).
  • No new dependencies. Branch is on master HEAD (no conflicts).

Reviewer notes / tradeoffs

  • Media provider stats are limited to existing API fields (MediaModuleData.stats/libraries/lastAddedAt). No new upstream calls or fields were added, so the ledger surfaces what's available rather than inventing metrics. Richer per-provider stats would need provider-side changes (out of scope).
  • Fixed-width principle preserved: percentage section columns + max-w card caps mean items don't stretch on wide screens. A true mobile breakpoint pass is a separate effort.
  • The single-root edit card (Weather/Calendar/Markets config) keeps its bordered form container — a deliberate existing pattern left untouched to avoid scope creep.

🤖 Generated with Claude Code

iblh added 18 commits June 25, 2026 13:43
Introduce shared Archival Technical Minimalism primitives (specPrimitives.tsx):
SpecCaption (hairline-ruled mono section header), SpecRow/SpecRows (aligned
tabular-number ledger), SpecMetric (gauge cell with a hairline-tracked bar),
MetaChip/MetaChipGroup (borderless metadata), and one Sparkline language.

Rebuild the server card with them instead of boxes-in-boxes: a clean header on
a hairline rule, a 3-up CPU/Mem/Disk gauge strip, a two-column facts ledger
(mem/disk/uptime · net in/out/cores·temp), and a single 24h telemetry strip of
three labeled sparklines. Removes ServerUsageCard/ServerLoadCard/
ServerFactChips/ServerTrendPanel/TrendMini/TrendSparkline and the duplicated
local sparklinePoints. Preserves status/stale, all metrics, load, trends, and
edit/drag. Glanceable instrument panel, not a monitoring SaaS card.
… clean covers

Rework MediaWidget toward the archival system and align Plex/Jellyfin/Emby/
Radarr/Sonarr to one shape:
- Provider key stats now render as a borderless two-column ledger (MediaStatLedger)
  directly under the status line, replacing the bordered MediaInsightBadges grid.
- Libraries use the shared borderless MetaChip language instead of bordered pills.
- Recent covers drop the grey border+fill for a faint hairline ring so the
  original artwork reads cleanly; letter fallbacks use the serif face.
- Now-playing / queue thumbnails match the same hairline ring; progress bars are
  crisp 1px hairlines.
Section order tightened (status → stats → now playing → queue → libraries →
recent) and inner rules use consistent SpecCaption-style hairline headers.
Weather: forecast becomes a per-day ledger (weekday · condition · right-aligned
tabular hi/lo) instead of a cramped 3-up grid, so condition text is readable
without noise; location/humidity move to a mono caption beside the temperature.
Calendar: month grid reads like a printed instrument — mono tabular day numbers,
quieter weekday rail, and a precise solid-ink current-day marker (inverse text,
theme-safe) replacing the heavy bordered box.
Markets: adopt the shared Sparkline (tone follows the day's direction) and add
tabular-nums to change/price; list structure unchanged.
Removes the now-dead local MarketSparkline + sparklinePoints/roundSvgNumber.
Tabs: mono uppercase labels with a solid-ink active underline that overlays the
baseline rule (1.5px), and idle tabs reveal a faint hairline on hover with a
smooth 200ms fade — reads as printed technical tabs, not boxed controls. The
sliding hover rail and edit-mode tab composition (stacked sources shown as one
tabbed module) are preserved. Post meta uses tabular-nums and a quieter source
caption.
Add a Structure subsection documenting the Archival Technical Minimalism
primitives introduced for Media + Server (specPrimitives.tsx): the no-boxes-in-
boxes rule, SpecCaption/SpecRow/SpecMetric/MetaChip/Sparkline vocabulary, and
the bare-label status convention. New pattern → spec first, per CLAUDE.md.
…n today, week numbers

Introduce the dashboard's signature archival devices and apply them to Calendar
as a vertical slice (style probe before rolling out to other modules):

- SpecHeader: a filed-record index line — fixed module code (CAL) + provenance
  (LOCAL) on the left, a registration mark (⌖) + serial (2026·06) on the right,
  on one hairline rule. The site-wide motif that makes a module read as an
  archived record, not a generic card.
- RegistrationMark: four corner crop-ticks framing content; the new focus/today
  marker (instrument target, not a filled highlight).
- Stamp: one mono stamped-label status language (live/idle/±/syncing) for reuse.

Calendar is rebuilt as a month ledger: a WK week-number gutter column (the
technical tell), mono tabular days, printed-grey out-of-month + lighter weekend
days, and the registration-mark today cell replacing the solid-ink square.
Adds isoWeekNumber + formatMonthSerial helpers. No grain, no card border,
WYSIWYG and dark-mode tokens intact.
Thread an optional specHeader slot through ModulePanel (+ renderModuleStatusControl
to keep refresh/status in its right slot), then roll the motif out:

- Markets: MKT / LIVE header with a '<n> SYM' serial; each row reads as a ticker
  instrument; delta becomes a stamped ▲/▼ signed figure (positive/negative tone).
  Removes the now-unused marketTrendTone.
- Weather: WTHR / LIVE header (°C/°F serial); temperature reads as a measurement
  figure with a unit tick; station metadata (location, RH) aligned right.
- Server: an SRV / LIVE (or STALE) index line above the device label; status now
  uses the shared Stamp primitive instead of an ad-hoc badge.

No new card borders; dark-mode tokens intact.
- Media: provider status line becomes a MED / <service> index with the live
  session count (or status) rendered as a Stamp instead of an ad-hoc dot label.
- Posts: stacked header gains an IDX tag and the active source tab carries a
  small filled stamp marker (the 'current divider'), keeping the sliding hover
  rail and underline. RegistrationMark stays reserved for box-framed current
  items (calendar today), per the sparse-usage rule.

lint, test:unit (13/13), build all pass.
- Loading: skeletons become a blank archive record filling in — faint ruled
  label ticks + empty value slots (hairline 'Slot's), a calm recordSweep opacity
  animation (reduced-motion aware) instead of a generic pulse. The media
  skeleton drops its bordered sub-boxes to match the borderless ledger.
- Empty: a blank catalog card — a 'NIL' stamp over a hairline + one terse line.
- Error: an inspection note — a 'NO READING' ✕ stamp over a faint rust rule with
  the message beneath, instead of a red SaaS alert.

Shared via ModuleBodyState/EmptyModuleState so every module inherits them.
- Markets rows: a left guide-rule grows in on hover like a ruler cursor, and the
  symbol nudges off it — instrument-selector feel instead of a flat bg tint.
- Calendar cells: RegistrationMark gains an opt-in hoverTickClass so a hovered
  day reveals faint corner ticks (the same 'cursor lands here' language as the
  today marker), kept to a literal class so the JIT generates it.

lint, build pass.
…width

- Weather: let the station location take remaining width (temperature is shrink-0)
  so common city names like 'San Francisco, California' no longer truncate early.
- DESIGN_SPEC: add a 'Signature archival elements' section documenting the three
  memory-point devices (SpecHeader codes/provenance, RegistrationMark for
  current-only, Stamp status language), each module's archival form, the
  in-character loading/empty/error states, and the mechanical-hover rule.
Edit mode now reads like laying work out on a drafting sheet, without changing
controls or drag behaviour:
- Each section header shows a small mono grid coordinate (A:1, B:2, …) beside its
  grip — a plate number on a technical sheet, derived from the live row/column.
- While a section is dragged, a very faint drafting grid fades in behind the
  layout (.drafting-surface, toggled by data-drafting). Off at rest; view mode
  untouched; WYSIWYG preserved.

lint, build pass.
Replace the system sans/mono stacks with Geist (prose/UI) and Geist Mono (all
data) via next/font/google — the archival 'spec sheet' voice needs a consistent
technical typeface across platforms, not whatever the OS ships. Exposes
--font-sans / --font-mono and points tailwind font-body / font-mono at them;
serif titles (Sorts Mill Goudy) unchanged. No new dependency; build fetches the
faces. This is the foundation for the document-shell + mechanical-number passes.
The motif now reaches the page level so the dashboard reads as one filed sheet,
not floating modules:
- A masthead band above the greeting: OPAQUE wordmark + 'personal archive', and
  mono datestamp fields on the right (SHEET 01/01 · DATE <ISO> · TZ <offset>),
  on a hairline rule. Date/TZ computed client-side to avoid SSR locale mismatch.
- Faint registration / crop corners on the content frame (DocumentFrame) — the
  edges of a printed sheet.
- Footer becomes a colophon mirroring the masthead: DOC · SCALE 1:1 · PAGE 01/01
  · © OPAQUE, aligned to the same page margins.

Token-driven; dark-mode safe; header controls untouched.
Add a RollingNumber primitive — each digit is a 0-9 reel that rolls to the new
value when it changes, like a mechanical counter / instrument. Non-digit glyphs
stay fixed; animates only after the first change (no roll-from-zero on load);
honors prefers-reduced-motion. Wired into the values that actually update on
poll: markets price + delta, the weather temperature, and the server CPU/Mem/Disk
gauges (via SpecMetric). Tabular + monospaced so columns never shift.

tsc, lint, build pass; verified baseline alignment in browser.
…douts

Record the bold-pass conventions in DESIGN_SPEC: Geist / Geist Mono as the
body/data voice, the document shell (masthead + registration frame + footer
colophon = 'the page is a filed sheet'), and RollingNumber mechanical readouts
for live values (the one place motion is expressive, with the usage limits).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant