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)
112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Remove the redundant footer [data-i18n-toggle] block.
|
|
|
|
After Issue #13 the top-right widget owns toggling. The legacy footer button
|
|
+ "Maschinell übersetzt" disclaimer line are now redundant — top-right button
|
|
has the same disclaimer in its title tooltip, and ai-disclosure.js still
|
|
adds the AI footnote.
|
|
|
|
Two patterns handled:
|
|
Pattern A: <div style="text-align:center;margin-top:16px..."> ... </div>
|
|
Pattern B (knzlmgmt, schulfrai): <p class="footer" style="margin-top:12px;">...</p>
|
|
|
|
Idempotent — sites without the patterns are skipped.
|
|
"""
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
SITES_DIR = ROOT / "sites"
|
|
|
|
# Pattern A: a div wrapping the button + br + small disclaimer.
|
|
# Allow extra style segments after margin-top:16px (some sites add ;opacity:1 etc.)
|
|
PATTERN_A = re.compile(
|
|
r'\s*<div\s+style="text-align:center;margin-top:16px[^"]*">\s*'
|
|
r'<button\s+data-i18n-toggle[\s\S]*?</button>\s*'
|
|
r'<br>\s*<small[^>]*data-de="Maschinell übersetzt"[^>]*>[\s\S]*?</small>\s*'
|
|
r'</div>',
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
# Pattern B: <p class="footer" style="margin-top:12px;">...</p>
|
|
PATTERN_B = re.compile(
|
|
r'\s*<p\s+class="footer"\s+style="margin-top:12px;">'
|
|
r'<button\s+data-i18n-toggle[\s\S]*?'
|
|
r'</p>',
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
# Pattern C: bare button (optionally followed by <br><small>...</small>),
|
|
# not enclosed in our standard wrappers. Used by sites that placed the
|
|
# toggle inline in a footer paragraph (ichbinotto, kainco, keinefreun,
|
|
# omakise) or in a custom-classed div (orakil).
|
|
PATTERN_C = re.compile(
|
|
r'\s*<button\s+data-i18n-toggle[\s\S]*?</button>'
|
|
r'(?:\s*<br>\s*<small[^>]*data-de="Maschinell übersetzt"[^>]*>[\s\S]*?</small>)?',
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
# Pattern D: <div class="footer-toggle">...</div> (orakil only, but tolerant)
|
|
PATTERN_D = re.compile(
|
|
r'\s*<div\s+class="footer-toggle">\s*'
|
|
r'<button\s+data-i18n-toggle[\s\S]*?</button>\s*'
|
|
r'<br>\s*<small[^>]*data-de="Maschinell übersetzt"[^>]*>[\s\S]*?</small>\s*'
|
|
r'</div>',
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
|
|
def patch(html):
|
|
new = html
|
|
# Wrappers first (they contain a button); then bare-button fallback.
|
|
new, n_a = PATTERN_A.subn("", new)
|
|
new, n_b = PATTERN_B.subn("", new)
|
|
new, n_d = PATTERN_D.subn("", new)
|
|
new, n_c = PATTERN_C.subn("", new)
|
|
return new, n_a + n_b + n_c + n_d
|
|
|
|
|
|
def main():
|
|
sites = sorted(p for p in SITES_DIR.iterdir() if p.is_dir() and (p / "index.html").exists())
|
|
total_removed = 0
|
|
sites_changed = 0
|
|
sites_with_attr = 0
|
|
sites_residual = []
|
|
|
|
for site in sites:
|
|
path = site / "index.html"
|
|
before = path.read_text()
|
|
if "data-i18n-toggle" not in before:
|
|
continue
|
|
sites_with_attr += 1
|
|
|
|
# Count old buttons before removal (we expect exactly 1 footer button per site;
|
|
# the new top-right widget injects its own at runtime, not in source).
|
|
before_count = len(re.findall(r"data-i18n-toggle", before))
|
|
|
|
after, removed = patch(before)
|
|
after_count = len(re.findall(r"data-i18n-toggle", after))
|
|
|
|
if removed > 0:
|
|
path.write_text(after)
|
|
sites_changed += 1
|
|
total_removed += removed
|
|
print(f" [removed {removed}] {site.name} (data-i18n-toggle: {before_count} -> {after_count})")
|
|
if after_count > 0:
|
|
sites_residual.append((site.name, after_count))
|
|
else:
|
|
sites_residual.append((site.name, before_count))
|
|
print(f" [no-match] {site.name} (still has {before_count} data-i18n-toggle)")
|
|
|
|
print(f"\nSites changed: {sites_changed}/{sites_with_attr}")
|
|
print(f"Total wrappers removed: {total_removed}")
|
|
if sites_residual:
|
|
print(f"\nSites with residual data-i18n-toggle attribute (manual review):")
|
|
for name, n in sites_residual:
|
|
print(f" - {name}: {n}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|