This commit is contained in:
2026-01-29 00:50:56 +01:00
parent 4b55fc0c63
commit c427b5f6e2
9 changed files with 738 additions and 1118 deletions

View File

@@ -1,29 +1,29 @@
'use client';
import { ArrowUp, Home, Info, Mail } from 'lucide-react';
import { ArrowUp, Home, Info, Mail, Menu, X } from 'lucide-react';
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { motion, AnimatePresence } from 'framer-motion';
const Layout = ({ children }: { children: React.ReactNode }) => {
const pathname = usePathname();
const [showScrollTop, setShowScrollTop] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
useEffect(() => {
const handleScroll = () => {
setShowScrollTop(window.scrollY > 400);
setIsScrolled(window.scrollY > 20);
};
const throttledScroll = () => {
window.requestAnimationFrame(handleScroll);
};
window.addEventListener('scroll', throttledScroll, { passive: true });
return () => window.removeEventListener('scroll', throttledScroll);
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
useEffect(() => {
window.scrollTo(0, 0);
setIsMobileMenuOpen(false);
}, [pathname]);
const scrollToTop = () => {
@@ -32,111 +32,160 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
const isActive = (path: string) => pathname === path;
const navLinks = [
{ href: '/', label: 'Startseite', icon: Home },
{ href: '/ueber-uns', label: 'Über uns', icon: Info },
{ href: '/kontakt', label: 'Kontakt', icon: Mail },
];
return (
<div className="min-h-screen flex flex-col">
<header className="sticky top-0 z-[100] bg-bg-color/95 backdrop-blur-xl border-b border-secondary-bg pt-[env(safe-area-top)]">
<div className="max-w-[1200px] mx-auto px-4 h-20 flex justify-between items-center">
<div className="min-h-screen flex flex-col font-sans">
<header
className={`fixed top-0 left-0 right-0 z-[100] transition-all duration-300 ${
isScrolled ? 'bg-white/80 backdrop-blur-lg border-b border-slate-200 py-2' : 'bg-transparent py-4'
}`}
>
<div className="container-custom flex justify-between items-center">
<Link
href="/"
className="flex items-center"
className="relative z-10 flex items-center group"
aria-label="MB Grid Solutions - Zur Startseite"
>
<img
src="/assets/logo.png"
alt="MB Grid Solutions"
className="h-12 md:h-40 transition-all"
className={`transition-all duration-300 ${isScrolled ? 'h-[90px]' : 'h-[120px] md:h-[150px]'}`}
loading="eager"
/>
</Link>
<nav className="hidden md:flex gap-8" aria-label="Hauptnavigation">
<Link href="/" className={`text-xs font-semibold uppercase tracking-widest transition-colors ${isActive('/') ? 'text-accent-green' : 'text-text-primary hover:text-accent-green'}`}>
Startseite
</Link>
<Link href="/ueber-uns" className={`text-xs font-semibold uppercase tracking-widest transition-colors ${isActive('/ueber-uns') ? 'text-accent-green' : 'text-text-primary hover:text-accent-green'}`}>
Über uns
</Link>
<Link href="/kontakt" className={`text-xs font-semibold uppercase tracking-widest transition-colors ${isActive('/kontakt') ? 'text-accent-green' : 'text-text-primary hover:text-accent-green'}`}>
Kontakt
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center gap-1" aria-label="Hauptnavigation">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${
isActive(link.href)
? 'text-accent bg-accent/5'
: 'text-slate-600 hover:text-primary hover:bg-slate-50'
}`}
>
{link.label}
</Link>
))}
<Link
href="/kontakt"
className="ml-4 btn-primary !py-2 !px-5 !text-sm"
>
Projekt anfragen
</Link>
</nav>
{/* Mobile Menu Toggle */}
<button
className="md:hidden p-2 text-slate-600 hover:text-primary transition-colors"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Menü öffnen"
>
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</header>
<main className="flex-grow pb-[calc(72px+env(safe-area-bottom))] md:pb-0">
{/* Mobile Menu Overlay */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="fixed inset-0 z-[90] bg-white pt-24 px-6 md:hidden"
>
<nav className="flex flex-col gap-4">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className={`flex items-center gap-4 p-4 rounded-xl text-lg font-semibold transition-all ${
isActive(link.href)
? 'text-accent bg-accent/5'
: 'text-slate-600 hover:text-primary hover:bg-slate-50'
}`}
>
<link.icon size={24} />
{link.label}
</Link>
))}
<Link
href="/kontakt"
className="mt-4 btn-primary w-full py-4 text-center"
>
Projekt anfragen
</Link>
</nav>
</motion.div>
)}
</AnimatePresence>
<main className="flex-grow">
{children}
</main>
<button
onClick={scrollToTop}
className={`fixed bottom-24 md:bottom-8 right-5 md:right-8 w-12 md:w-14 h-12 md:h-14 bg-primary text-white rounded-full flex items-center justify-center cursor-pointer z-[900] shadow-lg transition-all duration-300 hover:-translate-y-1 hover:bg-accent-green ${showScrollTop ? 'opacity-100 visible translate-y-0' : 'opacity-0 invisible translate-y-2'}`}
className={`fixed bottom-8 right-8 w-12 h-12 bg-primary text-white rounded-full flex items-center justify-center cursor-pointer z-[80] shadow-xl transition-all duration-300 hover:-translate-y-1 hover:bg-accent ${
showScrollTop ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4 pointer-events-none'
}`}
aria-label="Nach oben scrollen"
aria-hidden={!showScrollTop}
tabIndex={showScrollTop ? 0 : -1}
>
<ArrowUp size={24} strokeWidth={2.5} />
<ArrowUp size={20} strokeWidth={2.5} />
</button>
<nav className="md:hidden fixed bottom-0 left-0 w-full h-[calc(72px+env(safe-area-bottom))] bg-white/95 backdrop-blur-2xl border-t border-black/10 flex justify-around items-start pt-2 z-[1000] px-2" aria-label="Mobile Navigation">
<Link
href="/"
className={`flex flex-col items-center gap-1 text-[10px] font-semibold uppercase tracking-wider flex-1 py-2 transition-colors ${isActive('/') ? 'text-primary' : 'text-gray-400'}`}
aria-label="Startseite"
>
<Home size={22} strokeWidth={2} className={isActive('/') ? 'text-accent-green scale-110' : ''} />
<span>Start</span>
</Link>
<Link
href="/ueber-uns"
className={`flex flex-col items-center gap-1 text-[10px] font-semibold uppercase tracking-wider flex-1 py-2 transition-colors ${isActive('/ueber-uns') ? 'text-primary' : 'text-gray-400'}`}
aria-label="Über uns"
>
<Info size={22} strokeWidth={2} className={isActive('/ueber-uns') ? 'text-accent-green scale-110' : ''} />
<span>Über uns</span>
</Link>
<Link
href="/kontakt"
className={`flex flex-col items-center gap-1 text-[10px] font-semibold uppercase tracking-wider flex-1 py-2 transition-colors ${isActive('/kontakt') ? 'text-primary' : 'text-gray-400'}`}
aria-label="Kontakt"
>
<Mail size={22} strokeWidth={2} className={isActive('/kontakt') ? 'text-accent-green scale-110' : ''} />
<span>Kontakt</span>
</Link>
</nav>
<footer className="bg-white border-t border-secondary-bg py-8 md:py-16 mt-8 md:mt-16">
<div className="max-w-[1200px] mx-auto px-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 md:gap-12 mb-8 md:mb-12">
<div className="flex flex-col items-center md:items-start text-center md:text-left">
<footer className="bg-slate-900 text-slate-300 py-16 md:py-24">
<div className="container-custom">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12 mb-16">
<div className="lg:col-span-2">
<img
src="/assets/logo.png"
alt="MB Grid Solutions"
className="h-16 md:h-20 mb-6 grayscale"
className="h-20 mb-8 brightness-0 invert opacity-80"
loading="lazy"
/>
<p className="text-text-secondary text-sm md:text-base leading-relaxed">
Ihr Partner für Energiekabelprojekte bis 110 kV.
<p className="text-slate-400 max-w-md leading-relaxed mb-8">
Ihr spezialisierter Partner für herstellerneutrale technische Beratung und Projektbegleitung bei Energiekabelprojekten bis 110 kV.
</p>
<div className="flex gap-4">
{/* Social links could go here */}
</div>
</div>
<div className="flex flex-col items-center md:items-start text-center md:text-left">
<h4 className="text-sm md:text-base font-semibold mb-4">Navigation</h4>
<nav className="flex flex-col gap-3" aria-label="Footer Navigation">
<Link href="/" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">Startseite</Link>
<Link href="/ueber-uns" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">Über uns</Link>
<Link href="/kontakt" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">Kontakt</Link>
<div>
<h4 className="text-white font-bold mb-6">Navigation</h4>
<nav className="flex flex-col gap-4">
{navLinks.map((link) => (
<Link key={link.href} href={link.href} className="hover:text-accent transition-colors">
{link.label}
</Link>
))}
</nav>
</div>
<div className="flex flex-col items-center md:items-start text-center md:text-left">
<h4 className="text-sm md:text-base font-semibold mb-4">Rechtliches</h4>
<nav className="flex flex-col gap-3" aria-label="Legal Navigation">
<Link href="/impressum" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">Impressum</Link>
<Link href="/datenschutz" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">Datenschutz</Link>
<Link href="/agb" className="text-sm md:text-[15px] hover:text-accent-green transition-colors">AGB</Link>
<div>
<h4 className="text-white font-bold mb-6">Rechtliches</h4>
<nav className="flex flex-col gap-4">
<Link href="/impressum" className="hover:text-accent transition-colors">Impressum</Link>
<Link href="/datenschutz" className="hover:text-accent transition-colors">Datenschutz</Link>
<Link href="/agb" className="hover:text-accent transition-colors">AGB</Link>
</nav>
</div>
</div>
<div className="border-t border-secondary-bg pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-text-secondary text-xs md:text-sm text-center">
<div>&copy; 2026 MB Grid Solutions GmbH. Alle Rechte vorbehalten.</div>
<div>Made with precision.</div>
<div className="pt-8 border-t border-slate-800 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-slate-500">
<p>&copy; {new Date().getFullYear()} MB Grid Solutions GmbH. Alle Rechte vorbehalten.</p>
<p className="flex items-center gap-2">
Made with <span className="text-accent">precision</span> in Germany
</p>
</div>
</div>
</footer>