mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-10-26 00:28:42 +00:00
Currently dark mode is only available to users that have opted-in by selecting a cookie. Users that have set their device preference to dark still see light mode until they've specifically clicked the button to set the cookie. Without a css_dark_mode cookie the page now renders data-darkmode="auto", and the dark styles apply under @media (prefers-color-scheme: dark), so a device in dark mode gets the dark theme without opting in from the menu. Pure CSS - no flash of the wrong theme and no JS needed. The cookie set by the menu toggle still wins either way, so light-mode devices can choose dark and vice versa. In "auto" the toggle reads the current effective theme via matchMedia so the first click always flips it. A dark-mode SCSS mixin emits each dark block for both html[data-darkmode="true"] and the auto+media-query case; the processor badge and tag colour rules generated outside SCSS get the same pair.
41 lines
1.8 KiB
Python
41 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import re
|
|
from urllib.parse import urlsplit
|
|
|
|
from flask import url_for
|
|
|
|
|
|
def get_html_darkmode_state(res):
|
|
# Read it from the <html> tag - the inline badge/tag CSS also contains html[data-darkmode="..."]
|
|
m = re.search(rb'<html[^>]*\sdata-darkmode="([^"]*)"', res.data)
|
|
return m.group(1).decode() if m else None
|
|
|
|
|
|
def test_darkmode_follows_device_unless_cookie_set(client, live_server, measure_memory_usage, datastore_path):
|
|
# The test client defaults cookies to domain="localhost", which isn't sent to the
|
|
# live_server's SERVER_NAME (localhost.localdomain), so set them for the real host
|
|
cookie_domain = urlsplit(url_for("watchlist.index", _external=True)).hostname
|
|
|
|
# No cookie - "auto", the CSS follows prefers-color-scheme
|
|
client.delete_cookie('css_dark_mode', domain=cookie_domain)
|
|
res = client.get(url_for("watchlist.index"), follow_redirects=True)
|
|
assert get_html_darkmode_state(res) == 'auto'
|
|
|
|
# The cookie from the menu toggle always wins over the device setting
|
|
client.set_cookie('css_dark_mode', 'true', domain=cookie_domain)
|
|
res = client.get(url_for("watchlist.index"), follow_redirects=True)
|
|
assert get_html_darkmode_state(res) == 'true'
|
|
|
|
client.set_cookie('css_dark_mode', 'false', domain=cookie_domain)
|
|
res = client.get(url_for("watchlist.index"), follow_redirects=True)
|
|
assert get_html_darkmode_state(res) == 'false'
|
|
|
|
# Garbage cookie value falls back to the device setting instead of erroring
|
|
client.set_cookie('css_dark_mode', 'banana', domain=cookie_domain)
|
|
res = client.get(url_for("watchlist.index"), follow_redirects=True)
|
|
assert res.status_code == 200
|
|
assert get_html_darkmode_state(res) == 'auto'
|
|
|
|
client.delete_cookie('css_dark_mode', domain=cookie_domain)
|