From 4773c152bc5f299fa682575bb8d1efea7587c7bc Mon Sep 17 00:00:00 2001 From: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:21:34 +0800 Subject: [PATCH] feat(website): add a persistent light and dark theme switch --- scripts/test-website.py | 20 +- scripts/website.py | 2 +- website/AGENTS.md | 5 +- website/README.md | 30 +- website/locales/ar/messages.po | 3280 +++++++++-------- website/locales/de/messages.po | 3280 +++++++++-------- website/locales/es/messages.po | 3280 +++++++++-------- website/locales/fa/messages.po | 3280 +++++++++-------- website/locales/fr/messages.po | 3280 +++++++++-------- website/locales/id/messages.po | 3280 +++++++++-------- website/locales/it/messages.po | 3280 +++++++++-------- website/locales/ja/messages.po | 3280 +++++++++-------- website/locales/ko/messages.po | 3280 +++++++++-------- website/locales/messages.pot | 3170 ++++++++-------- website/locales/pl/messages.po | 3280 +++++++++-------- website/locales/pt-BR/messages.po | 3280 +++++++++-------- website/locales/ru/messages.po | 3280 +++++++++-------- website/locales/th/messages.po | 3280 +++++++++-------- website/locales/tr/messages.po | 3280 +++++++++-------- website/locales/uk/messages.po | 3280 +++++++++-------- website/locales/vi/messages.po | 3280 +++++++++-------- website/locales/zh-CN/messages.po | 3280 +++++++++-------- website/locales/zh-TW/messages.po | 3280 +++++++++-------- website/public/assets/dino-demo.js | 4 +- website/public/assets/styles.css | 205 +- website/public/assets/theme.js | 70 + website/public/blog/index.html | 24 +- .../blog/touhou-reconstruction/index.html | 24 +- website/public/examples/dino-lab/index.html | 24 +- website/public/faq/index.html | 24 +- website/public/first-investigation/index.html | 24 +- website/public/get-started/index.html | 24 +- website/public/guides/browser/index.html | 24 +- website/public/guides/index.html | 24 +- website/public/guides/javascript/index.html | 24 +- website/public/guides/native/index.html | 24 +- website/public/index.html | 24 +- website/public/showcase/aegis/index.html | 24 +- website/public/showcase/ctf/index.html | 24 +- website/public/showcase/dx-ball/index.html | 24 +- website/public/showcase/index.html | 24 +- website/public/showcase/notion/index.html | 24 +- website/public/showcase/th04/index.html | 24 +- website/style-guide.md | 18 +- website/templates/header.html.tmpl | 9 + website/templates/page.html | 12 +- website/templates/theme.html.tmpl | 3 + 47 files changed, 31691 insertions(+), 31305 deletions(-) create mode 100644 website/public/assets/theme.js create mode 100644 website/templates/theme.html.tmpl diff --git a/scripts/test-website.py b/scripts/test-website.py index fed68227a..5c1aef876 100644 --- a/scripts/test-website.py +++ b/scripts/test-website.py @@ -401,7 +401,7 @@ class WebsiteTranslationChecks(unittest.TestCase): server.shutdown() worker.join() - def test_every_reading_page_offers_light_and_dark_theme_colors(self): + def test_every_reading_page_loads_theme_before_styles(self): site = ROOT / "website/_site" english_pages = reading_pages(ROOT / "website/public") self.assertTrue(english_pages) @@ -412,10 +412,20 @@ class WebsiteTranslationChecks(unittest.TestCase): for path in {original, site / relative if code == "en" else site / code / relative}: with self.subTest(language=code, page=str(path.relative_to(ROOT))): doc = Document(path.read_text()) - media = sorted(node.attrs.get("media") for node in doc.nodes if node.tag == "meta" and node.attrs.get("name") == "theme-color") - self.assertEqual(media, ["(prefers-color-scheme: dark)", "(prefers-color-scheme: light)"]) - styles = (ROOT / "website/public/assets/styles.css").read_text() - self.assertTrue("@media (prefers-color-scheme: dark)" in styles, "styles.css has no dark color scheme block") + colors = [node for node in doc.nodes if node.tag == "meta" and node.attrs.get("name") == "theme-color"] + self.assertEqual(len(colors), 1) + self.assertEqual(colors[0].attrs.get("content"), "#ffffff") + self.assertNotIn("media", colors[0].attrs) + theme = [node for node in doc.nodes if node.tag == "script" and (node.attrs.get("src") or "").endswith("/assets/theme.js")] + self.assertEqual(len(theme), 1) + for deferred in ("defer", "async", "type"): + self.assertNotIn(deferred, theme[0].attrs) + stylesheet = next(node for node in doc.nodes if node.tag == "link" and node.attrs.get("rel") == "stylesheet") + self.assertLess(theme[0].start, stylesheet.start) + toggle = [node for node in doc.nodes if "data-theme-toggle" in node.attrs] + self.assertEqual(len(toggle), 1) + self.assertEqual(toggle[0].tag, "button") + self.assertIn("hidden", toggle[0].attrs) if __name__ == "__main__": diff --git a/scripts/website.py b/scripts/website.py index a3bd44333..1d6661fc1 100644 --- a/scripts/website.py +++ b/scripts/website.py @@ -119,7 +119,7 @@ def shared_blocks(root, path, source): templates = root / "website/templates" return { name: indent(Template((templates / f"{name}.html.tmpl").read_text(encoding="utf-8")).substitute(values), " ") - for name in ("sharing", "header", "footer") + for name in ("sharing", "theme", "header", "footer") } diff --git a/website/AGENTS.md b/website/AGENTS.md index 37c9c0f50..5448512d1 100644 --- a/website/AGENTS.md +++ b/website/AGENTS.md @@ -43,8 +43,9 @@ for asset notes and the source of case-study claims. from HTML automatically. Mark example applications `noindex` in the head and keep them crawlable. Maintain the SVG sharing source, not the generated PNG. - Check both local root and `/rea/` paths, mobile layouts, expanded details, - copying and downloads. Run `python3 scripts/website.py check`, using the Python - environment described in the README. It rejects drift rather than silently + copying and downloads. Check light and dark themes, including a manual choice + opposite to the system preference. Run `python3 scripts/website.py check`, + using the Python environment described in the README. It rejects drift rather than silently rewriting shared HTML. Use `website.py links` for an optional network audit; distinguish missing targets from access denials and unverified fragments. - Check setup and support statements against the current installation/provider diff --git a/website/README.md b/website/README.md index 5df87b875..b7a159570 100644 --- a/website/README.md +++ b/website/README.md @@ -47,14 +47,15 @@ Edit the page's HTML in `public/`. Keep the question, evidence and result easy t follow. The writing and design guidance in [style-guide.md](style-guide.md) applies to every page. -| Change | Edit | Then run | -| ------------------------------ | ---------------------------------------------------------------- | ----------------------------------------------- | -| Page text, examples or figures | The page's HTML outside the marked shared regions | `python3 scripts/website.py check` | -| Search title or description | The page's `