Rollout des Toggle-Patterns auf alle 57 statischen Sites (dasbes.de + dumusst.com sind dynamic, kein index.html). 1. **Bulk-Wiring (53 Sites)** via tools/patch-theme.py: - Anti-FOUC inline IIFE im <head> (vor erstem Paint) - <link rel="stylesheet" href="/shared/css/theme.css"> - <script src="/shared/theme.js"> + toggles.js (i18n.js bleibt, hängt sich ans neue Widget) 2. **Per-Site Light-Overrides (14 Sites)** via tools/patch-light-overrides.py: - 6034, allainallain, commanderkin, hallofraumaier, heygoldi, keinefreun, lexsiebels, machesdocheinfach, matthiasbreier, orakil, osterai, patentonkel, traihard, wartebitte - Pro Site nur die failing accent-vars darkened (--green-dim, --text-faint, --warm-dim, --gold-dim, etc.) - AA 4.5:1+ auf white bg gesichert; Brand-Akzent erhalten 3. **data-theme-lock="dark" (4 Sites)** auf <html>: - kilibri, killusion, killionaer, killuminati - Aesthetisch dark-only — toggles.js blendet Theme-Button automatisch aus, Lang-Button bleibt 4. **Footer-Toggle Removal (52 Sites)** via tools/remove-footer-toggle.py: - Bestehende footer [data-i18n-toggle] Buttons entfernt — top-right widget übernimmt - Disclaimer-Information in tooltip des neuen Buttons + ai-disclosure.js footer QA: - ./build.sh: 59/59 sites built clean - contrast-audit.py --both: 0/59 dark fail, 0/59 light fail - anti-ai-lint: 0/57 sites flagged Tools committed (idempotent, für Wiederverwendung): - tools/patch-theme.py (--all wired alle Sites) - tools/patch-light-overrides.py (per-site OVERRIDES dict) - tools/remove-footer-toggle.py (4 Patterns für versch. Footer-Strukturen)
114 lines
2.9 KiB
Python
114 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Insert per-site [data-theme="light"] override block after :root.
|
|
|
|
Each entry maps site -> dict of var -> light-value. Vars not listed
|
|
fall through to shared/css/theme.css defaults.
|
|
"""
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
SITES_DIR = ROOT / "sites"
|
|
|
|
OVERRIDES = {
|
|
"6034.de": {
|
|
"--green-dim": "#15803d", # AA 4.7:1 on white
|
|
},
|
|
"allainallain.de": {
|
|
"--text-faint": "#5a608a",
|
|
},
|
|
"commanderkin.de": {
|
|
"--green-dim": "#166e16",
|
|
},
|
|
"hallofraumaier.de": {
|
|
"--text-light": "#6e6452",
|
|
},
|
|
"heygoldi.de": {
|
|
"--text-gentle": "#6e6452",
|
|
},
|
|
"keinefreun.de": {
|
|
"--text-dimmer": "#5a5662",
|
|
"--accent-dim": "#5d28b8",
|
|
},
|
|
"lexsiebels.de": {
|
|
"--text-bright": "#1a1a1a", # high-contrast text inverts on light bg
|
|
},
|
|
"machesdocheinfach.de": {
|
|
"--text-faint": "#6e6452",
|
|
},
|
|
"matthiasbreier.de": {
|
|
"--text-light": "#475569",
|
|
},
|
|
"orakil.de": {
|
|
"--gold-dim": "#6c5b1a",
|
|
},
|
|
"osterai.de": {
|
|
"--text-faint": "#6e6452",
|
|
},
|
|
"patentonkel.de": {
|
|
"--warm-dim": "#6e5418",
|
|
},
|
|
"traihard.de": {
|
|
"--muted": "#555568",
|
|
},
|
|
"wartebitte.de": {
|
|
"--text-faint": "#6e685e",
|
|
},
|
|
}
|
|
|
|
|
|
def find_root_block(html):
|
|
"""Find the first `:root {...}` block. Returns (start, end) of `}` char or None."""
|
|
m = re.search(r":root\s*\{", html)
|
|
if not m:
|
|
return None
|
|
depth = 1
|
|
i = m.end()
|
|
while i < len(html) and depth > 0:
|
|
if html[i] == "{":
|
|
depth += 1
|
|
elif html[i] == "}":
|
|
depth -= 1
|
|
i += 1
|
|
if depth != 0:
|
|
return None
|
|
return i # position right after the closing brace
|
|
|
|
|
|
def detect_root_indent(html, root_end):
|
|
"""Look at line containing :root to detect indent."""
|
|
# find start of line with :root
|
|
m = re.search(r"^([ \t]*):root\s*\{", html, re.MULTILINE)
|
|
if m:
|
|
return m.group(1)
|
|
return " "
|
|
|
|
|
|
def patch_site(site, vars_map):
|
|
path = SITES_DIR / site / "index.html"
|
|
if not path.exists():
|
|
return f"missing index.html"
|
|
html = path.read_text()
|
|
if '[data-theme="light"]' in html:
|
|
return f"already has [data-theme=\"light\"] block — skipped"
|
|
end = find_root_block(html)
|
|
if end is None:
|
|
return f"no :root block found"
|
|
indent = detect_root_indent(html, end)
|
|
inner = "\n".join(f"{indent} {k}: {v};" for k, v in vars_map.items())
|
|
block = f"\n\n{indent}[data-theme=\"light\"] {{\n{inner}\n{indent}}}"
|
|
new_html = html[:end] + block + html[end:]
|
|
path.write_text(new_html)
|
|
return f"patched ({len(vars_map)} vars)"
|
|
|
|
|
|
def main():
|
|
for site, vars_map in OVERRIDES.items():
|
|
result = patch_site(site, vars_map)
|
|
print(f" {site}: {result}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|