feat: Add Section layout component and refactor page.tsx with updated styling and new Button variants.

This commit is contained in:
1elle1
2026-01-30 16:05:22 +01:00
parent f1cb4ef2cc
commit ef983e0b79
6 changed files with 219 additions and 175 deletions

View File

@@ -5,6 +5,8 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { Menu, X } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { Container } from "@/components/ui/Container";
import { Button } from "@/components/ui/Button";
const NAV_ITEMS = [
{ href: "/", label: "Startseite" },
@@ -20,8 +22,8 @@ export function Header() {
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-background/95 backdrop-blur-sm border-b border-border">
<div className="mx-auto flex items-center justify-between px-[var(--spacing-container-padding)] py-4" style={{ maxWidth: "var(--spacing-container)" }}>
<Link href="/" className="text-xl font-bold tracking-tight" aria-label="Sportbox Reutte Zur Startseite">
<Container className="flex items-center justify-between py-4">
<Link href="/" className="text-xl font-bold tracking-tight text-primary" aria-label="Sportbox Reutte Zur Startseite">
SPORTBOX
</Link>
@@ -30,24 +32,24 @@ export function Header() {
<Link
key={item.href}
href={item.href}
className={`text-sm tracking-wide transition-colors hover:text-muted ${
pathname === item.href ? "font-bold" : "font-normal"
}`}
className={`text-sm tracking-wide transition-colors hover:text-muted ${pathname === item.href ? "font-bold text-primary" : "font-normal text-muted-foreground/80"
}`}
>
{item.label}
</Link>
))}
<Link
<Button
href="/leistungen#kontakt"
className="bg-primary text-secondary px-5 py-2.5 text-sm font-medium transition-opacity hover:opacity-80"
variant="primary"
className="py-2.5 px-5 text-sm"
>
Jetzt Termin buchen
</Link>
</Button>
</nav>
<button
type="button"
className="lg:hidden p-2 -mr-2"
className="lg:hidden p-2 -mr-2 text-primary"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-expanded={mobileMenuOpen}
aria-controls="mobile-menu"
@@ -55,7 +57,7 @@ export function Header() {
>
{mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</Container>
<AnimatePresence>
{mobileMenuOpen && (
@@ -74,20 +76,22 @@ export function Header() {
key={item.href}
href={item.href}
onClick={() => setMobileMenuOpen(false)}
className={`py-3 text-base transition-colors hover:text-muted ${
pathname === item.href ? "font-bold" : "font-normal"
}`}
className={`py-3 text-base transition-colors hover:text-muted ${pathname === item.href ? "font-bold text-primary" : "font-normal text-muted-foreground"
}`}
>
{item.label}
</Link>
))}
<Link
href="/leistungen#kontakt"
onClick={() => setMobileMenuOpen(false)}
className="mt-2 bg-primary text-secondary px-5 py-3 text-center text-sm font-medium transition-opacity hover:opacity-80"
>
Jetzt Termin buchen
</Link>
<div className="mt-4">
<Button
href="/leistungen#kontakt"
onClick={() => setMobileMenuOpen(false)}
variant="primary"
className="w-full justify-center"
>
Jetzt Termin buchen
</Button>
</div>
</div>
</motion.nav>
)}

View File

@@ -0,0 +1,22 @@
interface SectionProps {
children: React.ReactNode;
className?: string;
id?: string;
as?: "section" | "div";
}
export function Section({
children,
className = "",
id,
as: Component = "section",
}: SectionProps) {
return (
<Component
id={id}
className={`py-[var(--spacing-section)] relative ${className}`}
>
{children}
</Component>
);
}

View File

@@ -1,12 +1,10 @@
import Link from "next/link";
import { JSX } from "react";
interface ButtonProps {
children: React.ReactNode;
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
href?: string;
variant?: "primary" | "secondary" | "ghost";
variant?: "primary" | "secondary" | "ghost" | "outline-white" | "ghost-white";
className?: string;
type?: "button" | "submit" | "reset";
onClick?: () => void;
}
export function Button({
@@ -15,30 +13,32 @@ export function Button({
variant = "primary",
className = "",
type = "button",
onClick,
...props
}: ButtonProps) {
const base =
"inline-flex items-center justify-center px-6 py-3 text-sm font-medium transition-all duration-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary";
"inline-flex items-center justify-center px-6 py-3 text-sm font-medium transition-all duration-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:opacity-50 disabled:pointer-events-none cursor-pointer";
const variants = {
primary: "bg-primary text-secondary hover:opacity-80",
secondary:
"border border-primary text-primary hover:bg-primary hover:text-secondary",
ghost: "text-primary underline-offset-4 hover:underline",
primary: "bg-primary text-secondary hover:opacity-90 border border-transparent",
secondary: "bg-transparent border border-primary text-primary hover:bg-primary hover:text-secondary",
ghost: "text-primary hover:bg-neutral/50",
"outline-white": "border border-secondary text-secondary hover:bg-secondary hover:text-primary",
"ghost-white": "text-secondary hover:bg-secondary/10",
};
const classes = `${base} ${variants[variant]} ${className}`;
const selectedVariant = variants[variant] || variants.primary;
const combinedClasses = `${base} ${selectedVariant} ${className}`;
if (href) {
return (
<Link href={href} className={classes}>
<Link href={href} className={combinedClasses}>
{children}
</Link>
);
}
return (
<button type={type} className={classes} onClick={onClick}>
<button type={type} className={combinedClasses} {...props}>
{children}
</button>
);

View File

@@ -11,8 +11,7 @@ export function Container({
}: ContainerProps) {
return (
<Component
className={`mx-auto px-[var(--spacing-container-padding)] ${className}`}
style={{ maxWidth: "var(--spacing-container)" }}
className={`mx-auto w-full max-w-[var(--spacing-container)] px-[var(--spacing-container-padding)] ${className}`}
>
{children}
</Component>