feat(ui): Fundament und Einkaufserlebnis visuell aufgewertet

- Fundament: feine Papierkoernung, Scrollbar/Cursor/Fokusring/Markierung in
  Markenfarben, gleich breite Ziffern fuer Preise, einlaufende Unterstriche
- Knoepfe fuellen sich beim Hover von unten wie ein Glas (Honig/Waldgruen),
  geben beim Klick nach
- Wabenmotiv aus dem Logo als Komponente (Raster, Markierung, Haekchen)
- In den Warenkorb: ein Honigtropfen fliegt im Bogen zum Korb, der Korb
  wippt, der Zaehler springt, erst dann oeffnet die Schublade; Knopf zeigt
  gezeichnetes Haekchen. Reduzierte Bewegung: Schublade oeffnet sofort.
- Produktkarten: Honigschimmer, Anheben, Serifen-Preis, gestaffeltes
  Erscheinen, Pfeil-Links
- Produktseite: mitlaufendes Bild auf Wabenraster, groesserer Titel und
  Preis, sich fuellende Geschmacksskala, Waben-Haekchen statt "✓"
- Shop-Filter als einheitliche Werkzeugleiste mit Schalter
- Warenkorb-Schublade: Dialog-Semantik, animierte Positionen, tickende
  Summe, gestalteter leerer Zustand

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 04:56:03 +02:00
1 parent 839bbff595
commit 3cb639c154
11 files changed
+621 -123

No files matched your search

+34 -10
View File
@@ -1,5 +1,6 @@
import Link from "next/link";
import type { ComponentPropsWithoutRef, ReactNode } from "react";
import { HexMark } from "@/components/honeycomb";
export function Container({
id,
@@ -19,14 +20,22 @@ export function Container({
type ButtonVariant = "primary" | "secondary" | "ghost";
// Signatur-Hover: der Knopf fuellt sich von unten wie ein Glas — beim
// Primaerknopf mit Honig, beim Sekundaerknopf mit Waldgruen. Umgesetzt als
// Hintergrund-Verlauf, dessen Hoehe waechst (kein Layout-Eigenschafts-
// Tweening, kein zusaetzliches Element).
const fillBase =
"bg-no-repeat bg-bottom bg-[length:100%_0%] hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] motion-reduce:transition-colors";
const buttonStyles: Record<ButtonVariant, string> = {
primary:
"bg-forest text-cream hover:bg-[#1a271f] border border-forest",
secondary:
"bg-transparent text-forest border border-forest hover:bg-forest hover:text-cream",
ghost: "bg-transparent text-ink border border-ink/20 hover:border-ink",
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]",
};
const buttonBase =
"inline-flex items-center justify-center gap-2 px-7 py-3 text-sm tracking-wide-caps transition-[color,background-size,border-color,transform,box-shadow] duration-500 ease-[var(--ease-arrive)] hover:shadow-[0_10px_24px_-14px_rgba(36,53,43,0.55)] active:scale-[0.97] active:duration-100";
interface LinkButtonProps extends ComponentPropsWithoutRef<typeof Link> {
variant?: ButtonVariant;
}
@@ -39,7 +48,7 @@ export function LinkButton({
}: LinkButtonProps) {
return (
<Link
className={`inline-flex items-center justify-center gap-2 px-7 py-3 text-sm tracking-wide-caps transition-[color,background-color,border-color,transform] duration-300 active:scale-[0.97] ${buttonStyles[variant]} ${className}`}
className={`${buttonBase} ${buttonStyles[variant]} ${className}`}
{...props}
>
{children}
@@ -59,7 +68,7 @@ export function Button({
}: ButtonProps) {
return (
<button
className={`inline-flex items-center justify-center gap-2 px-7 py-3 text-sm tracking-wide-caps transition-[color,background-color,border-color,transform] duration-300 active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100 ${buttonStyles[variant]} ${className}`}
className={`${buttonBase} disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100 disabled:hover:bg-[length:100%_0%] disabled:hover:shadow-none ${buttonStyles[variant]} ${className}`}
{...props}
>
{children}
@@ -93,14 +102,29 @@ export function SectionHeading({
>
{eyebrow ? (
<p
className={`tracking-wide-caps text-xs mb-3 ${tone === "inverted" ? "text-honey-light" : "text-honey-dark"}`}
className={`flex items-center gap-2 tracking-wide-caps text-xs mb-4 ${
align === "center" ? "justify-center" : ""
} ${tone === "inverted" ? "text-honey-light" : "text-honey-dark"}`}
>
<HexMark className="h-2.5 w-2.5 flex-shrink-0" />
{eyebrow}
</p>
) : null}
<Heading className="text-3xl md:text-4xl text-forest">{title}</Heading>
<Heading
className={`text-4xl md:text-5xl leading-[1.05] tracking-[-0.01em] ${
tone === "inverted" ? "text-cream" : "text-forest"
}`}
>
{title}
</Heading>
{subtitle ? (
<p className="mt-4 text-ink/70 leading-relaxed">{subtitle}</p>
<p
className={`mt-5 max-w-[60ch] leading-relaxed ${align === "center" ? "mx-auto" : ""} ${
tone === "inverted" ? "text-cream/75" : "text-ink/70"
}`}
>
{subtitle}
</p>
) : null}
</div>
);