From 3de17ca070789a102a81f7fd3ceb72228b26f16c Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Fri, 25 Sep 2026 07:48:08 +0200 Subject: [PATCH] feat(ui): Startseite mutiger gestaltet - Hero: deutlich groessere Headline, langsam atmendes Bild, Wabenraster, Honigtropfen als Scroll-Hinweis, Hauptaktion in Honig - "Sechs Schritte" als Weg: eine Honiglinie fuellt sich beim Scrollen und laesst die Waben der Schritte nacheinander aufleuchten (waagerecht ab lg, senkrecht auf dem Handy; reduzierte Bewegung: sofort gefuellt) - Philosophie mit Waben statt Nummern, Verantwortung als geteiltes Layout mit mitlaufender Ueberschrift - Bilder mit versetztem Honigrahmen, Wabenraster auf dunklen Flaechen, grosse Anfuehrungszeichen bei den Kundenstimmen - Knopf-Varianten "inverted"/"accent" fuer dunkle Flaechen ersetzen !-Overrides, die den Fuell-Effekt ausgehebelt haetten - Fix: Ueberschrift der Kundenstimmen war Waldgruen auf Waldgruen Co-Authored-By: Claude Opus 5.5 (1M context) --- src/app/globals.css | 38 ++++++++++ src/components/cookie-consent.tsx | 4 +- src/components/hero.tsx | 54 +++++++++----- src/components/home-sections-a.tsx | 57 ++++++++------- src/components/home-sections-b.tsx | 110 ++++++++++++++--------------- src/components/process-path.tsx | 95 +++++++++++++++++++++++++ src/components/product-card.tsx | 2 +- src/components/site-chrome.tsx | 4 +- src/components/ui.tsx | 37 +++++++++- 9 files changed, 298 insertions(+), 103 deletions(-) create mode 100644 src/components/process-path.tsx diff --git a/src/app/globals.css b/src/app/globals.css index 1773f5e..310056d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -165,3 +165,41 @@ p { opacity: 0.5; } } + +/* Hero: das Bild "atmet" kaum merklich (langsamer Zoom hin und zurueck). */ +@keyframes wh-drift { + from { + transform: scale(1); + } + to { + transform: scale(1.07) translate(-1%, -1%); + } +} + +/* Scroll-Hinweis im Hero: ein Honigtropfen loest sich und faellt. */ +@keyframes wh-drip { + 0%, + 15% { + transform: translateY(0) scale(0.6); + opacity: 0; + } + 30% { + transform: translateY(0) scale(1); + opacity: 1; + } + 75% { + transform: translateY(26px) scale(0.9, 1.1); + opacity: 1; + } + 100% { + transform: translateY(34px) scale(0.4); + opacity: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .motion-drift, + .motion-drip { + animation: none !important; + } +} diff --git a/src/components/cookie-consent.tsx b/src/components/cookie-consent.tsx index d58eee6..0044fbd 100644 --- a/src/components/cookie-consent.tsx +++ b/src/components/cookie-consent.tsx @@ -49,8 +49,8 @@ export function CookieConsentBanner() {

{t.home.productSpotlight.price}
-
{formatPrice(product.priceCents, product.currency, locale)}
+
+ {formatPrice(product.priceCents, product.currency, locale)} +
{t.home.productSpotlight.cta} - +
diff --git a/src/components/home-sections-b.tsx b/src/components/home-sections-b.tsx index c5afa12..5985b38 100644 --- a/src/components/home-sections-b.tsx +++ b/src/components/home-sections-b.tsx @@ -1,4 +1,6 @@ -import { Container, SectionHeading, LinkButton } from "@/components/ui"; +import { Container, SectionHeading, LinkButton, FramedMedia } from "@/components/ui"; +import { ProcessPath } from "@/components/process-path"; +import { HoneycombPattern, HexMark } from "@/components/honeycomb"; import { ScrollReveal } from "@/components/scroll-reveal"; import { ContentImage } from "@/components/content-image"; import { StarRating } from "@/components/star-rating"; @@ -23,21 +25,7 @@ export async function ProcessTimeline() { className="mx-auto" /> -
- {steps.map((step, i) => ( - -
- - {step.number} - -

{step.title}

-

- {step.text} -

-
-
- ))} -
+ ); @@ -56,7 +44,7 @@ export async function RegionalSection() { ); return (
- + - + + +
@@ -94,26 +84,30 @@ export async function Sustainability() { const content = await getContentValues(["home.sustainability.items"], locale); const items = parseListTitled(content["home.sustainability.items"]); return ( -
- - - +
+ {/* Geteilt statt Viererreihe: die Ueberschrift laeuft mit, die Punkte + werden als ruhige Liste gelesen. */} + + +
+ +
-
+
    {items.map((item, i) => ( - -

    {item.title}

    -

    - {item.text} -

    -
    +
  • + +
    + +
    +

    {item.title}

    +

    {item.text}

    +
    +
    +
    +
  • ))} -
+
); @@ -128,16 +122,18 @@ export async function BusinessTeaser() { ); return (
- + - + + + ({ ...r, rating: 5, authorUrl: null })); return ( -
- +
+ + {items.slice(0, 6).map((review, i) => ( + {t.home.reviews.starsOutOf5(review.rating)} -

- „{review.quote}“ +

+ {review.quote}

{/* Zuordnung zur Quelle: die Nutzungsbedingungen der Places API verlangen, dass eine angezeigte Rezension zu Google diff --git a/src/components/process-path.tsx b/src/components/process-path.tsx new file mode 100644 index 0000000..225a056 --- /dev/null +++ b/src/components/process-path.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { useRef } from "react"; +import { motion, useReducedMotion, useScroll, useSpring, useTransform, type MotionValue } from "motion/react"; + +interface Step { + number: string; + title: string; + text: string; +} + +/** + * "Vom Bienenstock ins Glas" als Weg, den der Honig nimmt: eine Honiglinie + * fuellt sich im Takt des Scrollens und laesst die Waben der einzelnen + * Schritte der Reihe nach aufleuchten. Hier traegt die Bewegung Bedeutung — + * die Reihenfolge IST der Inhalt. + * + * Ab lg waagerecht (sechs Spalten), darunter senkrecht mit Linie links. + * Bei reduzierter Bewegung ist der Weg von Anfang an gefuellt. + */ +export function ProcessPath({ steps }: { steps: Step[] }) { + const ref = useRef(null); + const reduceMotion = useReducedMotion(); + const { scrollYProgress } = useScroll({ target: ref, offset: ["start 85%", "end 55%"] }); + // Gefedert statt direkt am Scrollwert: die Linie "fliesst" nach, wie Honig. + const smooth = useSpring(scrollYProgress, { stiffness: 90, damping: 22, mass: 0.6 }); + const full = useTransform(smooth, () => 1); + const progress = reduceMotion ? full : smooth; + + return ( +
    + {/* Leitung (Grundlinie) und Honigfuellung — waagerecht ab lg, sonst senkrecht. */} +
+ ); +} + +function ProcessStep({ + step, + index, + total, + progress, +}: { + step: Step; + index: number; + total: number; + progress: MotionValue; +}) { + // Die Wabe "entzuendet" sich, sobald die Linie ihre Position erreicht. + const at = total > 1 ? index / (total - 1) : 0; + const lit = useTransform(progress, [Math.max(0, at - 0.06), at + 0.02], [0, 1]); + const scale = useTransform(lit, [0, 1], [0.85, 1]); + + return ( +
  • + + {step.number} +

    {step.title}

    +

    {step.text}

    +
  • + ); +} diff --git a/src/components/product-card.tsx b/src/components/product-card.tsx index 81b99f4..01a0077 100644 --- a/src/components/product-card.tsx +++ b/src/components/product-card.tsx @@ -160,7 +160,7 @@ export function AddToCartButton({ }: { product: ProductWithRelations; quantity?: number; - variant?: "primary" | "secondary" | "ghost"; + variant?: "primary" | "secondary" | "ghost" | "inverted" | "accent"; className?: string; }) { const { t } = useI18n(); diff --git a/src/components/site-chrome.tsx b/src/components/site-chrome.tsx index f0d5e6a..79fea39 100644 --- a/src/components/site-chrome.tsx +++ b/src/components/site-chrome.tsx @@ -419,8 +419,8 @@ export function Header({ companyName }: { companyName: string }) { setMobileOpen(false)} > {t.nav.discoverHoney} diff --git a/src/components/ui.tsx b/src/components/ui.tsx index 074b231..1538b90 100644 --- a/src/components/ui.tsx +++ b/src/components/ui.tsx @@ -18,7 +18,7 @@ export function Container({ ); } -type ButtonVariant = "primary" | "secondary" | "ghost"; +type ButtonVariant = "primary" | "secondary" | "ghost" | "inverted" | "accent"; // Signatur-Hover: der Knopf fuellt sich von unten wie ein Glas — beim // Primaerknopf mit Honig, beim Sekundaerknopf mit Waldgruen. Umgesetzt als @@ -31,6 +31,11 @@ const buttonStyles: Record = { primary: `${fillBase} bg-forest bg-[linear-gradient(var(--color-honey-dark),var(--color-honey-dark))] text-cream border border-forest hover:border-honey-dark`, secondary: `${fillBase} bg-transparent bg-[linear-gradient(var(--color-forest),var(--color-forest))] text-forest border border-forest hover:text-cream focus-visible:text-cream`, ghost: "bg-transparent text-ink border border-ink/20 hover:border-ink hover:bg-ink/[0.03]", + // Fuer dunkle Flaechen (Hero, Waldgruen-Abschnitte, Menue): Creme-Rahmen, + // fuellt sich mit Creme, Text wechselt auf Waldgruen. + inverted: `${fillBase} bg-transparent bg-[linear-gradient(var(--color-cream),var(--color-cream))] text-cream border border-cream hover:text-forest focus-visible:text-forest`, + // Hauptaktion auf dunklen Flaechen, wo Waldgruen im Grund verschwinden wuerde. + accent: `${fillBase} bg-honey-dark bg-[linear-gradient(var(--color-cream),var(--color-cream))] text-cream border border-honey-dark hover:text-forest hover:border-cream focus-visible:text-forest`, }; const buttonBase = @@ -129,3 +134,33 @@ export function SectionHeading({ ); } + +/** + * Bild mit versetztem Honigrahmen dahinter — gibt den Bildspalten der + * Startseite Tiefe, statt sie flach neben den Text zu legen. Der Rahmen + * weicht beim Hover etwas zurueck, das Bild bleibt ruhig. + */ +export function FramedMedia({ + children, + side = "right", + className = "", +}: { + children: ReactNode; + /** Richtung, in die der Rahmen versetzt ist. */ + side?: "left" | "right"; + className?: string; +}) { + return ( +
    +
    + ); +}