From 85f99ae6166e3a2e90518d2b19979a2cdcb7a235 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Sat, 3 Oct 2026 20:13:01 -0400 Subject: [PATCH] feat(web): add automatic light and dark theme switcher --- scripts/build-assets.mjs | 12 ++ tests/functional/test_asgi.py | 18 +++ tests/web/color_theme.test.mjs | 132 ++++++++++++++++++ web/css/api_docs.css | 4 + web/css/custom.css | 238 +++++++++++++++++++-------------- web/js/api_docs.js | 1 + web/js/color_theme.js | 68 ++++++++++ web/js/icons.js | 6 + web/templates/base.html | 14 +- web/templates/color_theme.html | 9 ++ 10 files changed, 397 insertions(+), 105 deletions(-) create mode 100644 tests/web/color_theme.test.mjs create mode 100644 web/css/api_docs.css create mode 100644 web/js/color_theme.js create mode 100644 web/templates/color_theme.html diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs index 4a39f234..9444f7c0 100644 --- a/scripts/build-assets.mjs +++ b/scripts/build-assets.mjs @@ -28,3 +28,15 @@ await build({ '.woff2': 'file', }, }); + +// A small classic script applies the theme synchronously in the document head. +await build({ + entryPoints: [resolve(webDir, 'js/color_theme.js')], + absWorkingDir: process.cwd(), + outdir, + bundle: true, + minify: true, + target: ['es2022'], + format: 'iife', + platform: 'browser', +}); diff --git a/tests/functional/test_asgi.py b/tests/functional/test_asgi.py index e7d443a7..2b3c7a60 100644 --- a/tests/functional/test_asgi.py +++ b/tests/functional/test_asgi.py @@ -273,6 +273,24 @@ def test_api_documentation_requires_session_and_uses_local_assets(browser): assert browser.get('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/api/openapi.json').status_code == 401 +def test_theme_switcher_is_shared_by_workspace_swagger_and_sign_in(browser): + for path in ('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/settings/', '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/api/docs'): + page = browser.get(path) + assert page.status_code == 200 + assert 'data-color-theme' in page.text + assert all(f'data-theme-icon="{mode}"' in page.text for mode in ('light', 'dark', 'auto')) + assert all(f'data-lucide="{icon}"' in page.text for icon in ('sun', 'moon', 'sun-moon')) + script = page.text.index('