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:
1 parent
839bbff595
commit
3cb639c154
11 files changed
+621
-123
No files matched your search
+34
-10
@@ -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>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user