feat(admin): Logo und Favicon per Bild-Upload austauschbar

Neue Gruppe "Logo und Favicon" unter Admin > Inhalte mit drei Bildfeldern:
Logo (Kopfzeile), optionales Logo fuer dunkle Flaechen (Mobilmenue,
Fusszeile, Admin-Leiste; faellt sonst auf das normale Logo zurueck) und
Favicon. Leer bleibt alles wie bisher (gezeichnetes Waben-Zeichen bzw.
Standard-Icon).

- lib/brand.ts liest die Pfade und prueft sie erneut gegen das
  Upload-Muster, bevor sie in ein src-Attribut gelangen.
- Statische app/icon.svg und app/favicon.ico ersetzt durch dynamische
  app/icon.tsx (512 px PNG) und app/apple-icon.tsx (180 px auf Creme);
  lib/brand-icon.ts rendert Upload oder Standard-Icon per sharp und liest
  Dateien nur ueber resolveUploadPath. Cache-Control no-cache, damit ein
  neues Favicon ohne Tage Verzoegerung erscheint.
- /favicon.ico per Rewrite auf /icon, Manifest nutzt /icon.
- Hochgeladenes Logo mit fester Hoehe und begrenzter Breite (Kopfzeile
  mobil 56 px, ab sm 112 px), damit breite Wortmarken nichts sprengen.

Uploads bleiben auf Rasterbilder beschraenkt (kein SVG, XSS-Schutz).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-09-26 01:02:18 +02:00
1 parent ae2726b0ee
commit 4f442ec06d
19 files changed
+217 -77

No files matched your search

+8
View File
@@ -72,6 +72,14 @@ const nextConfig: NextConfig = {
turbopackFileSystemCacheForBuild: false,
},
// Das Favicon ist im Admin austauschbar und wird von app/icon.tsx erzeugt;
// eine statische app/favicon.ico gibt es deshalb nicht mehr. Browser und
// Crawler, die ohne <link rel="icon"> direkt /favicon.ico abfragen,
// bekommen dasselbe Bild.
async rewrites() {
return [{ source: "/favicon.ico", destination: "/icon" }];
},
async headers() {
// Content-Security-Policy wird bewusst NICHT hier gesetzt: sie braucht
// eine pro Request neue Nonce (siehe proxy.ts), was ein statischer