Skip to content

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

Merged
mhenrixon merged 1 commit into
mainfrom
issue-16-brand-href-dark-code-themes
Jul 3, 2026
Merged

feat(config): brand_href + dark/light code themes — the knobs API sites shim today#32
mhenrixon merged 1 commit into
mainfrom
issue-16-brand-href-dark-code-themes

Conversation

@mhenrixon

Copy link
Copy Markdown
Owner

Summary

Three config knobs replace the workarounds sites (zazu/app-4) shim by subclassing DocsUI::Shell today — the app-4 Shell subclass shrinks to nothing once these land.

Knob Default What it does
c.brand_href "/" The topbar brand link target. Shell#topbar reads it, so pointing the brand at /docs is one line — not a copy-pasted #topbar subclass (flagged fragile in app-4's own comments).
c.code_theme_dark nil A second Rouge theme for dark daisyUI themes. nil keeps the single-theme behavior byte-for-byte (backwards compatible). When set, DocsUI::Code also emits that theme's CSS scoped under [data-theme=X] .code-highlight for each shipped dark theme, so code blocks stay readable when the switcher flips dark.
c.dark_themes DEFAULT_DARK_THEMES (the built-in daisyUI dark names) Which theme names count as dark. Intersected with c.themes at render time (#dark_themes_shipped) so only shipped themes emit CSS. Overridable for custom dark themes (e.g. %w[zazu-dark]).

code_theme_dark_class mirrors code_theme_class (String / Class / nil).

Why CSS-only, no JS

The base (light) theme is emitted un-scoped; the dark theme is scoped under [data-theme=X]. daisyUI's [data-theme] selector is more specific than the un-scoped base rule, so the theme switcher restyles code blocks with no JavaScript and no flash. Rouge CSS is inlined per block (not part of the Tailwind build), so the theme-sync invariant is unaffected — a code_theme_dark doesn't need a CSS rebuild.

Test Coverage

  • configuration_specbrand_href default/override; code_theme_dark nil default + override; code_theme_dark_class String/Class/nil; dark_themes frozen default + override; dark_themes_shipped intersection + declaration order + empty case
  • shell_spec — brand link href defaults to "/" and follows config.brand_href
  • code_spec — dark CSS scoped per shipped dark theme; a non-shipped dark theme (synthwave when unshipped) excluded; base rule coexists with dark rules; byte-identical regression guard when code_theme_dark is nil

Dogfood + docs

  • docs/ initializer configured with Github (light) + Monokai (dark) so the light↔dark restyle is visible across all 9 themes
  • README documents the three knobs and notes the theme-sync invariant is unaffected
  • Install generator template ships the knobs as commented examples (so docs_kit:install and docs-kit new both surface them)

Verification

  • bundle exec rspec — 252 examples, 0 failures; Configuration 100% covered
  • bundle exec rubocop — no offenses
  • End-to-end render check: with themes: %w[light dark synthwave retro dracula] the emitted dark scopes are exactly dark, synthwave, dracula; light/retro excluded; base rule present

Out of scope

Closes #16

Three config knobs replace what sites (zazu/app-4) shim by subclassing
DocsUI::Shell today:

- c.brand_href (default "/") — the topbar brand link target. Shell#topbar
  reads it, so pointing the brand at /docs is one line, not a copy-pasted
  #topbar subclass.
- c.code_theme_dark (default nil) — a second Rouge theme for DARK daisyUI
  themes. nil keeps the single-theme behavior byte-for-byte (backwards
  compatible). When set, DocsUI::Code additionally emits that theme's CSS
  scoped under [data-theme=X] .code-highlight for each shipped dark theme,
  so code blocks stay readable when the switcher flips dark — CSS-only,
  no JS, no flash (daisyUI's [data-theme] selector out-specifies the base).
- c.dark_themes (default DEFAULT_DARK_THEMES, the built-in daisyUI dark
  names) — which themes count as dark. Intersected with c.themes at render
  time (#dark_themes_shipped) so only shipped themes emit CSS. Overridable
  for custom dark themes.

code_theme_dark_class mirrors code_theme_class (String/Class/nil).

## Test Coverage
- configuration_spec: brand_href default/override; code_theme_dark nil
  default + override; code_theme_dark_class String/Class/nil; dark_themes
  frozen default + override; dark_themes_shipped intersection + order + empty
- shell_spec: brand link href defaults to "/" and follows config
- code_spec: dark CSS scoped per shipped dark theme; non-shipped dark theme
  excluded; base rule coexists; byte-identical regression guard when nil

## Dogfood + docs
- docs/ initializer: Github (light) + Monokai (dark) so the restyle is
  visible across all 9 themes
- README: the three knobs documented; theme-sync invariant noted unaffected
  (Rouge CSS is inline, not Tailwind)
- install generator template: the knobs added as commented examples

## Verification
- [x] bundle exec rspec — 252 examples, 0 failures; Configuration 100% covered
- [x] bundle exec rubocop — no offenses

Closes #16
@mhenrixon mhenrixon self-assigned this Jul 3, 2026
@mhenrixon mhenrixon added the enhancement New feature or request label Jul 3, 2026
@mhenrixon mhenrixon merged commit 7d1076d into main Jul 3, 2026
3 checks passed
@mhenrixon mhenrixon deleted the issue-16-brand-href-dark-code-themes branch July 4, 2026 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant