chore: ignore build output site/, add favicon implementation plan

This commit is contained in:
rewa81 committed 2026-08-16 11:20:41 +02:00
1 parent 13d15a95a7
commit 5fd2337465
2 files changed
+244

No files matched your search

+2
View File
@@ -3,3 +3,5 @@
.cache
.vscode
.venv/
site/
@@ -0,0 +1,242 @@
# Favicon Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Das rwcloud.ch-Wiki bekommt ein eigenes minimalistisches Favicon (Monogramm „r“ auf Slate-Squircle) und es ist in `mkdocs.yml` aktiviert, sichtbar im Browser-Tab.
**Architecture:** Ein neues `favicon.svg` (Pfad-basiert, fonts-unabhängig) dient als Master. Da ImageMagick auf dem Build-Mac nicht installiert ist, werden die PNG-/ICO-Ableitungen per Pillow deterministisch gezeichnet (gleiche Geometrie, flache Ecken statt Béziers — bei Favicon-Grössen visuell identisch) und zu einer Multi-Size `.ico` gebündelt. `mkdocs.yml` verweist auf die neue `.ico`. Die bestehende `favicon.ico` wird ersetzt.
**Tech Stack:** SVG (Master), Python 3 + Pillow (als dev-Dependency via `uv add --dev pillow`), MkDocs Material
## Global Constraints
- Farben: Untergrund Material Slate 900 `#263238`, Buchstabe Material Green 500 `#4CAF50`
- „r" ist **Pfads**, kein `<text>`-Element (fonts-unabhängig, Rasterisierbar)
- SVG: 512×512 viewBox, keine Verläufe/Filter
- ICO enthält 16/32/48/64 px, alle mit Alpha-Kanal (RGBA)
- `mkdocs.yml` Zeile 24: `#favicon: assets/images/favicon.ico` wird aktiviert; `#logo:` bleibt kommentiert
- Keine neuen Python-Abhängigkeiten
---
### Task 1: Favicon-Assets (SVG, PNG, ICO)
**Files:**
- Create: `docs/assets/images/favicon.svg`
- Create: `docs/assets/images/icon-192.png`
- Create: `docs/assets/images/icon-512.png`
- Replace: `docs/assets/images/favicon.ico` (existiert bereits, wird überschrieben)
- Create: `scripts/render_favicon.py` (einmaliges Render-Script, bleibt als Nachvollziehbarkeit im Repo)
**Interfaces:**
- Produziert: die drei obigen Bilddateien + ein `favicon.ico` mit Größen 16/32/48/64
- Konsumiert von: Task 2 (`mkdocs.yml`) und dem Browser-Tab
- [ ] **Step 1: Pillow als dev-Dependency installieren**
Run: `uv add --dev pillow`
Expected: `Added pillow ...` und `uv.lock` + `pyproject.toml` aktualisiert. Wenn Pillow schon vorhanden ist (`uv pip show pillow` zeigt eine Version), überspringen.
- [ ] **Step 2: `favicon.svg` schreiben**
Erstelle `docs/assets/images/favicon.svg` mit exakt diesem Inhalt (blockiges „r" = Stemm + Arm + rechter Abfall, eine zusammenhängende Kontur):
```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect x="0" y="0" width="512" height="512" rx="112" fill="#263238"/>
<path fill="#4CAF50" d="M160 400 L160 150 L380 150 L380 280 L316 280 L316 215 L224 215 L224 400 Z"/>
</svg>
```
Erklärung: Squircle (rx=112 ≈ 22 % der Kanten), Slate 900 `#263238`; das „r" als ein Pfad: Stemm (160→224 breit, 150→400), Arm (224→380, 150→215 hoch), rechter Abfall (316→380, 150→280). Alle Strokes ≥ 64px in 512-Koordinaten = ≥ 2px in 16px.
- [ ] **Step 3: Render-Script `scripts/render_favicon.py` anlegen**
Erstelle `scripts/render_favicon.py` mit exakt diesem Inhalt (reines Pillow, deterministisch, gleiche Geometrie wie `favicon.svg`):
```python
"""Rendert docs/assets/images/favicon.ico (16/32/48/64) und icon-192/icon-512.png.
Geometrie entspricht 1:1 favicon.svg (512-Koordinatensystem, lineare Skalierung).
Voraussetzung: Pillow (im uv-Venv, dev-Dependency).
Aufruf: uv run python scripts/render_favicon.py
"""
from pathlib import Path
from PIL import Image, ImageDraw
ROOT = Path(__file__).resolve().parent.parent
IMG = ROOT / "docs" / "assets" / "images"
BG = (0x26, 0x32, 0x38, 255) # Material Slate 900
FG = (0x4C, 0xAF, 0x50, 255) # Material Green 500
def draw(size: int) -> Image.Image:
im = Image.new("RGBA", (size, size), (0, 0, 0, 0))
d = ImageDraw.Draw(im)
d.rounded_rectangle([0, 0, size - 1, size - 1], radius=size // 5, fill=BG)
def s(v512: int) -> int:
# 512er-Koordinate auf Zielgrösse skalieren (aufgerundet)
return round(v512 * size / 512)
d.polygon(
[
(s(160), s(400)),
(s(160), s(150)),
(s(380), s(150)),
(s(380), s(280)),
(s(316), s(280)),
(s(316), s(215)),
(s(224), s(215)),
(s(224), s(400)),
],
fill=FG,
)
return im
def main() -> None:
draw(512).save(IMG / "icon-512.png")
draw(192).save(IMG / "icon-192.png")
sizes = [16, 32, 48, 64]
images = [draw(sz) for sz in sizes]
images[-1].save(
IMG / "favicon.ico",
format="ICO",
sizes=[(im.width, im.height) for im in images],
append_images=images[:-1],
)
print("OK:", ", ".join(p.name for p in
[IMG / "favicon.ico", IMG / "icon-192.png", IMG / "icon-512.png"]))
if __name__ == "__main__":
main()
```
- [ ] **Step 4: Render-Script ausführen**
Run: `uv run python scripts/render_favicon.py`
Expected: `OK: favicon.ico, icon-192.png, icon-512.png`
- [ ] **Step 5: Verifikation – ICO & PNG haben die richtigen Dimensionen**
```bash
uv run python - <<'PY'
from PIL import Image
i = Image.open("docs/assets/images/favicon.ico")
print("ICO primary size:", i.size, "frames:", i.n_frames)
assert i.n_frames == 4, "ICO muss 4 Frames (16/32/48/64) haben"
for n in range(i.n_frames):
i.seek(n)
print(" frame", n, i.size)
for f, name in [(192, "icon-192.png"), (512, "icon-512.png")]:
im = Image.open(f"docs/assets/images/{name}")
assert im.size == (f, f), f"{name} wrong size {im.size}"
assert im.mode == "RGBA"
print(name, im.size, im.mode)
print("ALL OK")
PY
```
Expected: `ICO primary size: (64, 64) frames: 4`, Frames 16/32/48/64, `icon-192.png (192, 192) RGBA`, `icon-512.png (512, 512) RGBA`, `ALL OK`.
- [ ] **Step 6: Visuelle Prüfung**
Öffne `docs/assets/images/icon-512.png` im macOS-Preview:
`open docs/assets/images/icon-512.png`
Erwartet: Slate-Quadrat mit abgerundeten Ecken, helles blockiges „r" mittig (Stemm links, Arm oben nach rechts, Abfall rechts). Falls das „r" falsch aussieht (z. B. umgedreht, zu klein, nicht zentriert): die `d=`-Pfad-Koordinaten in `favicon.svg` UND die Polygon-Punkte in `scripts/render_favicon.py` **zusammen** anpassen, dann Step 4 wieder.
- [ ] **Step 7: Commit**
- [ ] **Step 7: Commit**
```bash
git add docs/assets/images/favicon.svg docs/assets/images/favicon.ico \
docs/assets/images/icon-192.png docs/assets/images/icon-512.png \
scripts/render_favicon.py
git commit -m "feat(favicon): add minimal 'r' monogram favicon + render script"
```
---
### Task 2: `mkdocs.yml` aktivieren + Build-Verifikation
**Files:**
- Modify: `mkdocs.yml:23-24` (nur die `favicon`-Zeile entkommentieren)
**Interfaces:**
- Konsumiert: `docs/assets/images/favicon.ico` aus Task 1
- Produziert: ein gebauter `site/`-Ordner, dessen `index.html` das neue Favicon referenziert
- [ ] **Step 1: `mkdocs.yml` anpassen**
Öffne `mkdocs.yml` und ändere Zeile 24 von
` #favicon: assets/images/favicon.ico`
zu
` favicon: assets/images/favicon.ico`
Zeile 23 (`#logo:`) bleibt unverändert.
- [ ] **Step 2: Build ausführen**
Run: `uv run mkdocs build --clean`
Expected: `INFO - Cleaning site directory` … `INFO - Git revision ... - Done in Xs` (oder analog), exit 0.
- [ ] **Step 3: Verifikation – Site enthält neues Favicon, HTML referenziert es**
```bash
ls -la site/assets/images/favicon.ico site/assets/images/icon-192.png site/assets/images/icon-512.png
grep -o 'favicon[^"]*\.ico' site/index.html | head -1
# Ersetzt: altes favicon.ico sollte durch neues ersetzt sein
cmp site/assets/images/favicon.ico docs/assets/images/favicon.ico && echo "identical"
```
Expected: alle drei Dateien existieren unter `site/assets/images/`, `index.html` enthält einen `favicon`-Href, `cmp` meldet `identical`.
- [ ] **Step 4: Commit**
```bash
git add mkdocs.yml
git commit -m "feat(favicon): enable new favicon in mkdocs.yml"
```
---
### Task 3: `mkdocs serve` starten (Nutzer-Ansicht)
**Files:**
- Keine (nur Prozess starten)
**Interfaces:**
- Konsumiert: Task 1 + Task 2 Ergebnis
- Sichtbar im Browser unter `http://localhost:8000`
- [ ] **Step 1: Port 8000 freigeben (falls belegt)**
Run: `lsof -i :8000 || true`
Expected: leer. Falls ein Prozess dort lauscht, diesen identifizieren und fragen, ob er beendet werden darf; sonst auf Port 8001 ausweichen (Step 3).
- [ ] **Step 2: `mkdocs serve` im Hintergrund starten**
Run (dauert kurz, bis `Serving on http://...`):
```bash
uv run mkdocs serve --dev-port 8000 2>&1 | tee /tmp/mkdocs-serve.log &
sleep 4
grep -E "Serving on|ERROR" /tmp/mkdocs-serve.log
```
Expected: `Serving on http://127.0.0.1:8000/` und kein `ERROR`.
- [ ] **Step 3: Nutzer prüft Favicon**
Nutzer öffnet im Browser: `http://localhost:8000` → Browser-Tab zeigt das neue „r"-Favicon. Falls gewünscht, Tab 4-fach zoomen, um 16px-Rendering zu prüfen.
- [ ] **Step 4: Aufräumen (nach Freigabe)**
Nutzer meldet „passt" →
```bash
pkill -f "mkdocs serve" || true
rm -f /tmp/mkdocs-serve.log
```
Beachte: `site/` ist Build-Artefakt. Es ist aktuell NICHT in `.gitignore` (nur `.DS_Store`, `.temp`, `.cache`, `.vscode`, `.venv/`). Prüfen mit `git status --porcelain | grep site/` — falls `site/` als untracked auftaucht, `site/` zu `.gitignore` hinzufügen und separat committen, bevor Task 3 startet.