Var-ify inline styles and snap off-scale type/radii (design Phase 2)
Phase 2 of the design-contract cleanup: - 346 inline-style hexes (+7 #475569, mapped by property) -> var(--token), scoped to CSS-value position so JS-logic/quoted hex, the meta theme-color, SVG attrs, and the no-:root share-export region stay literal; #fff and no-token hexes left as-is. - Snap off-scale font sizes (9/10.5->10, 11.5/12.5->12, 15->16, 24->22) and radii (3->4, 5->6, 7->6, 11->12, 9->8|10) to the scale. - Bump to 0.2.161, which also ships the previously-uninstalled 0.2.160 share-page HTML export.
This commit is contained in:
@@ -136,11 +136,11 @@ unsure whether a change is contract-affecting, assume it is and check.
|
||||
|
||||
## Current state
|
||||
|
||||
**Live on the operator's StartOS box** — app **0.2.159** + relay **0.2.126**. Tests: `cd server && npm test` → **144 pass**.
|
||||
**Live on the operator's StartOS box** — app **0.2.161** + relay **0.2.126**. Tests: `cd server && npm test` → **144 pass**.
|
||||
|
||||
**Done & live:** self-serve Pro/Max purchase (Bitcoin inline-Lightning + Zaprite card, prepaid, relay owns tier/expiry), core-decoupling, per-tenant subscriptions, expiry-reminder emails (`POST /api/admin/reminders/run {test_email}`), **opt-in Daily Digest** (0.2.158, `b4fa5d7`): off-by-default daily email of a user's last ~24h of library recaps, each synthesized via `/relay/analyze` (operator-absorbed); `daily-digest.js` scan at `SEND_HOUR=8`, per-user watermark dedup, public tokenized unsubscribe, admin trigger `POST /api/admin/digest/run`; and **YouTube `/live/` + `/shorts/` URL support** (0.2.159, `cb961cd`): `extractVideoId` now accepts those forms (was rejecting them as "Invalid YouTube URL"). Plans in `docs/*-plan.md`.
|
||||
**Done & live:** self-serve Pro/Max purchase (Bitcoin inline-Lightning + Zaprite card, prepaid, relay owns tier/expiry), core-decoupling, per-tenant subscriptions, expiry-reminder emails (`POST /api/admin/reminders/run {test_email}`), **opt-in Daily Digest** (0.2.158, `b4fa5d7`): off-by-default daily email of a user's last ~24h of library recaps, each synthesized via `/relay/analyze` (operator-absorbed); `daily-digest.js` scan at `SEND_HOUR=8`, per-user watermark dedup, public tokenized unsubscribe, admin trigger `POST /api/admin/digest/run`; **YouTube `/live/` + `/shorts/` URL support** (0.2.159, `cb961cd`): `extractVideoId` now accepts those forms (was rejecting them as "Invalid YouTube URL"); and **self-contained shareable HTML export** (0.2.160, `621af7c`; first installed in 0.2.161): the Export menu offers a standalone `.html` with the embedded video + expandable timestamped summaries baked in, no account needed (native share sheet on mobile, download on desktop). Plans in `docs/*-plan.md`.
|
||||
|
||||
**Design system (NEW this session, NOT yet deployed):** the `design/` contract is live (`design/DESIGN.md` + `design/tokens.tokens.json`; see the **Design** line up top). Phase 1 of the conformance cleanup is done — a canonical `:root` token block is the single source of truth in `public/index.html`'s `<style>`, the stylesheet + `public/auth.html` use `var(--token)`, and all color/weight drift is fixed across every surface (auth blue→indigo, legacy darks→ladder). Verified locally (144 tests, both pages serve 200, all `var()` resolve); **not installed** — reaches recaps.cc only on the next box-serve / `make install`. Phase 2 (var-ify the long-tail inline styles; snap off-scale font/radius — both *visible* changes) is queued in `ROADMAP.md`.
|
||||
**Design system — DONE & live (0.2.161).** The `design/` contract (`design/DESIGN.md` + `design/tokens.tokens.json`; see the **Design** line up top) plus both cleanup phases are now installed. Phase 1: a canonical `:root` token block is the single source of truth in `public/index.html`'s `<style>`; the stylesheet + `public/auth.html` use `var(--token)`; all color/weight drift fixed. Phase 2: var-ified the long-tail inline `style=` hexes (346 + 7 `#475569` → `var()`, scoped to CSS-value position so JS-logic/quoted hex, the `<meta theme-color>`, SVG attrs, and the no-`:root` `SHARE_PAGE_*` region were dodged; `#fff` and no-token hexes left literal on purpose), and snapped off-scale font sizes (21) + radii (18) to the scale. Verified: 144 tests, both pages serve 200, every `var()` resolves, no off-scale residue. Phase 2 details + the remaining Style-Dictionary stretch goal are in `ROADMAP.md`.
|
||||
|
||||
**Only loose end:** the Daily Digest's relay-synthesis + SMTP path can't be exercised off-box, so it's installed but **not yet smoke-tested** — that's operator action #5 below. Everything else (schema/upgrade, scheduler boot, unsubscribe flow) is verified.
|
||||
|
||||
|
||||
+20
-14
@@ -32,20 +32,26 @@ Verified: 144 tests pass, both pages serve 200, all 426+27 `var()` references re
|
||||
undefined vars. (`SHARE_PAGE_CSS` and `auth.html` are standalone documents that each carry
|
||||
their own copy — kept in sync; the meta `theme-color` stays a literal `#0a0e1a`.)
|
||||
|
||||
**Phase 2 — REMAINING (deliberately deferred; these are *visible* changes, unlike Phase 1's
|
||||
no-op var migration).**
|
||||
- **Var-ify the long-tail inline `style=` attributes.** Phase 1 fixed the *drift* inline
|
||||
values but left canonically-correct inline hexes as literals (the stylesheet is now the
|
||||
single source of truth; inline styles still hardcode). Convert them to `var(--token)` now
|
||||
that the tokens exist — but dodge the spots that can't take `var()`: the `<meta theme-color>`,
|
||||
SVG `fill`/`stroke` set via JS (e.g. `index.html` sub-icon), and any hex used in JS *logic*
|
||||
rather than as a CSS value. Per-occurrence judgement, not a blind sweep.
|
||||
- **Snap off-scale font sizes** to the scale: `15→16`, `24→22`, `9→10`, `12.5/11.5→12`,
|
||||
`10.5→10` (~23 occurrences). Each is a small visible size change — eyeball per component.
|
||||
- **Snap off-scale radii**: `3→4`, `5→6`, `7→6|8`, `9→8|10`, `11→10|12` (~18; scrollbars,
|
||||
history/queue action buttons, mobile submit/menu, buy inputs).
|
||||
- **(stretch) Generate `design/brand/palette.css` from the tokens** (Style Dictionary) and
|
||||
`@import`/inline it, so the `:root` block isn't hand-maintained in three places.
|
||||
**Phase 2 — DONE 2026-06-17 (shipped in app 0.2.161).**
|
||||
- **Var-ified the long-tail inline `style=` attributes** — 346 inline-style hexes (+7
|
||||
`#475569`, mapped by property to `--text-faint`/`--border-strong`) → `var(--token)`. Scoped
|
||||
to CSS-value position (hex preceded by `:`/space/`,`, never a quote), which cleanly dodged
|
||||
the non-`var()` spots: the `<meta theme-color>`, SVG `fill`/`stroke` attrs, and hex held in
|
||||
JS *logic* (quoted ternary branches like `${cond ? "#1e293b" : ...}`, `const colour = …`).
|
||||
Left as literals on purpose: `#fff` (its uses split between on-accent button text and
|
||||
functional white — `--on-accent` doesn't cleanly cover both, zero visual gain), no-token
|
||||
hexes (`#e0e7ff`/`#c7d2fe`/`#a78bfa`/`#04210f`/etc.), and the entire `SHARE_PAGE_*` export
|
||||
region (a standalone doc with no `:root` — `var()` wouldn't resolve there).
|
||||
- **Snapped off-scale font sizes** (21 occ): `9/10.5→10`, `11.5/12.5→12`, `15→16`, `24→22`.
|
||||
Left `40px`/`56px` display glyphs (success numeral, buy spinner) — off-scale by design.
|
||||
- **Snapped off-scale radii** (18 occ): `3→4`, `5→6`, `7→6`, `11→12`; `9→10` for the two 18px
|
||||
capsules (`.menu-badge`, `.rc-spk` — radius clamps at 9 on an 18px box, so on-scale and
|
||||
visually identical) and `9→8` for `.icon-btn`/`.buy-select-btn`/`.buy-discount-input`. Left
|
||||
the `1px` hamburger-bar radius. Verified: 144 tests pass, both pages serve 200, every
|
||||
introduced `var()` resolves against `:root`, no off-scale residue.
|
||||
- **(stretch, NOT done) Generate `design/brand/palette.css` from the tokens** (Style
|
||||
Dictionary) and `@import`/inline it, so the `:root` block isn't hand-maintained in three
|
||||
places. Still open.
|
||||
|
||||
## Known debt (P2, from the 2026-06-14 full-eval — `EVALUATION.md`)
|
||||
|
||||
|
||||
+303
-303
File diff suppressed because it is too large
Load Diff
@@ -179,8 +179,9 @@ import { v_0_2_157 } from './v0.2.157'
|
||||
import { v_0_2_158 } from './v0.2.158'
|
||||
import { v_0_2_159 } from './v0.2.159'
|
||||
import { v_0_2_160 } from './v0.2.160'
|
||||
import { v_0_2_161 } from './v0.2.161'
|
||||
|
||||
export const versionGraph = VersionGraph.of({
|
||||
current: v_0_2_160,
|
||||
other: [v_0_2_159, v_0_2_158, v_0_2_157, v_0_2_156, v_0_2_155, v_0_2_154, v_0_2_153, v_0_2_152, v_0_2_151, v_0_2_150, v_0_2_149, v_0_2_148, v_0_2_147, v_0_2_146, v_0_2_145, v_0_2_144, v_0_2_143, v_0_2_142, v_0_2_141, v_0_2_140, v_0_2_139, v_0_2_138, v_0_2_137, v_0_2_136, v_0_2_135, v_0_2_134, v_0_2_133, v_0_2_132, v_0_2_131, v_0_2_130, v_0_2_129, v_0_2_128, v_0_2_127, v_0_2_126, v_0_2_125, v_0_2_124, v_0_2_123, v_0_2_122, v_0_2_121, v_0_2_120, v_0_2_119, v_0_2_118, v_0_2_117, v_0_2_116, v_0_2_115, v_0_2_114, v_0_2_113, v_0_2_112, v_0_2_111, v_0_2_110, v_0_2_109, v_0_2_108, v_0_2_107, v_0_2_106, v_0_2_105, v_0_2_104, v_0_2_103, v_0_2_102, v_0_2_101, v_0_2_100, v_0_2_99, v_0_2_98, v_0_2_97, v_0_2_96, v_0_2_95, v_0_2_94, v_0_2_93, v_0_2_92, v_0_2_91, v_0_2_90, v_0_2_89, v_0_2_88, v_0_2_87, v_0_2_86, v_0_2_85, v_0_2_84, v_0_2_83, v_0_2_82, v_0_2_81, v_0_2_80, v_0_2_79, v_0_2_78, v_0_2_77, v_0_2_76, v_0_2_75, v_0_2_74, v_0_2_73, v_0_2_72, v_0_2_71, v_0_2_70, v_0_2_69, v_0_2_68, v_0_2_67, v_0_2_66, v_0_2_65, v_0_2_64, v_0_2_63, v_0_2_62, v_0_2_61, v_0_2_60, v_0_2_59, v_0_2_58, v_0_2_57, v_0_2_56, v_0_2_55, v_0_2_54, v_0_2_53, v_0_2_52, v_0_2_51, v_0_2_50, v_0_2_49, v_0_2_48, v_0_2_47, v_0_2_46, v_0_2_45, v_0_2_44, v_0_2_43, v_0_2_42, v_0_2_41, v_0_2_40, v_0_2_39, v_0_2_38, v_0_2_37, v_0_2_36, v_0_2_35, v_0_2_34, v_0_2_33, v_0_2_32, v_0_2_31, v_0_2_30, v_0_2_29, v_0_2_28, v_0_2_27, v_0_2_26, v_0_2_25, v_0_2_24, v_0_2_23, v_0_2_22, v_0_2_21, v_0_2_20, v_0_2_19, v_0_2_18, v_0_2_17, v_0_2_16, v_0_2_15, v_0_2_14, v_0_2_13, v_0_2_12, v_0_2_11, v_0_2_10, v_0_2_9, v_0_2_8, v_0_2_7, v_0_2_6, v_0_2_5, v_0_2_4, v_0_2_3, v_0_2_2, v_0_2_1, v_0_2_0, v_0_1_18, v_0_1_17, v_0_1_16, v_0_1_15, v_0_1_14, v_0_1_13, v_0_1_12, v_0_1_11, v_0_1_10, v_0_1_9, v_0_1_8, v_0_1_7, v_0_1_6, v_0_1_5, v_0_1_4, v_0_1_3, v_0_1_2, v_0_1_1, v_0_1_0],
|
||||
current: v_0_2_161,
|
||||
other: [v_0_2_160, v_0_2_159, v_0_2_158, v_0_2_157, v_0_2_156, v_0_2_155, v_0_2_154, v_0_2_153, v_0_2_152, v_0_2_151, v_0_2_150, v_0_2_149, v_0_2_148, v_0_2_147, v_0_2_146, v_0_2_145, v_0_2_144, v_0_2_143, v_0_2_142, v_0_2_141, v_0_2_140, v_0_2_139, v_0_2_138, v_0_2_137, v_0_2_136, v_0_2_135, v_0_2_134, v_0_2_133, v_0_2_132, v_0_2_131, v_0_2_130, v_0_2_129, v_0_2_128, v_0_2_127, v_0_2_126, v_0_2_125, v_0_2_124, v_0_2_123, v_0_2_122, v_0_2_121, v_0_2_120, v_0_2_119, v_0_2_118, v_0_2_117, v_0_2_116, v_0_2_115, v_0_2_114, v_0_2_113, v_0_2_112, v_0_2_111, v_0_2_110, v_0_2_109, v_0_2_108, v_0_2_107, v_0_2_106, v_0_2_105, v_0_2_104, v_0_2_103, v_0_2_102, v_0_2_101, v_0_2_100, v_0_2_99, v_0_2_98, v_0_2_97, v_0_2_96, v_0_2_95, v_0_2_94, v_0_2_93, v_0_2_92, v_0_2_91, v_0_2_90, v_0_2_89, v_0_2_88, v_0_2_87, v_0_2_86, v_0_2_85, v_0_2_84, v_0_2_83, v_0_2_82, v_0_2_81, v_0_2_80, v_0_2_79, v_0_2_78, v_0_2_77, v_0_2_76, v_0_2_75, v_0_2_74, v_0_2_73, v_0_2_72, v_0_2_71, v_0_2_70, v_0_2_69, v_0_2_68, v_0_2_67, v_0_2_66, v_0_2_65, v_0_2_64, v_0_2_63, v_0_2_62, v_0_2_61, v_0_2_60, v_0_2_59, v_0_2_58, v_0_2_57, v_0_2_56, v_0_2_55, v_0_2_54, v_0_2_53, v_0_2_52, v_0_2_51, v_0_2_50, v_0_2_49, v_0_2_48, v_0_2_47, v_0_2_46, v_0_2_45, v_0_2_44, v_0_2_43, v_0_2_42, v_0_2_41, v_0_2_40, v_0_2_39, v_0_2_38, v_0_2_37, v_0_2_36, v_0_2_35, v_0_2_34, v_0_2_33, v_0_2_32, v_0_2_31, v_0_2_30, v_0_2_29, v_0_2_28, v_0_2_27, v_0_2_26, v_0_2_25, v_0_2_24, v_0_2_23, v_0_2_22, v_0_2_21, v_0_2_20, v_0_2_19, v_0_2_18, v_0_2_17, v_0_2_16, v_0_2_15, v_0_2_14, v_0_2_13, v_0_2_12, v_0_2_11, v_0_2_10, v_0_2_9, v_0_2_8, v_0_2_7, v_0_2_6, v_0_2_5, v_0_2_4, v_0_2_3, v_0_2_2, v_0_2_1, v_0_2_0, v_0_1_18, v_0_1_17, v_0_1_16, v_0_1_15, v_0_1_14, v_0_1_13, v_0_1_12, v_0_1_11, v_0_1_10, v_0_1_9, v_0_1_8, v_0_1_7, v_0_1_6, v_0_1_5, v_0_1_4, v_0_1_3, v_0_1_2, v_0_1_1, v_0_1_0],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { VersionInfo } from '@start9labs/start-sdk'
|
||||
|
||||
export const v_0_2_161 = VersionInfo.of({
|
||||
version: '0.2.161:0',
|
||||
releaseNotes: {
|
||||
en_US: 'New: shareable HTML export for YouTube recaps — a self-contained .html file with the embedded video and expandable timestamped summaries baked in, openable by anyone with no account (native share sheet on mobile, download on desktop). Plus a design-system pass: colors, type sizes, and corner radii now follow one consistent set of tokens across the app.',
|
||||
},
|
||||
migrations: {
|
||||
up: async ({ effects }) => {},
|
||||
down: async ({ effects }) => {},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user