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

docs: add user theme preferences design plan

Completed brainstorming session. Design includes:
- Cookie-based preference storage (atbb-light-theme, atbb-dark-theme)
- PRG form with HTMX live color swatch preview
- User preference as first step in theme resolution waterfall
- 5 implementation phases with full acceptance criteria

+30
+30
docs/design-plans/2026-03-20-user-theme-preferences.md
··· 45 45 - **user-theme-preferences.AC5.2 Success:** Theme resolution ignores user preference cookies when `allowUserChoice: false` and uses forum default 46 46 47 47 ### user-theme-preferences.AC6: Preview endpoint 48 + <<<<<<< HEAD 48 49 - **user-theme-preferences.AC6.1 Success:** `GET /settings/preview?lightThemeUri=<valid-uri>` (or `?darkThemeUri=`) returns an HTML fragment with swatches and theme name 49 50 - **user-theme-preferences.AC6.2 Edge:** `GET /settings/preview?lightThemeUri=<unknown-uri>` (or `?darkThemeUri=`) returns an empty `<div id="theme-preview">` fragment without crashing 51 + ======= 52 + - **user-theme-preferences.AC6.1 Success:** `GET /settings/preview?theme=<valid-uri>` returns an HTML fragment with swatches and theme name 53 + - **user-theme-preferences.AC6.2 Edge:** `GET /settings/preview?theme=<unknown-uri>` returns an empty `<div id="theme-preview">` fragment without crashing 54 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 50 55 51 56 ## Glossary 52 57 ··· 74 79 A new route file (`apps/web/src/routes/settings.tsx`) registers three endpoints: 75 80 76 81 - `GET /settings` — fetches the theme policy, partitions available themes by `colorScheme`, reads existing preference cookies to pre-select values, and renders the settings page inside `BaseLayout` 82 + <<<<<<< HEAD 77 83 - `GET /settings/preview?lightThemeUri=<uri>` (or `?darkThemeUri=<uri>`) — HTMX endpoint; whichever select fired sends its name/value via `hx-include="this"`. Fetches the theme by rkey and returns an HTML fragment of color swatches. 84 + ======= 85 + - `GET /settings/preview?theme=<uri>` — HTMX endpoint; fetches the theme by URI and returns an HTML fragment of color swatches (used to preview a theme before saving) 86 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 78 87 - `POST /settings/appearance` — validates `lightThemeUri` and `darkThemeUri` against the current policy's `availableThemes`, sets `atbb-light-theme` and `atbb-dark-theme` cookies, redirects 302 to `/settings?saved=1` 79 88 80 89 The theme resolution waterfall in `apps/web/src/lib/theme-resolution.ts` gains a new first lookup step: read the user preference cookie for the active color scheme and validate the stored URI is still present in `availableThemes`. If valid, use it; if stale or missing, fall through to the existing forum-default and preset-fallback steps. ··· 106 115 107 116 **Done when:** Tests pass for all cases; `pnpm test` passes; theme resolution uses user cookie when valid. 108 117 118 + <<<<<<< HEAD 109 119 **Covers:** user-theme-preferences.AC3.1, user-theme-preferences.AC3.2, user-theme-preferences.AC3.3, user-theme-preferences.AC5.2 120 + ======= 121 + **Covers:** user-theme-preferences.AC3.1, user-theme-preferences.AC3.2, user-theme-preferences.AC3.3, user-theme-preferences.AC5.1, user-theme-preferences.AC5.2 122 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 110 123 <!-- END_PHASE_1 --> 111 124 112 125 <!-- START_PHASE_2 --> ··· 125 138 126 139 **Done when:** All integration tests pass; `pnpm test` passes; preferences round-trip correctly. 127 140 141 + <<<<<<< HEAD 128 142 **Covers:** user-theme-preferences.AC1.2, user-theme-preferences.AC1.5, user-theme-preferences.AC2.1, user-theme-preferences.AC2.2, user-theme-preferences.AC2.3, user-theme-preferences.AC4.1, user-theme-preferences.AC4.2, user-theme-preferences.AC4.3, user-theme-preferences.AC4.4, user-theme-preferences.AC5.1 143 + ======= 144 + **Covers:** user-theme-preferences.AC1.1, user-theme-preferences.AC1.2, user-theme-preferences.AC2.1, user-theme-preferences.AC2.2, user-theme-preferences.AC2.3, user-theme-preferences.AC4.1, user-theme-preferences.AC4.2, user-theme-preferences.AC4.3, user-theme-preferences.AC4.4, user-theme-preferences.AC6.1, user-theme-preferences.AC6.2 145 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 129 146 <!-- END_PHASE_2 --> 130 147 131 148 <!-- START_PHASE_3 --> ··· 134 151 **Goal:** Add the color swatch preview fragment returned when the user changes a `<select>`. 135 152 136 153 **Components:** 154 + <<<<<<< HEAD 137 155 - `GET /settings/preview` handler in `apps/web/src/routes/settings.tsx` — accepts `?lightThemeUri=` or `?darkThemeUri=` (whichever select fired via `hx-include="this"`); fetches theme from AppView by rkey, extracts key tokens (`color-bg`, `color-surface`, `color-primary`, `color-text`, `color-border`), returns an HTML fragment with swatches and theme name; returns empty `<div id="theme-preview">` on unknown URI or fetch failure 138 156 - `<select>` elements in the settings page carry `hx-get="/settings/preview"`, `hx-trigger="change"`, `hx-target="#theme-preview"`, `hx-swap="outerHTML"`, `hx-include="this"` 157 + ======= 158 + - `GET /settings/preview?theme=<uri>` handler in `apps/web/src/routes/settings.tsx` — fetches theme from cache, extracts key tokens (`color-bg`, `color-surface`, `color-primary`, `color-text`, `color-border`), returns an HTML fragment with swatches and theme name; returns empty `<div id="theme-preview">` on unknown URI or fetch failure 159 + - `<select>` elements in the settings page carry `hx-get="/settings/preview?theme={value}"`, `hx-trigger="change"`, `hx-target="#theme-preview"`, `hx-swap="outerHTML"` 160 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 139 161 - Tests: preview returns swatch fragment for valid URI; returns empty div for unknown URI; select attributes are present in rendered page HTML 140 162 141 163 **Dependencies:** Phase 2 (settings page and route file exist) 142 164 143 165 **Done when:** Tests pass; selecting a theme in the UI swaps in a swatch preview; `pnpm test` passes. 144 166 167 + <<<<<<< HEAD 145 168 **Covers:** user-theme-preferences.AC1.3, user-theme-preferences.AC1.4, user-theme-preferences.AC6.1, user-theme-preferences.AC6.2 169 + ======= 170 + **Covers:** user-theme-preferences.AC1.3, user-theme-preferences.AC1.4 171 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 146 172 <!-- END_PHASE_3 --> 147 173 148 174 <!-- START_PHASE_4 --> ··· 158 184 159 185 **Done when:** Tests pass; authenticated users see Settings link; unauthenticated users do not; `pnpm test` passes. 160 186 187 + <<<<<<< HEAD 161 188 **Covers:** user-theme-preferences.AC1.1 189 + ======= 190 + **Covers:** user-theme-preferences.AC1.1 (discoverability), user-theme-preferences.AC2.1 191 + >>>>>>> 3e0fcd6 (docs: add user theme preferences design plan) 162 192 <!-- END_PHASE_4 --> 163 193 164 194 <!-- START_PHASE_5 -->