Files
Wabenhain/src/components/home-sections-a.tsx
T
Nick SzaunigandClaude Opus 5.5 1fa8ca246a refactor(ui): Kicker-Zeilen ueber Ueberschriften entfernt
Jede zweite Ueberschrift trug eine kleine Versalien-Zeile mit Wabenpunkt
("• STIMMEN", "• AKTUELL VERFUEGBAR", "• KUNDENKONTO" ...). Auf 29 Seiten
und Abschnitten wiederholt las sich das wie eine Vorlage. SectionHeading
rendert sie nicht mehr, die Prop ist entfernt; die Ueberschrift traegt den
Abschnitt allein.

Die eyebrow-Texte, die weiterhin als Seitentitel, Bildbeschriftung oder
Breadcrumb dienen, bleiben; 18 danach ungenutzte Eintraege sind aus Typ und
beiden Woerterbuechern entfernt.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-26 01:41:48 +02:00

204 lines
7.6 KiB
TypeScript

import { Container, SectionHeading, LinkButton, FramedMedia } from "@/components/ui";
import { HoneycombPattern, HexMark } from "@/components/honeycomb";
import { ScrollReveal } from "@/components/scroll-reveal";
import { ContentImage } from "@/components/content-image";
import { ProductCard, TasteScale, AddToCartButton } from "@/components/product-card";
import { formatPrice, formatDate } from "@/lib/format";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
import { getContentValues, parseListSimple, parseListTitled } from "@/lib/content";
import type { ProductWithRelations } from "@/lib/data";
export async function CurrentHarvest({
products,
reviewSummaries,
}: {
products: ProductWithRelations[];
reviewSummaries?: Map<string, { average: number | null; count: number }>;
}) {
const t = getDictionary(await getLocale());
return (
<section className="py-24">
<Container>
<ScrollReveal>
<SectionHeading
title={t.home.currentHarvest.title}
subtitle={t.home.currentHarvest.subtitle}
/>
</ScrollReveal>
<div className="mt-14 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-8 gap-y-14">
{products.map((product, index) => (
<ProductCard
key={product.id}
product={product}
reviewSummary={reviewSummaries?.get(product.id)}
index={index}
/>
))}
</div>
</Container>
</section>
);
}
export async function OriginStory() {
const locale = await getLocale();
const t = getDictionary(locale);
const content = await getContentValues(
[
"home.originStory.paragraph1",
"home.originStory.paragraph2",
"home.originStory.facts",
"home.originStory.image",
],
locale
);
const facts = parseListSimple(content["home.originStory.facts"]);
return (
<section className="py-28 bg-cream/60">
<Container className="grid md:grid-cols-2 gap-16 lg:gap-24 items-center">
<ScrollReveal>
<FramedMedia>
<ContentImage
src={content["home.originStory.image"] || null}
alt=""
tone="forest"
className="aspect-[4/5] w-full"
label={t.home.originStory.eyebrow}
sizes="(min-width: 768px) 50vw, 100vw"
/>
</FramedMedia>
</ScrollReveal>
<ScrollReveal delay={0.1}>
<SectionHeading
title={t.home.originStory.title}
/>
<p className="mt-6 text-ink/75 leading-relaxed">{content["home.originStory.paragraph1"]}</p>
<p className="mt-4 text-ink/75 leading-relaxed">{content["home.originStory.paragraph2"]}</p>
<ul className="mt-8 grid gap-2.5 text-sm text-ink/75 sm:grid-cols-2">
{facts.map((fact) => (
<li key={fact} className="flex items-start gap-2.5">
<HexMark className="mt-1.5 h-2 w-2 flex-shrink-0 text-honey" />
{fact}
</li>
))}
</ul>
<LinkButton href="/herkunft" variant="secondary" className="mt-8">
{t.home.originStory.cta}
</LinkButton>
</ScrollReveal>
</Container>
</section>
);
}
export async function Philosophy() {
const locale = await getLocale();
const t = getDictionary(locale);
const content = await getContentValues(["home.philosophy.items"], locale);
const items = parseListTitled(content["home.philosophy.items"]);
return (
<section className="py-24">
<Container>
<ScrollReveal>
<SectionHeading
title={t.home.philosophy.title}
align="center"
className="mx-auto"
/>
</ScrollReveal>
<div className="mt-16 grid sm:grid-cols-2 lg:grid-cols-4 gap-x-8 gap-y-14">
{items.map((item, i) => (
<ScrollReveal key={item.title} delay={i * 0.08}>
<div className={`border-t border-ink/15 pt-6 ${i % 2 === 1 ? "lg:mt-10" : ""}`}>
{/* Wabe statt "01"-Nummer: die vier Punkte sind gleichrangig, keine Reihenfolge. */}
<HexMark filled={i % 2 === 0} className="h-5 w-5 text-honey" />
<h3 className="mt-4 text-2xl text-forest">{item.title}</h3>
<p className="mt-3 text-sm text-ink/70 leading-relaxed">
{item.text}
</p>
</div>
</ScrollReveal>
))}
</div>
</Container>
</section>
);
}
type HoneySpotlightProduct = ProductWithRelations & {
harvest: NonNullable<ProductWithRelations["harvest"]>;
batch: NonNullable<ProductWithRelations["batch"]>;
};
export async function ProductSpotlight({ product }: { product: HoneySpotlightProduct }) {
const locale = await getLocale();
const t = getDictionary(locale);
return (
<section className="relative overflow-hidden py-28 bg-forest text-cream">
<HoneycombPattern className="text-honey-light/[0.08]" size={28} fade="right" />
<Container className="relative grid md:grid-cols-2 gap-14 lg:gap-24 items-center">
<ScrollReveal>
<ContentImage
src={product.images[0] ?? null}
alt={product.name}
tone="honey"
className="aspect-square w-full"
label={product.name}
sizes="(min-width: 768px) 50vw, 100vw"
/>
</ScrollReveal>
<ScrollReveal delay={0.1}>
<p className="tracking-wide-caps text-xs text-honey-light mb-3">
{product.harvest.type} {product.harvest.year}
</p>
<h2 className="text-5xl md:text-6xl leading-[1] tracking-[-0.015em]">{product.name}</h2>
<p className="mt-4 text-cream/75 leading-relaxed">
{t.home.productSpotlight.description}
</p>
<div className="mt-8 space-y-3">
<TasteScale label={t.product.tasteMild} value={product.intensityMild} tone="inverted" />
<TasteScale label={t.product.tasteFloral} value={product.intensityFloral} tone="inverted" />
<TasteScale label={t.product.tasteIntense} value={product.intensityKraeftig} tone="inverted" />
</div>
<p className="mt-4 text-sm text-cream/60">
{t.home.productSpotlight.consistency}: {product.consistency}
</p>
<dl className="mt-8 grid grid-cols-2 gap-4 text-sm text-cream/70">
<div>
<dt className="text-cream/65">{t.home.productSpotlight.harvest}</dt>
<dd>{formatDate(product.harvest.harvestDate, locale)}</dd>
</div>
<div>
<dt className="text-cream/65">{t.home.productSpotlight.batch}</dt>
<dd>{product.batch.code}</dd>
</div>
<div>
<dt className="text-cream/65">{t.home.productSpotlight.weight}</dt>
<dd>{product.weightGrams} g</dd>
</div>
<div>
<dt className="text-cream/65">{t.home.productSpotlight.price}</dt>
<dd className="font-serif text-2xl text-cream tabular-nums">
{formatPrice(product.priceCents, product.currency, locale)}
</dd>
</div>
</dl>
<div className="mt-10 flex flex-wrap gap-4">
<LinkButton
href={`/honig/${product.slug}`}
variant="inverted"
>
{t.home.productSpotlight.cta}
</LinkButton>
<AddToCartButton product={product} variant="accent" />
</div>
</ScrollReveal>
</Container>
</section>
);
}