WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: ATB-52 CSS token extraction design doc

Malpercio efd7307b ceddbd09

+165
+165
docs/plans/2026-03-02-css-token-extraction-design.md
··· 1 + # ATB-52: CSS Token Extraction — Design 2 + 3 + **Status:** Approved, ready for implementation 4 + **Linear:** ATB-52 5 + **Date:** 2026-03-02 6 + 7 + --- 8 + 9 + ## Context 10 + 11 + The web UI uses a neobrutal aesthetic with a CSS custom property token system. Most of `theme.css` already references `var(--token)` exclusively. Two sections were added separately (moderation UI, structure management UI) and were never aligned with the token schema. This design covers the full extraction. 12 + 13 + `tokensToCss()` and `neobrutal-light.ts` already exist. The work is: fix the remaining hardcoded values, add one missing token, convert presets to JSON, and add the dark preset. 14 + 15 + --- 16 + 17 + ## Audit: Hardcoded Values Remaining 18 + 19 + ### Moderation UI (`theme.css` lines 751–821) 20 + 21 + | Hardcoded value | Replace with | 22 + |----------------|--------------| 23 + | `var(--space-2)` | `var(--space-sm)` (8px = 0.5rem) | 24 + | `var(--space-4)` | `var(--space-md)` (16px = 1rem) | 25 + | `var(--space-6)` | `var(--space-lg)` (24px = 1.5rem) | 26 + | `1px solid var(--color-border)` | `var(--border-width) solid var(--color-border)` | 27 + | `2px solid currentColor` | `var(--border-width) solid currentColor` | 28 + | `border-radius: 0` | `var(--radius)` | 29 + | `font-weight: 700` | `var(--font-weight-bold)` | 30 + | `0.25rem 0.6rem` (mod-btn padding) | `var(--space-xs) var(--space-sm)` | 31 + | `0.75rem` (mod-btn font-size) | `var(--font-size-xs)` ← new token | 32 + | `1.25rem` (dialog title font-size) | `var(--font-size-lg)` (20px = 1.25rem) | 33 + | `6px 6px 0 var(--color-shadow)` | `var(--card-shadow)` | 34 + | `color: #fff` (hover text) | `var(--color-surface)` | 35 + | `var(--color-danger, #d00)` | `var(--color-danger)` (remove fallback) | 36 + | `var(--color-text-muted, #666)` | `var(--color-text-muted)` (remove fallback) | 37 + | `3px solid var(--color-border)` | `var(--border-width) solid var(--color-border)` | 38 + 39 + ### Structure UI (`theme.css` lines 1003–1154) 40 + 41 + | Hardcoded value | Replace with | 42 + |----------------|--------------| 43 + | `var(--space-6, 1.5rem)` | `var(--space-lg)` (remove fallback) | 44 + | `var(--radius, 0.5rem)` | `var(--radius)` (remove fallback) | 45 + | `var(--radius, 0.375rem)` | `var(--radius)` (remove fallback) | 46 + | `var(--font-size-xl, 2rem)` | `var(--font-size-xl)` (remove fallback) | 47 + 48 + --- 49 + 50 + ## Token Schema Addition 51 + 52 + One new token added to complete the type scale: 53 + 54 + | Token | neobrutal-light | neobrutal-dark | Description | 55 + |-------|----------------|----------------|-------------| 56 + | `font-size-xs` | `12px` | `12px` | Extra-small text (mod buttons, badges) | 57 + 58 + --- 59 + 60 + ## Preset Files 61 + 62 + ### Format 63 + 64 + Convert from TypeScript to JSON. `resolveJsonModule: true` is already set in `tsconfig.base.json` — no config changes needed. Import in `base.tsx` changes to: 65 + 66 + ```typescript 67 + import neobrutalLight from "../styles/presets/neobrutal-light.json" assert { type: "json" }; 68 + ``` 69 + 70 + Or, since `moduleResolution: bundler` is set, the assert clause may not be required — verify during implementation. 71 + 72 + ### `neobrutal-light.json` (converted from existing TS, adds `font-size-xs`) 73 + 74 + ```json 75 + { 76 + "color-bg": "#f5f0e8", 77 + "color-surface": "#ffffff", 78 + "color-text": "#1a1a1a", 79 + "color-text-muted": "#555555", 80 + "color-primary": "#ff5c00", 81 + "color-primary-hover": "#e04f00", 82 + "color-secondary": "#3a86ff", 83 + "color-border": "#1a1a1a", 84 + "color-shadow": "#1a1a1a", 85 + "color-success": "#2ec44a", 86 + "color-warning": "#ffbe0b", 87 + "color-danger": "#ff006e", 88 + "color-code-bg": "#1a1a1a", 89 + "color-code-text": "#f5f0e8", 90 + "font-body": "'Space Grotesk', system-ui, sans-serif", 91 + "font-heading": "'Space Grotesk', system-ui, sans-serif", 92 + "font-mono": "'JetBrains Mono', ui-monospace, monospace", 93 + "font-size-base": "16px", 94 + "font-size-sm": "14px", 95 + "font-size-xs": "12px", 96 + "font-size-lg": "20px", 97 + "font-size-xl": "28px", 98 + "font-size-2xl": "36px", 99 + "font-weight-normal": "400", 100 + "font-weight-bold": "700", 101 + "line-height-body": "1.6", 102 + "line-height-heading": "1.2", 103 + "space-xs": "4px", 104 + "space-sm": "8px", 105 + "space-md": "16px", 106 + "space-lg": "24px", 107 + "space-xl": "40px", 108 + "radius": "0px", 109 + "border-width": "2px", 110 + "shadow-offset": "2px", 111 + "content-width": "100%", 112 + "button-radius": "0px", 113 + "button-shadow": "2px 2px 0 var(--color-shadow)", 114 + "card-radius": "0px", 115 + "card-shadow": "4px 4px 0 var(--color-shadow)", 116 + "btn-press-hover": "1px", 117 + "btn-press-active": "2px", 118 + "input-radius": "0px", 119 + "input-border": "2px solid var(--color-border)", 120 + "nav-height": "64px" 121 + } 122 + ``` 123 + 124 + ### `neobrutal-dark.json` (new) 125 + 126 + Same structural/typography/spacing tokens. Color tokens that differ: 127 + 128 + | Token | Value | 129 + |-------|-------| 130 + | `color-bg` | `#1a1a1a` | 131 + | `color-surface` | `#2d2d2d` | 132 + | `color-text` | `#f5f0e8` | 133 + | `color-text-muted` | `#a0a0a0` | 134 + | `color-primary-hover` | `#ff7a2a` (lightened for dark bg) | 135 + | `color-border` | `#f5f0e8` (inverted from light) | 136 + | `color-shadow` | `#000000` | 137 + | `color-code-bg` | `#111111` | 138 + 139 + All other tokens (primary, secondary, success, warning, danger, all typography, all spacing, all component) are identical to neobrutal-light. 140 + 141 + --- 142 + 143 + ## File Changes 144 + 145 + | File | Action | 146 + |------|--------| 147 + | `public/static/css/theme.css` | Fix ~15 hardcoded values in mod UI + structure UI | 148 + | `src/styles/presets/neobrutal-light.ts` | Delete | 149 + | `src/styles/presets/neobrutal-light.json` | Create (converted from TS, adds `font-size-xs`) | 150 + | `src/styles/presets/neobrutal-dark.json` | Create (dark color tokens, same structure) | 151 + | `src/layouts/base.tsx` | Update import to JSON | 152 + | `src/lib/theme.ts` | No changes | 153 + | `src/lib/__tests__/theme.test.ts` | No changes | 154 + 155 + --- 156 + 157 + ## Acceptance Criteria (from ATB-52) 158 + 159 + - [ ] `theme.css` contains zero hardcoded color values, font stacks, spacing values, or font sizes — all use `var(--token)` 160 + - [ ] No fallback values in `var()` calls (fallbacks are hardcoded values in disguise) 161 + - [ ] `tokensToCss()` utility exists and is tested (already satisfied) 162 + - [ ] `neobrutal-light.json` and `neobrutal-dark.json` ship with complete token sets 163 + - [ ] `--font-size-xs` added to both presets 164 + - [ ] `base.tsx` imports from JSON and the forum renders identically to before 165 + - [ ] All existing views render correctly after the refactor