[DX-1518] feat: site-wide dark mode + theme toggle#3466
Draft
jamiehenson wants to merge 10 commits into
Draft
Conversation
Add shared theme constants and an inline pre-paint script, injected into <head> by gatsby-ssr, that reads the persisted choice (validated against the known themes, or the system preference) and sets ui-theme-light/ui-theme-dark on <html> before first paint. On the static build this avoids a flash of the wrong theme before React hydrates. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add ThemeProvider/useTheme exposing the user's choice (light/dark/system), the resolved light|dark, and a setter that persists to localStorage and reflects the choice as ui-theme-* on <html>. Follows the system preference live when set to 'system'. resolvedTheme is exposed for JS-driven consumers that can't use CSS dark: variants (e.g. the Sandpack editor). The persisted read is wrapped in try/catch and normalised to a known theme, so blocked storage (privacy modes, partitioned iframes) or a corrupt value falls back to the default instead of crashing the root provider or applying an unknown class. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the root element in ThemeProvider in both gatsby-browser and gatsby-ssr so useTheme is available across the whole app. Add a ThemeSwitcher dropdown (Light/Dark/System with the active option checked) to the docs header, on both the desktop actions cluster and the mobile bar. The trigger renders a sun and a moon toggled with CSS dark: variants - the theme class is on <html> before paint, so no client-only state and no hydration mismatch. The header wordmark also swaps to a white variant (ably-logo-dark.svg) in dark mode via the same CSS toggle. Stub the theme context in the Header test so its render path stays provider-free. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The primary Admonition component already carries dark variants; the legacy Aside (used for new/updated/experimental/public-preview badges) still had hardcoded light-only colours. Tokenise its container background/border and add a ui-theme-dark surface override, tokenise the versioning text colour so it reads on both themes, and give the note/important/further-reading labels a dark text variant. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Sandpack examples editor was hardcoded to light (githubLight + the Chrome light variant), leaving the existing dark sandpackTheme unused. Read resolvedTheme from the theme context and pick the dark or light Sandpack theme and Chrome variant accordingly. Sandpack takes the theme as JS values rather than CSS dark: variants, so gate on mount - render light (matching the server) until hydrated - to avoid a hydration mismatch for dark-mode users. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add dark variants to the last components that assumed a light background: the demo API-key tooltip and the examples grid cards (surfaces, borders, title/description text, and the search-term highlight). Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
html/body had no background-color, so in dark mode the browser's default white showed through behind themed sections. Set an explicit body background (neutral-000 light, neutral-1300 dark) and a light default text colour. Flip the vendored ui-text-* typography classes for dark mode: headings (title/h1-h5/quote) and body copy (p1-p4) hardcoded dark colours with only labels overridden, so any heading or paragraph without an explicit dark: variant rendered dark-on-dark. The overrides are wrapped in :where() so they add no specificity - they still override the hardcoded base but defer to any explicit dark:text-* a component sets (text.css is imported after Tailwind's utilities, so without this they would wrongly win, e.g. washing out a tooltip on a light surface). Also correct an inline-code rule that targeted the wrong class (.dark vs .ui-theme-dark). Keep tooltips a dark chip in both themes (dark surface, light text) rather than inverting to a light chip in dark mode. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Several decorative background grids and gradients assume a light page and read as stray light panels on the dark canvas. In dark mode: hide the homepage hero pattern, drop the Examples card's light gradient (so it matches the transparent Changelog card) and hide its background grid, and hide the examples listing page's desktop/mobile grid patterns. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Redoc used a hardcoded light theme, so on the dark page canvas its sidebar and body text rendered dark-on-dark. Wire the Loader to the theme context: pass a dark Redoc theme (light text, dark sidebar/right-panel/code blocks and borders; literal hex since Redoc ignores CSS variables) when resolvedTheme is dark, and re-init Redoc into a cleared container when the theme changes. Make the re-init safe: the CDN script load is memoised so toggling while it downloads can't attach a second onload and double-init, and each init's menu-navigation listeners/observer are captured and torn down before the next init and on unmount rather than accumulating (overrideMenuItemNavigation's disposer is now held in a ref, and its cleanup also disconnects the observer). Redoc's section sub-headers (h5) use an internal muted dark token the theme object can't reach; and since redoc.module.css is a CSS module its .redoc-content selectors were hashed and never matched Redoc's DOM, so use :global for a dark-mode h5 colour rule that gives them the same light treatment. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the header theme dropdown (ThemeSwitcher) with a three-cell segmented toggle (System / Dark / Light) in the footer, right-aligned under the status unit. The toggle is a radiogroup of icon cells that highlights the active choice and calls setTheme; it defers the active-cell highlight until mount to avoid a hydration mismatch. Remove ThemeSwitcher from the header (desktop and mobile) and drop the now-unused theme-context mock from the Header test. Refs DX-1518 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
897fb79 to
ee50ba6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Site-wide dark mode + theme toggle
Adds a site-wide dark mode to the docs, with a light / dark / system toggle. Jira: DX-1518.
The
@ably/uicut-off (DX-1128) is what made this tractable — the localised components already carried theirdark:variants and the vendored highlight.js theme already had.ui-theme-darkrules; they were just dormant because nothing ever set the class. This PR activates that and closes the gaps.How it works
gatsby-ssrsetsui-theme-light/ui-theme-darkon<html>fromlocalStorage(or the OS preference) before first paint, so the static build never flashes the wrong theme.ThemeProvider/useTheme(light / dark / system), persisted tolocalStorage, reflected as theui-theme-*class which drives Tailwind'sdark:variants (darkMode: ['selector', '.ui-theme-dark']). Storage reads are guarded and values normalised, so blocked storage or a corrupt value falls back to the default instead of crashing the root provider.ui-text-*classes hardcoded dark colours (only labels had a dark override); added dark overrides for headings/body + fixed an inline-code rule that targeted.darkinstead of.ui-theme-dark.bodyhad no background, so dark mode showed white behind themed sections; set an explicit body background per theme.Verified in-browser (dark + a light/toggle pass)
Homepage, MDX doc pages (prose, tables, admonitions, code blocks, inline code), the Redoc API reference, the examples listing, and header/footer chrome. The Redoc re-init leak fix was measured directly (scroll-listener add/remove balanced across a toggle; single Redoc render).
yarn lintclean; 190 unit tests pass.Out of scope (follow-up)
Content imagery (Phase 4) — inline MDX diagrams/screenshots with baked-in light backgrounds (e.g. the platform architecture diagram, example preview shots) need dark asset variants; deferred to a separate effort. Default theme is deliberately
light(notsystem) until that lands.Not yet eyeballed: the live Sandpack editor (gated behind a logged-in API key), a mobile/responsive pass, and every component variant (nested API tables,
<Tiles>, the code-tab switcher) — the systemic fixes should cover them but they warrant a look on the review app.Testing
Add the
review-applabel for a deployment, then use the footer toggle (System / Dark / Light) and walk the page types above./cc @team-deved for review.
🤖 Generated with Claude Code