Add issue #017: customizable, switchable document theme variants
Design issue capturing the request to let users customize document-artifact colors and switch between theme variants, instead of everyone getting one forced theme. Notes the two separable pieces (structure/skin split via CSS variables as a prerequisite — the themes currently hardcode colors — and a switching mechanism), the preset-vs-raw-CSS security tradeoff, dark-mode interaction, and deck as the concrete trigger. References the existing planning docs on theme variants/palettes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
95b159c0df
commit
a41e8dcfa5
1 changed files with 114 additions and 0 deletions
114
issues/017-customizable-document-theme-variants.md
Normal file
114
issues/017-customizable-document-theme-variants.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# 017 — Customizable, switchable theme variants for document artifacts
|
||||
|
||||
**Status:** Open
|
||||
**Type:** Feature / design (not a bug)
|
||||
|
||||
## Motivation
|
||||
|
||||
Document artifacts (`markdown`, `html_fragment`, `deck`, and the `json`/`csv`
|
||||
viewers) are effectively locked into a single look. The poster's agent can
|
||||
pass a `theme` (`report` / `tasks` / `base`), but:
|
||||
|
||||
- There's no way for a **viewer** to switch an artifact's appearance — the
|
||||
theme is fixed at post time and can't even be changed afterward (`theme`
|
||||
isn't a `PATCH`-editable field; see `ArtifactDetailView.patch`).
|
||||
- There are only three document themes, differing in more than just color.
|
||||
- Recent consistency work (unifying artifact backgrounds to one off-white,
|
||||
issue-driven) further homogenized the look — good for consistency, but it
|
||||
underlines that everyone gets one palette whether they want it or not.
|
||||
|
||||
The ask: let people **customize the colors** for the different document
|
||||
types, keeping the same structural CSS (same elements/selectors, same
|
||||
layout), and provide a **way to switch between variants** — so the app isn't
|
||||
forcing a single theme on everyone.
|
||||
|
||||
## Current state (for grounding)
|
||||
|
||||
- `theme` is a per-artifact `CharField`, set at create time:
|
||||
`theme = data.get("theme") or DEFAULT_THEMES.get(kind, "base")`
|
||||
(`DEFAULT_THEMES` maps markdown/html_fragment→`report`, deck→`deck`).
|
||||
- Rendered pages link `/static/themes/{theme}.css`. Theme files:
|
||||
`base.css`, `report.css`, `tasks.css`, `deck.css` (+ `pygments.css`).
|
||||
- **The theme CSS hardcodes colors** (e.g. `report.css` sets
|
||||
`background: #faf9f6; color: #1e2b2f` directly). There is no
|
||||
color-variable layer, so a new palette today means duplicating a whole
|
||||
theme file rather than swapping a few values.
|
||||
- `json`/`csv` viewer styling is worse for this: it's inlined into each
|
||||
artifact's stored HTML at create time (`wrap_json_viewer`/
|
||||
`wrap_csv_viewer`), so it can't be restyled after the fact at all without
|
||||
re-rendering.
|
||||
|
||||
## Two separable pieces
|
||||
|
||||
**1. Structure/skin separation (prerequisite).** Refactor the document
|
||||
themes so structural rules (layout, spacing, element selectors, code
|
||||
highlighting) are defined once, and *color* lives in CSS custom properties.
|
||||
A "palette" then becomes a small set of variable values, not a duplicated
|
||||
stylesheet. This is the same pattern the app chrome already uses
|
||||
(`daybook.css` `:root` + `[data-theme="dark"]`); the artifact themes just
|
||||
never adopted it. Without this, "customizable colors" means maintaining N
|
||||
near-identical full CSS files.
|
||||
|
||||
Note: for `json`/`csv` to be re-skinnable, their viewer CSS needs to move
|
||||
from inline-baked to a linked stylesheet (or the palette needs to be linked
|
||||
separately), otherwise only newly-created ones can change.
|
||||
|
||||
**2. Switching mechanism.** Once palettes are swappable, decide *who* picks
|
||||
and *when*:
|
||||
|
||||
- **Viewer-side switch** (like the dark-mode toggle): the person browsing
|
||||
chooses a palette, applied at render/serve time; a personal preference
|
||||
persisted per user. Doesn't change the stored artifact.
|
||||
- **Per-artifact, editable**: make `theme`/palette a `PATCH`-editable field
|
||||
so an artifact's look can be changed after posting.
|
||||
- **Per-kind or global default**: a Settings option for "default palette for
|
||||
my markdown artifacts," etc.
|
||||
|
||||
These aren't mutually exclusive; a viewer-side personal default is probably
|
||||
the most flexible and matches the "don't force one theme on everyone" framing.
|
||||
|
||||
## Open questions
|
||||
|
||||
- **Preset palettes vs. user-authored CSS.** "Customize the CSS" could mean
|
||||
(a) pick from a set of provided palettes, (b) pick colors via a UI that
|
||||
generates a palette, or (c) let users paste raw CSS. (c) is the most
|
||||
flexible but has a real downside: user CSS is an injection surface (less
|
||||
severe than JS — see issue #014 — but still, e.g. CSS can load external
|
||||
resources / exfiltrate via background-image URLs). A curated-palette or
|
||||
color-picker approach (a/b) avoids that; raw-CSS would need the same
|
||||
"trusted content only" caveat as `html_full`. Recommend starting with
|
||||
presets + maybe a color-picker, not raw CSS.
|
||||
- **Interaction with app light/dark mode.** Artifacts currently always
|
||||
render light regardless of the app's dark mode. Should palettes include
|
||||
dark artifact variants, and should they follow the app theme or be
|
||||
independent?
|
||||
- **Scope: global vs per-user.** `TagColor` is already global/shared across
|
||||
users by design; would palettes be per-user preferences instead? (Likely
|
||||
yes — a viewing preference, not shared state.)
|
||||
- **`html_full`** stays out of this entirely (verbatim, poster owns styling).
|
||||
- **`deck`** is the concrete trigger: it's intentionally dark, and the
|
||||
request to make backgrounds consistent stalled on it precisely because
|
||||
it can't just take the off-white without reworking its text colors —
|
||||
a palette system with proper light/dark deck variants is the real fix.
|
||||
|
||||
## Suggested phasing
|
||||
|
||||
1. Refactor `base`/`report`/`tasks`/`deck` (and the json/csv viewers) to
|
||||
drive all colors from CSS variables — no behavior change, just makes
|
||||
everything else possible.
|
||||
2. Ship 2–3 curated palettes per document family.
|
||||
3. Add a viewer-side palette switch + persisted per-user preference
|
||||
(mirrors the dark-mode toggle plumbing).
|
||||
4. Later, optionally: per-artifact editable palette, or a color-picker for
|
||||
custom palettes.
|
||||
|
||||
## References
|
||||
|
||||
- `planning/2026-09-02-theme_variants_and_user_palettes.md` — prior design
|
||||
conversation on this exact topic.
|
||||
- `planning/framework_artifact_rendering.md` — rendering/theming framework
|
||||
notes (incl. the "vendor locally, CSS-only" stance and future renderers).
|
||||
|
||||
## Resolution
|
||||
|
||||
_(pending)_
|
||||
Loading…
Add table
Add a link
Reference in a new issue