diff --git a/docs/MEDIEN.md b/docs/MEDIEN.md
index 8f435e5..c3d2d1d 100644
--- a/docs/MEDIEN.md
+++ b/docs/MEDIEN.md
@@ -13,7 +13,7 @@ Dateinamen bitte so schreiben: ohne Leerzeichen und Umlaute. Gross- und Kleinsch
| `logo.svg` (oder `.png`, `.webp`) | Dunkles Logo für helle Flächen: Kopfzeile nach dem Scrollen, Fußbereich | SVG bevorzugt, PNG mit transparentem Hintergrund |
| `logo-hell.svg` (oder `.png`, `.webp`) | Helles bzw. weißes Logo über dem Headerbild | Fehlt es, wird `logo.*` verwendet |
-Das Logo wird 32 bis 40 px hoch angezeigt. Ein querformatiges Logo ohne Rand wirkt am besten.
+Das Logo wird über dem Headerbild bis 176 px hoch angezeigt, nach dem Scrollen 80 px. Die Seite misst selbst, ob eine Datei hell oder dunkel ist, und setzt sie auf den passenden Untergrund. Liegt nur eine helle Fassung vor, wird sie auf hellen Flächen automatisch abgedunkelt (und umgekehrt). Große PNGs werden verkleinert ausgeliefert.
## Headerbild
diff --git a/package.json b/package.json
index 41756ca..58a8202 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"react": "19.3.0",
"react-dom": "19.3.0",
"server-only": "0.0.1",
+ "sharp": "0.35.4",
"stripe": "22.6.2",
"zod": "4.6.5"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a332be7..2214071 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -199,6 +199,9 @@ importers:
server-only:
specifier: 0.0.1
version: 0.0.1
+ sharp:
+ specifier: 0.35.4
+ version: 0.35.4(@types/node@22.20.4)
stripe:
specifier: 22.6.2
version: 22.6.2(@types/node@22.20.4)
@@ -4094,8 +4097,7 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
- '@img/colour@1.1.0':
- optional: true
+ '@img/colour@1.1.0': {}
'@img/sharp-darwin-arm64@0.35.4':
optionalDependencies:
@@ -6755,7 +6757,6 @@ snapshots:
'@img/sharp-win32-ia32': 0.35.4
'@img/sharp-win32-x64': 0.35.4
'@types/node': 22.20.4
- optional: true
shebang-command@2.0.0:
dependencies:
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index fec912f..7a80869 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -53,7 +53,7 @@ export function Hero({ pricing, media, video }: { pricing: PublicPricing; media:
-
+
ARTISTA
{hero.title}
diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx
index 4208618..057e549 100644
--- a/src/components/Logo.tsx
+++ b/src/components/Logo.tsx
@@ -1,12 +1,31 @@
+import type { LogoImage } from "@/lib/site-media";
+
/**
- * ARTISTA-Logo aus dem Medienverzeichnis (logo.svg/png bzw. logo-hell.*).
- * Ohne Datei erscheint ein Schriftzug. Bewusst
statt next/image:
- * SVG-Logos laufen nicht durch die Bildoptimierung.
+ * Umfaerbung, wenn keine passende Fassung hochgeladen wurde (siehe
+ * resolveLogos in site-media.ts): ein helles Logo wird auf heller Flaeche
+ * dunkel, ein dunkles auf Foto weiss.
*/
-export function Logo({ src, className = "" }: { src: string | null; className?: string }) {
- if (src) {
- // eslint-disable-next-line @next/next/no-img-element
- return
;
+const TONE_FILTER: Record = {
+ "as-is": "",
+ darken: "brightness(0.28) contrast(1.2)",
+ lighten: "brightness(0) invert(1)",
+};
+/** Ueber dem Foto hebt ein weicher Schatten das Logo vom Bild ab. */
+const PHOTO_SHADOW = "drop-shadow(0 2px 14px rgb(0 0 0 / 0.55))";
+
+/**
+ * ARTISTA-Logo aus dem Medienverzeichnis (logo.* bzw. logo-hell.*). Ohne
+ * Datei erscheint ein Schriftzug. Bewusst
statt next/image: die URL
+ * ist bereits optimiert (Raster) bzw. ein SVG, und die Hoehe kommt vom
+ * Elternelement.
+ */
+export function Logo({ logo, onPhoto = false, className = "" }: { logo: LogoImage | null; onPhoto?: boolean; className?: string }) {
+ if (logo) {
+ const filter = [TONE_FILTER[logo.tone], onPhoto ? PHOTO_SHADOW : ""].filter(Boolean).join(" ");
+ return (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ );
}
return Artista;
}
diff --git a/src/components/SiteFooter.tsx b/src/components/SiteFooter.tsx
index c8a4f38..47a8617 100644
--- a/src/components/SiteFooter.tsx
+++ b/src/components/SiteFooter.tsx
@@ -1,14 +1,15 @@
import type { PublicCampFacts } from "@/lib/camp";
+import type { LogoImage } from "@/lib/site-media";
import { Logo } from "./Logo";
-export function SiteFooter({ facts, showDrafts, logo }: { facts: PublicCampFacts; showDrafts: boolean; logo: string | null }) {
+export function SiteFooter({ facts, showDrafts, logo }: { facts: PublicCampFacts; showDrafts: boolean; logo: LogoImage | null }) {
const organizer = facts.organizer;
return (