Relaunch Phase 1: Hero mit Deutschland-Karte, Kundenportal-Bühne, Leistungen, Preise, Unterseiten im neuen Layout
- Hero: wechselnde Überschrift (ein Durchlauf, Pause-Knopf), Karte zeichnet sich, roter Punkt auf Falkenstein - Kundenportal: Bühne mit Browserfenster und Handy-Rahmen (Desktop), Wisch-Reihe (Handy), Schrittzeile statt „So arbeiten wir“ - Leistungen als nummerierte Zeilen, Preise aus src/data/abos.ts - Unterseiten ohne eigenen Kopfbereich, Wortlaut der Rechtstexte unverändert - Tests für Hero, Kundenportal, Leistungen/Preise und Layout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
69d006334f
commit
1c8cfa5c1c
54 files changed
+4761
-1166
No files matched your search
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Relaunch: verkleinert die Rohexporte der Kundenportal-Screenshots für die Website.
|
||||
|
||||
docs/relaunch/assets/portal/*.webp (Rohdateien, doppelte Auflösung)
|
||||
-> public/relaunch/portal/<name>-<breite>.webp
|
||||
|
||||
Aufruf (aus dem Projektverzeichnis): python3 scripts/relaunch-bilder.py
|
||||
|
||||
Nur die Bilder, die der Abschnitt "Kundenportal" (Spezifikation 7.2) wirklich zeigt, landen in public/.
|
||||
Format und Budgets laut Spezifikation 9.5:
|
||||
- WebP, Qualität etwa 80, Desktop-Bilder in 800 / 1200 / 1600 px Breite, Handy-Bilder in 390 / 780 px
|
||||
- ein einzelnes Desktop-Bild höchstens 120 KB, ein einzelnes Handy-Bild höchstens 60 KB
|
||||
(der lange Screenshot hat ein eigenes, größeres Budget, weil er mehr als dreimal so hoch ist)
|
||||
- wird ein Budget überschritten, sinkt die Qualität pro Datei schrittweise (nicht unter MIN_QUALITAET)
|
||||
Braucht Python 3 und Pillow mit WebP-Unterstützung.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
|
||||
WURZEL = Path(__file__).resolve().parent.parent
|
||||
QUELLE = WURZEL / "docs" / "relaunch" / "assets" / "portal"
|
||||
ZIEL = WURZEL / "public" / "relaunch" / "portal"
|
||||
|
||||
QUALITAET = 80
|
||||
MIN_QUALITAET = 46
|
||||
SCHRITT = 4
|
||||
|
||||
KB = 1024
|
||||
BUDGET_DESKTOP = 120 * KB
|
||||
BUDGET_HANDY = 60 * KB
|
||||
# Der lange Screenshot ist gut dreimal so hoch wie ein Handy-Bild (5428 statt 1688 px). Sein Budget
|
||||
# wächst mit der Höhe (je Bildschirmhöhe weiterhin unter 60 KB), sonst wäre der Text nur noch Matsch.
|
||||
BUDGET_LANG = {390: 80 * KB, 780: 150 * KB}
|
||||
|
||||
# Dateiname (ohne .webp) -> (Art, Zielbreiten)
|
||||
BILDER = {
|
||||
# Desktop-Fenster (Roh 2880 x 1800)
|
||||
"desktop-1-projekte": ("desktop", (800, 1200, 1600)),
|
||||
"desktop-2-fortschritt": ("desktop", (800, 1200, 1600)),
|
||||
"desktop-3b-chat-foto": ("desktop", (800, 1200, 1600)),
|
||||
"desktop-4-rechnungen": ("desktop", (800, 1200, 1600)),
|
||||
"desktop-7-news-pinnwand": ("desktop", (800, 1200, 1600)),
|
||||
# Handy (Roh 780 x 1688, das lange Bild 780 x 5428)
|
||||
"phone-1-projekte": ("handy", (390, 780)),
|
||||
"phone-3-projektdetails": ("handy", (390, 780)),
|
||||
"phone-4b-chat-foto": ("handy", (390, 780)),
|
||||
"phone-5-rechnungen": ("handy", (390, 780)),
|
||||
"phone-8-news-vorschau": ("handy", (390, 780)),
|
||||
# langer Screenshot: behält sein hohes Seitenverhältnis (eigenes Budget, siehe BUDGET_LANG)
|
||||
"phone-2-projekte-lang": ("handy", (390, 780)),
|
||||
}
|
||||
|
||||
|
||||
def speichern(bild: Image.Image, ziel: Path, budget: int) -> tuple[int, int]:
|
||||
"""Speichert als WebP; senkt die Qualität, bis das Budget passt. Gibt (Bytes, Qualität) zurück."""
|
||||
qualitaet = QUALITAET
|
||||
while True:
|
||||
bild.save(ziel, "WEBP", quality=qualitaet, method=6)
|
||||
groesse = ziel.stat().st_size
|
||||
if groesse <= budget or qualitaet - SCHRITT < MIN_QUALITAET:
|
||||
return groesse, qualitaet
|
||||
qualitaet -= SCHRITT
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ZIEL.mkdir(parents=True, exist_ok=True)
|
||||
# alte Ausgaben entfernen, damit nichts Verwaistes liegen bleibt
|
||||
for alt in ZIEL.glob("*.webp"):
|
||||
alt.unlink()
|
||||
|
||||
fehler = 0
|
||||
summe = 0
|
||||
print(f"{'Datei':44} {'Pixel':>11} {'KB':>7} {'Q':>3} Budget")
|
||||
for name, (art, breiten) in BILDER.items():
|
||||
quelle = QUELLE / f"{name}.webp"
|
||||
if not quelle.exists():
|
||||
print(f"FEHLT: {quelle}", file=sys.stderr)
|
||||
fehler += 1
|
||||
continue
|
||||
roh = Image.open(quelle).convert("RGB")
|
||||
for breite in breiten:
|
||||
if name.endswith("-lang"):
|
||||
budget = BUDGET_LANG[breite]
|
||||
else:
|
||||
budget = BUDGET_DESKTOP if art == "desktop" else BUDGET_HANDY
|
||||
if breite > roh.width:
|
||||
print(f"übersprungen: {name} {breite} (Rohbild nur {roh.width} px breit)")
|
||||
continue
|
||||
hoehe = round(roh.height * breite / roh.width)
|
||||
klein = roh if breite == roh.width else roh.resize((breite, hoehe), Image.LANCZOS)
|
||||
datei = ZIEL / f"{name}-{breite}.webp"
|
||||
groesse, qualitaet = speichern(klein, datei, budget)
|
||||
summe += groesse
|
||||
ok = "ok" if groesse <= budget else f"ÜBER {budget // KB} KB"
|
||||
print(f"{datei.name:44} {breite:>5}x{hoehe:<5} {groesse / KB:7.1f} {qualitaet:>3} {ok}")
|
||||
print(f"Summe aller Dateien: {summe / KB:.0f} KB")
|
||||
return 1 if fehler else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user