feat(ui): Seitenabschluesse, Wissens-Verzeichnis, Kopfzeile ohne Ueberlauf

- Imkerei, Herkunft und Ernten endeten mit dem letzten Absatz direkt vor
  der Fusszeile. Neuer PageOutro: zwei naechste Wege als grosse
  Serif-Links mit Kurztext (Ernten/Shop bzw. Herkunft/Shop).
- Kopfzeile: bei 1280 px lief sie 54 px ueber (horizontale Scrollleiste),
  weil die nicht umbrechbare Slogan-Zeile unter dem Logo schon ab xl
  erschien. Jetzt erst ab 2xl; geprueft 1024 bis 1920 px ohne Ueberlauf.
- Wissen: Inhaltsverzeichnis statt zehn gleicher Bloecke mit je einem
  "Weiterlesen" - ganze Zeile ist der Link, Titel und Kurztext
  nebeneinander. Ungenutzter Schluessel readMore entfernt.
- Produktseite: bei ein, zwei Empfehlungen steht die Ueberschrift als
  erste Rasterspalte statt ueber einer einzelnen verlorenen Karte.

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 02:05:25 +02:00
1 parent 908afebacb
commit b588975317
10 files changed
+123 -25

No files matched your search

+8
View File
@@ -8,6 +8,7 @@ import { getHarvests } from "@/lib/data";
import { formatMonthYear } from "@/lib/format";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
import { PageOutro } from "@/components/page-outro";
export const metadata: Metadata = {
title: "Unsere Ernten",
@@ -96,6 +97,13 @@ export default async function ErntenPage() {
) : null}
</div>
</Container>
<PageOutro
ariaLabel={t.pageOutro.ariaLabel}
links={[
{ href: "/herkunft", label: t.nav.origin, text: t.pageOutro.originText },
{ href: "/shop", label: t.nav.shop, text: t.pageOutro.shopText },
]}
/>
</div>
);
}
+8
View File
@@ -6,6 +6,7 @@ import { ScrollReveal } from "@/components/scroll-reveal";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
import { getContentValue } from "@/lib/content";
import { PageOutro } from "@/components/page-outro";
export async function generateMetadata(): Promise<Metadata> {
const t = getDictionary(await getLocale());
@@ -72,6 +73,13 @@ export default async function HerkunftPage() {
{t.herkunftPage.privacyNote}
</p>
</Container>
<PageOutro
ariaLabel={t.pageOutro.ariaLabel}
links={[
{ href: "/ernten", label: t.nav.harvests, text: t.pageOutro.harvestsText },
{ href: "/shop", label: t.nav.shop, text: t.pageOutro.shopText },
]}
/>
</div>
);
}
+11 -8
View File
@@ -525,15 +525,18 @@ export default async function ProductDetailPage(
</Container>
{relatedProducts.length > 0 ? (
<Container className="mt-20">
<ScrollReveal>
<h2 className="text-3xl md:text-4xl text-forest mb-10">{t.productPage.relatedProductsHeading}</h2>
// Bei ein, zwei Empfehlungen steht die Ueberschrift als erste Spalte im
// Raster (wie "Aktuelle Ernte" auf der Startseite) — sonst stuende eine
// einzelne Karte verloren unter einer breiten Ueberschrift.
<Container className="mt-20 grid grid-cols-1 gap-x-8 gap-y-14 sm:grid-cols-2 lg:grid-cols-3">
<ScrollReveal
className={relatedProducts.length <= 2 ? "sm:col-span-2 lg:col-span-1" : "sm:col-span-2 lg:col-span-3"}
>
<h2 className="text-3xl md:text-4xl text-forest text-balance">{t.productPage.relatedProductsHeading}</h2>
</ScrollReveal>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-8 gap-y-14">
{relatedProducts.map((related, index) => (
<ProductCard key={related.id} product={related} index={index} />
))}
</div>
{relatedProducts.map((related, index) => (
<ProductCard key={related.id} product={related} index={index} />
))}
</Container>
) : null}
+8
View File
@@ -5,6 +5,7 @@ import { ScrollReveal } from "@/components/scroll-reveal";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
import { getContentValue } from "@/lib/content";
import { PageOutro } from "@/components/page-outro";
export async function generateMetadata(): Promise<Metadata> {
const t = getDictionary(await getLocale());
@@ -55,6 +56,13 @@ export default async function ImkereiPage() {
/>
</FramedMedia>
</Container>
<PageOutro
ariaLabel={t.pageOutro.ariaLabel}
links={[
{ href: "/ernten", label: t.nav.harvests, text: t.pageOutro.harvestsText },
{ href: "/shop", label: t.nav.shop, text: t.pageOutro.shopText },
]}
/>
</div>
);
}
+20 -13
View File
@@ -19,36 +19,43 @@ export default async function WissenPage() {
const t = getDictionary(await getLocale());
return (
<div className="py-20">
<Container className="max-w-3xl">
<Container className="max-w-5xl">
<ScrollReveal>
<SectionHeading level="h1" title={t.wissenListPage.title} />
</ScrollReveal>
<div className="mt-14 divide-y divide-ink/10 border-y border-ink/10">
{/* Inhaltsverzeichnis statt zehn gleicher Bloecke mit je einem
"Weiterlesen": die ganze Zeile ist der Link, Titel und Kurztext
stehen nebeneinander, der Pfeil zeigt die Richtung. */}
<ol className="mt-14 divide-y divide-ink/10 border-y border-ink/10">
{wissenSlugs.map((slug, i) => {
const article = t.wissenArticles[slug];
return (
<ScrollReveal key={slug} delay={(i % 5) * 0.06}>
<Link href={`/wissen/${slug}`} className="group block py-9">
<h2 className="link-draw inline pb-0.5 text-3xl leading-tight text-forest">{article.title}</h2>
<p className="mt-3 max-w-[60ch] text-ink/70 leading-relaxed">{article.excerpt}</p>
<span className="mt-4 inline-flex items-center gap-2 text-sm text-honey-dark tracking-wide-caps">
{t.wissenListPage.readMore}
<li key={slug}>
<ScrollReveal delay={(i % 5) * 0.05}>
<Link
href={`/wissen/${slug}`}
className="group grid gap-3 py-8 md:grid-cols-12 md:items-baseline md:gap-8"
>
<h2 className="text-2xl leading-tight text-forest text-balance md:col-span-5 md:text-3xl">
<span className="link-draw pb-0.5">{article.title}</span>
</h2>
<p className="max-w-[60ch] text-ink/70 leading-relaxed md:col-span-6">{article.excerpt}</p>
<svg
aria-hidden="true"
viewBox="0 0 24 24"
className="h-3.5 w-3.5 transition-transform duration-300 ease-[var(--ease-arrive)] group-hover:translate-x-1"
className="hidden h-5 w-5 justify-self-end text-honey-dark transition-transform duration-300 ease-[var(--ease-arrive)] group-hover:translate-x-1 motion-reduce:transition-none md:col-span-1 md:block"
fill="none"
stroke="currentColor"
strokeWidth="1.6"
>
<path d="M4 12h15M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</Link>
</ScrollReveal>
</Link>
</ScrollReveal>
</li>
);
})}
</div>
</ol>
</Container>
</div>
);