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