Skip to content

feat(config): brand_href + dark/light code themes — the knobs API sites shim today #16

Description

@mhenrixon

Part of #8 (Phase 2).

Problem / Goal

zazu/app-4 subclasses DocsUI::Shell and copy-pastes the private #topbar verbatim to change ONE href (brand link //docs) — flagged fragile in their own comments — and injects hand-written dark-mode Rouge CSS because code_theme supports exactly one theme while the switcher offers light AND dark themes (code blocks are unreadable in one of them on every site that offers both).

Goal: both needs become config knobs; the app-4 Shell subclass shrinks to nothing (once the in-flight nonce fix on fix/csp-nonce-shell merges).

Context (read these first)

  • app/components/docs_ui/shell.rb:127-138#topbar, the hardcoded a(href: "/").
  • app/components/docs_ui/code.rb:71-77highlight_css emits ONE theme scoped to .code-highlight.
  • lib/docs_kit/configuration.rb — knob conventions (attr + default + resolver).
  • ~/Code/zazu/app-4/app/views/docs/shell.rb — the workaround being deleted.
  • daisyUI's built-in theme list — which names are dark (for the default).

Decision

  1. c.brand_href — default "/"; Shell#topbar reads it. One-line change, kills the copy-paste subclass.
  2. c.code_theme_dark — default nil (current single-theme behavior, fully backwards compatible). When set, DocsUI::Code#highlight_css additionally emits the dark theme's CSS scoped under [data-theme=X] .code-highlight for each theme name in c.dark_themes.
  3. c.dark_themes — default: the built-in daisyUI dark theme names (%w[dark synthwave halloween forest black luxury dracula business night coffee dim sunset abyss], frozen constant Configuration::DEFAULT_DARK_THEMES), intersected with c.themes at render time so only shipped themes generate CSS. Overridable for custom themes (app-4's zazu-dark).
  4. Resolver code_theme_dark_class mirrors the existing code_theme_class (String or Class).

Alternatives rejected: prefers-color-scheme media queries (theme is user-selected via data-theme, not OS-derived); auto-detecting darkness from daisyUI CSS variables at render time (Ruby can't see the compiled CSS — a static default list + override is honest); making code_theme accept a {light:, dark:} hash (breaks the existing String contract; a second knob is simpler and compatible).

Implementation steps (TDD)

  1. Specs first: spec/docs_kit/configuration_spec.rb — defaults (brand_href "/"; code_theme_dark nil; dark_themes list frozen + overridable); code_theme_dark_class resolves String/Class/nil. spec/docs_ui/shell_spec.rb — brand link href follows config. spec/docs_ui/code_spec.rb — with code_theme_dark set and themes: %w[light dark], output contains [data-theme=dark] .code-highlight rules and no rules for non-shipped dark themes; with it nil, output byte-identical to today (regression guard).
  2. Implement the three knobs + resolver in lib/docs_kit/configuration.rb; thread through shell.rb and code.rb.
  3. Configure the dogfood site (docs/config/initializers/docs_kit.rb) with a dark pair (e.g. Rouge::Themes::Github light / Monokai dark) so it's visibly dogfooded across its 9 themes.
  4. README: document all three knobs in the Configure section; note the theme-sync invariant is unaffected (Rouge CSS is inline, not Tailwind).

Verification gates

  • bundle exec rspec — green; Configuration 100% covered.
  • bundle exec rubocop — no offenses.
  • Dogfood: switch light↔dark themes on /docs/languages — code blocks restyle with the theme (JS-free CSS scoping, no flash).
  • Backwards compat: nil code_theme_dark output unchanged (spec-asserted).

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions