Button
components/portfolio/hero.tsxNur zwei Varianten. Primär = einmal pro Ansicht. Icon rechts, verschiebt sich beim Hover um 4px. Höhe 44px mobil, 56px ab sm (sekundär +4px Rahmen).
Zustände
Hover, Fokus und Gedrückt sind hier statisch erzwungen, damit alle Zustände nebeneinander sichtbar sind.
- Standard
- Hover
- Fokus
- Gedrückt
- Deaktiviert
- Lädt
- Standard
- Hover
- Fokus
- Gedrückt
- Deaktiviert
- Lädt
Spezifikation
- Varianten
- primary (gefüllt), secondary (Rahmen). Beide mit optionalem Icon rechts.
- Größen
- Eine Größe, responsive
- Höhe
- 44px base · 56px sm+ (secondary + 2 × 2px border)
- Innenabstand
- px-6 py-3 → sm:px-8 sm:py-4 (24 × 12 → 32 × 16px)
- Radius-Token
- --radius-full · rounded-full
- Farb-Tokens
- --foreground, --background, --primary (glow, hover), --border (foreground/20)
- Bewegung
- all 300ms · magnetic 300ms cubic-bezier(0.34, 1.56, 0.64, 1) · glow 400ms ease
- Barrierefreiheit
- Native <button> oder <a>. Lädt: aria-busy="true" und disabled, Text bleibt sichtbar. Ziel mind. 44 × 44px.
// primary
<a className="group inline-flex items-center justify-center gap-2 sm:gap-3 px-6 sm:px-8 py-3 sm:py-4 rounded-full font-medium transition-all duration-300 text-sm sm:text-base disabled:pointer-events-none disabled:opacity-50 bg-foreground text-background hover:shadow-2xl hover:shadow-primary/20 hover-glow magnetic-hover">…</a>
// secondary
<a className="group inline-flex items-center justify-center gap-2 sm:gap-3 px-6 sm:px-8 py-3 sm:py-4 rounded-full font-medium transition-all duration-300 text-sm sm:text-base disabled:pointer-events-none disabled:opacity-50 bg-transparent border-2 border-foreground/20 text-foreground hover:border-primary hover:bg-primary/5 magnetic-hover">…</a>
// loading
<button disabled aria-busy="true">Wird gesendet <Loader2 className="motion-safe:animate-spin" /></button>