Skip to content

docs(ui): dark mode that follows the system setting, a theme toggle, and accessibility fixes (stacked on #511) - #520

Merged
lvca merged 6 commits into
ArcadeData:mainfrom
tae898:docs/dark-mode-a11y
Nov 5, 2026
Merged

lvca merged 6 commits into
ArcadeData:mainfrom
tae898:docs/dark-mode-a11y

Conversation

@tae898

@tae898 tae898 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Closes #519

Stacked on #511. This branch starts from the head of #511 (docs/toc-and-table-layout), so the diff on GitHub shows the commits of #511 as well until #511 merges; the change in this pull request is the last commit only (docs(ui): dark mode that follows the system setting ..., 5 files). Once #511 is merged this will be rebased onto main and the extra commits disappear.

Dark mode that follows the system setting, with a small toggle, plus the accessibility fixes from the issue. Only the UI files under docs/ui/supplemental/ change; no .adoc content.

What changed

  • css/arcadedb.css: every colour is now a token on :root (the existing variables, with their light values unchanged, plus surface, border, link, focus, and diagram-accent tokens). The dark values sit under @media (prefers-color-scheme: dark) guarded by :root:not([data-theme="light"]), and again under :root[data-theme="dark"]. The default UI's hard-coded colours in site.css (navbar, left navigation, "On this page", tables, admonitions, quotes, footer, search box, Pagefind) are overridden with the tokens in a new section at the end of the file, and the SVG diagrams, cards, and badges use the tokens instead of hex values. Code blocks were already dark; they get a slightly deeper background in the dark theme.
  • partials/head-styles.hbs: a four-line inline script sets data-theme on <html> from localStorage before the first paint (no white flash).
  • partials/header-content.hbs and js/theme-toggle.js (loaded from partials/footer-scripts.hbs): a button in the header cycles system, light, dark. "System" removes data-theme, so the CSS follows the system setting; light and dark set it and are saved under arcadedb-docs-theme in localStorage, every access wrapped in try/catch. The button's aria-label and title always name the current mode and the next one. The same script pauses the SMIL diagram animations when the reader asks for reduced motion.
  • Accessibility: a :focus-visible ring (2px, --color-focus, overrides the default UI's outline: none); tap targets of at least 24px on screens up to 768px wide and on touch devices (left navigation items, folding toggles, home icon, "On this page" links, breadcrumbs, pagination, header buttons); the phone header row now fits (the search field shrinks instead of pushing the menu button off the screen); prefers-reduced-motion turns off transitions, hover lift, and smooth scrolling. The search field border and the toggle border use a new stronger border token (3:1 or better) in both themes.
  • Text sizes need no change: the root is set in em and the UI text in rem already; px appears only as SVG user units inside the diagrams.
  • Two light-theme values changed on purpose: the code comment colour (#6B7280 to #8B95A5, 3.5:1 to 5.6:1 on the code background, same in both themes), and the search field border (now the strong border token, 4.0:1 instead of 1.2:1). Everything else in light is the same value as before; a few surfaces that were #fafafa in site.css (the unused "explore" panel) now use the nearest token, #FAFBFC.

Tokens

Token Light Dark
--color-bg #FFFFFF #0F1217
--color-bg-secondary #F5F6F7 #151920
--color-bg-accent #F0F4F8 #1C222C
--color-card #FFFFFF #1A1F27
--color-surface #FAFBFC #1D232C
--color-border #E2E8F0 #2C3440
--color-border-light #EDF2F7 #232A34
--color-border-strong #718096 #6B7788
--color-text-primary #1A1D23 #E8ECF2
--color-text-secondary #4A5568 #AEB8C6
--color-primary #0066CC #5AAEFF
--color-primary-dark #004C99 #8CC8FF
--color-on-primary #FFFFFF #0A1220
--color-link #1565C0 #6DB3FF
--color-link-hover #104D92 #9CCBFF
--color-focus #0066CC #8CC8FF
--color-danger #D32F2F #FF8A80
--color-code-bg #1A1D23 #0B0D11
--color-code-text #E4E8EE #E4E8EE
--color-code-comment #8B95A5 #8B95A5
--color-inline-code-bg #F0F4F8 #232A36
--color-inline-code-text #0066CC #8CC8FF
--color-scrollbar #C1C1C1 #4B5563
--hero-1 #F0F4F8 #1A212C
--hero-2 #E2EAF2 #18202B
--hero-3 #D9E5F0 #161D27
--c-blue #0066CC #5AAEFF
--c-green #10B981 #34D399
--c-green-text #047857 #34D399
--c-purple #7C3AED #B79CFF
--c-amber #F59E0B #FBBF24
--c-amber-text #B45309 #FBBF24
--c-red #EF4444 #F87171
--c-red-text #B91C1C #FCA5A5
--c-lime #65A30D #A3E635
--c-lime-bright #84CC16 #A3E635
--c-teal-text #0F766E #5EEAD4
--c-fuchsia-text #A21CAF #F0ABFC
--c-indigo-text #1D4ED8 #93B4FF
--c-pink-text #BE185D #F9A8D4
--c-gray-text #4B5563 #C0C7D2
--c-blue-soft #93C5FD #3B6EA8
--c-purple-soft #C4B5FD #6B58A8
--c-green-soft #6EE7B7 #2F8F6B
--c-amber-soft #FCD34D #9A7A1E
--c-red-soft #FCA5A5 #A04646
--c-blue-bg #F7FAFE #18212F
--c-amber-bg #FFFBEB #2A2415

Contrast, every text pair, both themes (WCAG relative luminance; computed by a script from the token values above; tints are composited over the page background). Minimum is 4.5:1 for text and 3:1 for large text, diagram labels, and the focus ring and control borders.

Pair Min Light Dark
text-primary on bg 4.5 16.88 15.83
text-secondary on bg 4.5 7.53 9.36
text-primary on bg-secondary 4.5 15.60 14.86
text-secondary on bg-secondary 4.5 6.96 8.79
text-primary on bg-accent 4.5 15.27 13.47
text-secondary on bg-accent 4.5 6.81 7.97
text-primary on card 4.5 16.88 13.95
text-secondary on card 4.5 7.53 8.25
text-primary on surface 4.5 16.29 13.33
text-secondary on surface 4.5 7.26 7.88
link on bg 4.5 5.75 8.53
primary on bg 4.5 5.57 7.98
link on bg-secondary 4.5 5.31 8.01
primary on bg-secondary 4.5 5.14 7.50
link on card 4.5 5.75 7.52
primary on card 4.5 5.57 7.04
link-hover on bg 4.5 8.40 11.08
primary-dark (hover) on bg 4.5 8.42 10.56
on-primary on primary (buttons) 4.5 5.57 7.97
on-primary on primary-dark (button hover) 4.5 8.42 10.55
inline-code-text on inline-code-bg 4.5 5.04 8.12
danger (unresolved link) on bg 4.5 4.98 8.22
code-text on code-bg 4.5 13.73 15.81
code-comment on code-bg 4.5 5.58 6.43
hljs keyword #7DD3FC on code-bg 4.5 10.13 11.66
hljs type #93C5FD on code-bg 4.5 9.36 10.78
hljs string #6EE7B7 on code-bg 4.5 11.08 12.76
hljs number #5EEAD4 on code-bg 4.5 11.41 13.15
hljs function #FCA5A5 on code-bg 4.5 8.89 10.25
hljs params #D1D5DB on code-bg 4.5 11.46 13.20
text-secondary on hero-1 4.5 6.81 8.07
text-primary on hero-1 4.5 15.27 13.65
text-secondary on hero-3 4.5 5.88 8.45
text-primary on hero-3 4.5 13.20 14.29
text-secondary on note admonition tint (5%) 4.5 6.98 9.07
text-secondary on tip admonition tint (5%) 4.5 7.20 8.84
text-secondary on warning admonition tint (5%) 4.5 7.23 8.77
text-secondary on caution admonition tint (5%) 4.5 7.07 9.04
diagram --c-blue text on card 3.0 5.57 7.04
diagram --c-blue text on surface 3.0 5.37 6.72
diagram --c-green text on card 3.0 2.54 (below) 8.61
diagram --c-green text on surface 3.0 2.45 (below) 8.22
diagram --c-green-text text on card 3.0 5.48 8.61
diagram --c-green-text text on surface 3.0 5.29 8.22
diagram --c-purple text on card 3.0 5.70 7.26
diagram --c-purple text on surface 3.0 5.50 6.93
diagram --c-amber text on card 3.0 2.15 (below) 9.91
diagram --c-amber text on surface 3.0 2.07 (below) 9.47
diagram --c-amber-text text on card 3.0 5.02 9.91
diagram --c-amber-text text on surface 3.0 4.85 9.47
diagram --c-red text on card 3.0 3.76 5.98
diagram --c-red text on surface 3.0 3.63 5.71
diagram --c-red-text text on card 3.0 6.47 8.72
diagram --c-red-text text on surface 3.0 6.24 8.33
diagram --c-lime text on card 3.0 3.09 10.97
diagram --c-lime text on surface 3.0 2.98 (below) 10.48
diagram --c-lime-bright text on card 3.0 1.98 (below) 10.97
diagram --c-lime-bright text on surface 3.0 1.91 (below) 10.48
badge graph on its tint over bg 4.5 4.83 7.45
badge math on its tint over bg 4.5 4.91 7.71
badge collections on its tint over bg 4.5 4.91 8.26
badge geo on its tint over bg 4.5 4.74 11.13
badge vector on its tint over bg 4.5 5.58 9.69
badge text on its tint over bg 4.5 4.58 9.29
badge date on its tint over bg 4.5 5.96 8.23
badge search on its tint over bg 4.5 5.35 9.44
badge misc on its tint over bg 4.5 6.51 9.83
focus ring on bg (3:1 UI) 3.0 5.57 10.56
focus ring on bg-secondary (3:1 UI) 3.0 5.14 9.92
border-strong on bg (3:1 UI, inputs/toggle) 3.0 4.02 4.13
border-strong on card (3:1 UI, inputs/toggle) 3.0 4.02 3.64
border-strong on bg-secondary (3:1 UI, inputs/toggle) 3.0 3.71 3.88

Every row passes in the dark theme. In the light theme every row passes except the diagram label colours that were already there and that this pull request leaves unchanged: green on card 2.54, green on surface 2.45, amber on card 2.15, amber on surface 2.07, lime on surface 2.98, and the bright lime on card and surface (1.98, 1.91), all below the 3:1 for large text. Making those pass in light means darkening the label colours, which is a visual change to the diagrams I did not want to make without your say.

Checked locally

  • Local build (npm ci, scripts/migrate.sh, npm run build, with Antora and Pagefind): succeeds; the built arcadedb.css contains the dark blocks, :focus-visible, and prefers-reduced-motion; every content page carries the pre-paint script, the toggle, and theme-toggle.js.
  • node --check on theme-toggle.js; braces in the CSS balance; every var(--...) used is defined.
  • python docs-validator.py passes. git diff --check is clean.
  • Headless Chrome screenshots in the dark theme at 1280px (home, a concept page with a code block, a multi-model page with an image) and at 390px (a table-heavy page): text, navigation, "On this page", admonition, search field, and cards read correctly; the header row fits at 390px. Measured at 390px with the menu open, links and buttons under 24px (links inside running text are exempt) went from 28 of 60 to 2 of 60 before the last tweak: the home icon, which this commit then enlarged (not re-measured), and the "Learn more" link in the cookie banner, which sits inside a sentence.

Not verified

  • Not tried in Safari or Firefox, with a screen reader, or on a real phone.
  • Three pages carry inline SVG with their own hard-coded fill colours in the .adoc source (about 29 #FFFFFF fills with dark text); they should keep their own light panels in dark mode, but I have not looked at each one.
  • Images with a transparent background get a white plate in the dark theme so they stay legible; screenshots with their own white background look the same as before.

If you want something different (a different default, the toggle somewhere else, the dark values adjusted, or this split into smaller pull requests), tell me and I will change it.

🤖 Generated with Claude Code

tae898 and others added 6 commits November 5, 2026 10:58
… fail Documentation Validation

- postgres.adoc: <<Column type mapping,...>> pointed at a section title; the
  section gets [[postgres-column-type-mapping]].
- settings.adoc: <<_a_statement_that_fails_halfway>> relied on the generated
  id; the section in transactions.adoc gets [[statement-fails-halfway]].
- sql/chapter.adoc: <<vector-neighbours,...>> -> the anchor is vector-neighbors.
- sql-functions.adoc: [[cchShortestPath]] and [[duanSSSP]] -> cch-shortest-path
  and duan-sssp (lowercase with hyphens), with the three references updated.

docs-validator.py passes locally (it failed on main with these five).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iteral monospace

The "Validate HTML output" step (html5validator on the single-page build,
target/generated-docs/index.html) failed with 21 errors, on main as well.
Asciidoctor applies strong, emphasis, mark and subscript before monospace,
so a pair of `*` (or `_`, `#`, `~`) in two different backtick spans pairs up
across them: `wal.group.*` and `commit.lock.*` rendered as
<code>wal.group.<strong></code> and <code>commit.lock.</strong></code>,
which is a stray "code" end tag, and `=~`/`!~` and `#` did the same with
sub and mark. `file://exports/<file-name>` was turned into a bare link with
an illegal href. The same markup renders the live pages wrong (bold running
over the text between two code spans), so the fix is in the sources.

Each affected span is now `+...+` literal monospace, the form sql-projections.adoc
already used. Only spans in the paragraphs that rendered wrongly changed.
Checked by rendering index.adoc with Asciidoctor 3 and scanning for
misnested code/strong/em/mark/sub tags (80 before, 0 after); the real
html5validator run is the CI step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main moved by about 130 commits; two new things would fail the same two
CI steps again. The anchor [[util-validatePredicate]] (utility.adoc) is
renamed util-validate-predicate, the lowercase-with-hyphens form the
validator requires (nothing refers to it). In redis.adoc, `*1\r\n:1\r\n`
and `'*'` paired as strong across the two code spans, giving a stray
"code" end tag in the single-page build; both are literal monospace now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e, at every width; link the Python docs

- Right TOC: the aside and the menu both drew the left rule and the links started 1px from it;
  now one rule on the menu and 0.75rem before the links.
- Tables: as wide as the content needs up to the content column, scrolling sideways beyond it
  (display:block, width:max-content, max-width:100%, overflow-x:auto) instead of splitting
  words; no automatic hyphenation; inline code no longer word-break:break-all (still
  overflow-wrap:anywhere for long setting names); 12px cell padding; at <= 768px a minimum
  column width so tables scroll instead of squeezing.
- python-embedded page: link the arcadedb-python component, now published on this site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eading width

Measured on a local build in frames of exact device widths: at 360 and 393 px the cells over 8 lines drop from 33 to 24 (which-package), 32 to 19 (http) and 62 to 47 (timeseries), and the longest cell from 27 to 15 and 69 to 31 lines; the table scrolls sideways instead (GitHub's pattern). Tablet and wider are unchanged by this rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d accessibility fixes

Every colour is a token on :root; the dark values sit under
prefers-color-scheme (guarded by :root:not([data-theme="light"])) and
under :root[data-theme="dark"]. A header button cycles system, light,
dark and remembers the choice (localStorage in try/catch); the saved
theme is applied by an inline script in head-styles.hbs before first
paint. site.css hard-coded colours are overridden with the tokens.

Accessibility: 24px minimum tap targets on small screens, a
:focus-visible ring, prefers-reduced-motion (CSS plus pausing the SMIL
diagram animations), and a phone header row that fits. Light values are
unchanged except the code comment colour (#6B7280 to #8B95A5, 3.3:1 to
5.6:1 on the code background).

Refs ArcadeData#519

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mergify

mergify Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again.

@lvca

lvca commented Nov 5, 2026

Copy link
Copy Markdown
Member

@claude review this

@lvca
lvca merged commit abf5d30 into ArcadeData:main Nov 5, 2026
4 checks passed
@lvca
lvca self-requested a review November 5, 2026 04:58
@tae898
tae898 deleted the docs/dark-mode-a11y branch November 5, 2026 04:59
@lvca

lvca commented Nov 5, 2026

Copy link
Copy Markdown
Member

Cool, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs site: dark mode that follows the system setting, and a few accessibility fixes

2 participants