fix(7606): sync theme-color meta with client-side dark-mode switch (#7690)

* fix(7606): sync theme-color meta with client-side dark-mode switch

PR #7636 emits <meta name="theme-color"> server-side from
settings.skinVariants. That covers operators who hard-code a dark
toolbar in settings.json, but not the runtime path: pad.ts auto-flips
the toolbar to super-dark when enableDarkMode is on, the browser
reports prefers-color-scheme: dark, and no localStorage white-mode
override is set, plus the user can flip it via #options-darkmode.
Both paths run skinVariants.updateSkinVariantsClasses(), which until
now never touched the meta — so dark-mode users kept the light
#ffffff baseline and saw a white address bar above a dark toolbar
(stffen on #7606 after 2.7.3).

Push the toolbar-color lookup into updateSkinVariantsClasses so the
meta tracks every class change: the auto-switch on init, the user
toggle, and the skinVariants builder. Mirrors the CSS-source-order
table from src/node/utils/SkinColors.ts (last matching *-toolbar
token wins). When no meta is present (non-colibris skin, server
omits it) the helper is a no-op.

Adds Playwright coverage for both paths under
colorScheme: 'light' (manual toggle) and 'dark' (auto-switch on
dark-OS clients — the case stffen reported).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(theme-color): action Qodo PR review

(1) Bug — duplicated toolbar→color table: extract the CSS-source-order
mapping and the default-color constant into src/static/js/skin_toolbar_colors,
re-imported by both src/node/utils/SkinColors.ts (server, EJS template
helper) and src/static/js/skin_variants.ts (client, runtime updates). Lives
under static/js so the browser bundle can resolve it; server-side imports
of static/js modules already exist (Changeset, AttributeMap, ImportHtml,
hooks). One source of truth means a future palette change can no longer
silently desync the server-rendered baseline meta from the client updates,
which was the exact regression that brought us here.

(2) Rule violation — 4-space continuation indentation in the new
Playwright spec: re-indent the themeColor helper and the multiline
test(...) call to the repo's 2-space rule (.editorconfig).

Existing backend coverage (configuredToolbarColor unit tests + the
specialpages server-render checks for both pad and timeslider) still
passes against the refactored helper, so it's regression-locked end to
end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
John McLear 2026-05-07 17:43:29 +08:00 committed by GitHub
parent fe9727b31e
commit ab0cff4d95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 99 additions and 24 deletions

View file

@ -1,34 +1,16 @@
'use strict';
// Toolbar background colors that the colibris skin variants resolve to.
// Mirrors --bg-color in src/static/skins/colibris/src/pad-variants.css. Only
// the colibris skin has a known mapping; for any other skin we cannot derive
// the toolbar color server-side and emit no theme-color meta.
//
// Order matters: when skinVariants contains multiple *-toolbar tokens the
// CSS cascade picks the rule defined last in pad-variants.css, so iterate in
// source order and let the last matching token win.
const TOOLBAR_COLORS_IN_CSS_ORDER: Array<[string, string]> = [
['super-light-toolbar', '#ffffff'],
['light-toolbar', '#f2f3f4'],
['super-dark-toolbar', '#485365'],
['dark-toolbar', '#576273'],
];
const COLIBRIS_DEFAULT_TOOLBAR_COLOR = '#ffffff';
import {toolbarColorForTokens} from '../../static/js/skin_toolbar_colors';
// The toolbar color the user actually sees on first paint, derived from the
// configured skin and skinVariants. Returns null when the skin is unknown so
// callers can omit the meta rather than emit a misleading value.
// configured skin and skinVariants. Only the colibris skin has a known
// mapping (see src/static/js/skin_toolbar_colors). For any other skin we
// cannot derive the toolbar color server-side and return null so callers can
// omit the meta rather than emit a misleading value.
export const configuredToolbarColor = (
skinName: string | undefined | null,
skinVariants: string | undefined | null,
): string | null => {
if (skinName !== 'colibris') return null;
const tokens = new Set((skinVariants || '').split(/\s+/).filter(Boolean));
let color: string | null = null;
for (const [variant, c] of TOOLBAR_COLORS_IN_CSS_ORDER) {
if (tokens.has(variant)) color = c;
}
return color || COLIBRIS_DEFAULT_TOOLBAR_COLOR;
return toolbarColorForTokens((skinVariants || '').split(/\s+/).filter(Boolean));
};