feat(ui): Kopfzeile, Fusszeile und Details mit mehr Leben
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 4m11s

- Kopfzeile: aktive Seite mit Honig-Unterstrich (auch im Handy-Menue),
  einlaufende Unterstriche beim Hover, beim Scrollen Glas und Schatten;
  weicht beim Runterscrollen aus und ist beim Hochscrollen sofort zurueck
  (steht still, solange Warenkorb oder Menue offen sind)
- Fusszeile mit Wabenraster und einlaufenden Link-Unterstrichen
- Mengensteller: gezeichnete Plus/Minus, taktiles Druecken, tickende Zahl
- Newsletter als eigene Flaeche mit Wabenraster; Erfolg zeichnet ein
  Haekchen in eine Wabe, Fehler werden als Alert angesagt
- 404: Wabe mit einer fehlenden Zelle als Bild fuer die fehlende Seite

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-09-25 08:05:01 +02:00
1 parent 4ee5bafe20
commit 064ca3ff6d
5 files changed
+188 -25

No files matched your search

+45 -3
View File
@@ -1,6 +1,8 @@
"use client";
import { useState, type FormEvent } from "react";
import { motion } from "motion/react";
import { HoneycombPattern } from "@/components/honeycomb";
import { Container, SectionHeading, Button } from "@/components/ui";
import { ScrollReveal } from "@/components/scroll-reveal";
import { TurnstileWidget } from "@/components/turnstile-widget";
@@ -50,8 +52,13 @@ export function NewsletterSignup({ turnstileSiteKey }: { turnstileSiteKey?: stri
return (
<section className="py-24">
<Container className="max-w-2xl text-center">
<Container className="max-w-4xl">
<ScrollReveal>
{/* Eigene Flaeche mit Wabenraster: die Anmeldung ist ein Angebot,
kein Nachsatz unter der Seite. */}
<div className="relative overflow-hidden border border-honey/30 bg-honey/[0.06] px-6 py-14 text-center sm:px-14">
<HoneycombPattern className="text-honey/25" size={24} />
<div className="relative mx-auto max-w-2xl">
<SectionHeading
eyebrow={t.home.newsletter.eyebrow}
title={t.home.newsletter.title}
@@ -61,7 +68,38 @@ export function NewsletterSignup({ turnstileSiteKey }: { turnstileSiteKey?: stri
<p className="mt-4 text-ink/70">{t.home.newsletter.description}</p>
{status === "success" ? (
<p className="mt-8 text-forest">{t.home.newsletter.successMessage}</p>
// Bestaetigung als kleine Zeremonie: das Haekchen zeichnet sich
// in der Wabe, dann erscheint der Text.
<div className="mt-8 flex flex-col items-center" role="status">
<svg viewBox="0 0 24 26" className="h-14 w-14" fill="none" aria-hidden="true">
<motion.polygon
points="12,1 22.4,7 22.4,19 12,25 1.6,19 1.6,7"
fill="var(--color-honey)"
initial={{ scale: 0.4, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: "spring", stiffness: 300, damping: 16 }}
style={{ transformOrigin: "center" }}
/>
<motion.path
d="M7.5 13.2l3 3 6-6.4"
stroke="var(--color-cream)"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 0.4, delay: 0.25 }}
/>
</svg>
<motion.p
className="mt-4 font-serif text-2xl text-forest"
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.45 }}
>
{t.home.newsletter.successMessage}
</motion.p>
</div>
) : (
<form onSubmit={handleSubmit} className="mt-8 max-w-lg mx-auto">
{/* Eingabefeld und Knopf bilden die Zeile, das CAPTCHA steht
@@ -92,7 +130,9 @@ export function NewsletterSignup({ turnstileSiteKey }: { turnstileSiteKey?: stri
</form>
)}
{status === "error" ? (
<p className="mt-4 text-sm text-red-700">{t.home.newsletter.errorMessage}</p>
<p className="mt-4 text-sm text-red-700" role="alert">
{t.home.newsletter.errorMessage}
</p>
) : null}
<p className="mt-6 text-xs text-ink/65">
@@ -102,6 +142,8 @@ export function NewsletterSignup({ turnstileSiteKey }: { turnstileSiteKey?: stri
</a>
{t.home.newsletter.consentAfterLink}
</p>
</div>
</div>
</ScrollReveal>
</Container>
</section>