From 804d1403b6f32b8acb8434385df24227cf2f5bfc Mon Sep 17 00:00:00 2001 From: Sebastian Pachon Date: Tue, 2 Jun 2026 21:46:56 +0200 Subject: [PATCH] Restore original desktop top-bar nav; sidebar nav for mobile only The sidebar + fullscreen overlay redesign was intended for mobile only. Desktop now renders the original fixed horizontal top bar (logo, centered hamburger, social + language) and its 3-column hover overlay exactly as before. Mobile (<768px) keeps the new 60px vertical sidebar and the single-column accordion overlay. Container offset is paddingTop:60 on desktop and paddingLeft:60 on mobile. Co-Authored-By: Claude Opus 4.8 --- src/components/layout/Layout.tsx | 1104 ++++++++++++++++++++---------- 1 file changed, 746 insertions(+), 358 deletions(-) diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index d56e0b4..e454477 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -7,9 +7,9 @@ import { useIsMobile } from '@/hooks/useIsMobile'; interface LayoutProps { children: React.ReactNode; } /* ── SVG icons ─────────────────────────────────────────── */ -const IgIcon = () => ; -const LiIcon = () => ; -const FbIcon = () => ; +const IgIcon = () => ; +const LiIcon = () => ; +const FbIcon = () => ; const SOCIAL = [ { href:'https://instagram.com', Icon:IgIcon, label:'Instagram' }, { href:'https://linkedin.com', Icon:LiIcon, label:'LinkedIn' }, @@ -90,11 +90,11 @@ const SECONDARY = [ /* ── Tokens ────────────────────────────────────────────── */ const NAVY = '#111D55'; -const ANTHRA = '#1A2030'; -const GOLD = '#EFBF04'; -const MUTED = '#D0D5DD'; -const SEP = 'rgba(239,191,4,0.2)'; -const LINE = 'rgba(239,191,4,0.35)'; +const ANTHRA = '#1A2030'; // nav + footer shared bg +const GOLD = '#EFBF04'; +const MUTED = '#D0D5DD'; +const SEP = 'rgba(239,191,4,0.2)'; +const LINE = 'rgba(239,191,4,0.35)'; const FF_DISPLAY = '"IBM Plex Sans", sans-serif'; const FF_BODY = '"Inter", sans-serif'; @@ -107,11 +107,13 @@ const SocialLink: React.FC<{ href:string; Icon:()=>JSX.Element; label:string }> > ); -/* ── Component ─────────────────────────────────────────── */ + +/* ── Component ──────────────────────────────────────────── */ const Layout: React.FC = ({ children }) => { - const [open, setOpen] = useState(false); - const [activeKey, setActive] = useState(null); // desktop hover - const [expandKey, setExpand] = useState(null); // mobile accordion + const [open, setOpen] = useState(false); // desktop overlay + const [activeKey, setActive] = useState(null); // desktop hover subnav + const [mobileOpen, setMobileOpen] = useState(false); // mobile sidebar overlay + const [expandKey, setExpand] = useState(null); // mobile accordion const [lang, setLang] = useState<'DE'|'EN'>('DE'); const [mounted, setMounted] = useState(false); const [showLoader, setShowLoader] = useState(() => { @@ -125,9 +127,10 @@ const Layout: React.FC = ({ children }) => { const isLegalPage = ['/impressum', '/datenschutz'].includes(location.pathname); const isMobile = useIsMobile(); - // Close overlay on route change + // Close everything on route change useEffect(() => { setOpen(false); + setMobileOpen(false); setExpand(null); if (location.hash) { setTimeout(() => { @@ -139,48 +142,49 @@ const Layout: React.FC = ({ children }) => { } }, [location]); - // Reset mobile accordion when overlay closes + // Reset mobile accordion when its overlay closes useEffect(() => { - if (!open) { - setTimeout(() => { setExpand(null); setActive(null); }, 220); - } - }, [open]); + if (!mobileOpen) setTimeout(() => setExpand(null), 220); + }, [mobileOpen]); - // Body scroll lock + // Body scroll lock (either overlay) useEffect(() => { + const anyOpen = open || mobileOpen; const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; - if (open) { + if (anyOpen) { document.body.style.overflow = 'hidden'; - document.body.style.paddingRight = `${scrollbarWidth}px`; + document.body.style.paddingRight = open ? `${scrollbarWidth}px` : ''; } else { document.body.style.overflow = ''; document.body.style.paddingRight = ''; + setTimeout(() => setActive(null), 220); } return () => { document.body.style.overflow = ''; document.body.style.paddingRight = ''; }; + }, [open, mobileOpen]); + + // Focus first desktop nav link on open + useEffect(() => { + if (open) setTimeout(() => firstLinkRef.current?.focus(), 300); }, [open]); - // Focus first nav link on open + // Escape closes either overlay useEffect(() => { - if (open && !isMobile) setTimeout(() => firstLinkRef.current?.focus(), 300); - }, [open, isMobile]); - - // Escape key - useEffect(() => { - const h = (e: KeyboardEvent) => { if (e.key === 'Escape' && open) setOpen(false); }; + const h = (e:KeyboardEvent) => { + if (e.key === 'Escape') { if (open) setOpen(false); if (mobileOpen) setMobileOpen(false); } + }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); - }, [open]); + }, [open, mobileOpen]); - // Mounted animation useEffect(() => { const t = setTimeout(() => setMounted(true), 60); return () => clearTimeout(t); }, []); - // Hide floating CTA when form section in view + // Hide floating CTA when the form section (#bewerben) is in view — homepage only useEffect(() => { setFormVisible(false); if (location.pathname !== '/') return; @@ -195,10 +199,13 @@ const Layout: React.FC = ({ children }) => { }, [location.pathname]); return ( -
+
{showLoader && setShowLoader(false)} />} - {/* ── GLOBAL CSS ───────────────────────────────── */} + {/* ── GLOBAL BAYERN CSS ────────────────────────── */} - {/* ── SIDEBAR ──────────────────────────────────── */} - - - {/* ── OVERLAY ──────────────────────────────────── */} -
- {/* Background watermark */} -
EXZELLENZ HAT EINEN NAMEN.
- - {isMobile ? ( - /* ── MOBILE: single-column accordion ──────── */ -
- - {/* Top bar */} -
- setOpen(false)} style={{ display:'flex', alignItems:'center', textDecoration:'none' }}> - BMP Logo + {/* LEFT — logo */} +
+ + Der Bayerische Mittelstandspreis 2026 -
+ + {/* CENTER — hamburger */} +
+ + + +
+ + {/* RIGHT — social + lang */} +
+
+ {SOCIAL.map(s => )} +
+
+
+ {(['DE','EN'] as const).map((l, i) => ( + + {i===1 && |} + + + ))} +
+
+ + + + {/* ── DESKTOP OVERLAY ──────────────────────────── */} +
+
+ + {/* TOP — tagline + logo */} +
+
+
+ Bayerischer Mittelstandspreis +
+
+ EXZELLENZ HAT
EINEN NAMEN. +
+
+
+ BMP Logo +
+
+ + {/* BOTTOM — 3 columns */} +
+ + {/* LEFT — main nav */} +
+
    + {NAV.map((item, idx) => ( +
  • + setOpen(false)} + onMouseEnter={() => setActive(item.key)} + style={{ + display:'flex', alignItems:'center', justifyContent:'space-between', + padding:'14px 40px 14px 0', + textDecoration:'none', + color: activeKey===item.key ? GOLD : '#fff', + fontSize:'clamp(15px,1.4vw,20px)', + fontFamily:FF_DISPLAY, + fontWeight:600, textTransform:'uppercase', letterSpacing:'.03em', + transition:'color .15s, transform .15s, opacity .3s ease-out', + transform: open + ? `translateX(${activeKey===item.key ? 6 : 0}px)` + : 'translateX(-16px)', + opacity: open ? 1 : 0, + transitionDelay: open ? `${.04 + idx*.06}s` : '0s', + }} + > + {item.label} + + +
  • + ))} +
  • +
+
+ + {/* MIDDLE — subnav */} +
+ {NAV.map(item => ( +
+
+ Überblick +
+
+ {item.subLabel} +
+
    + {item.sub?.map(sub => ( +
  • + setOpen(false)} + style={{ display:'block', padding:'9px 0', textDecoration:'none', color:MUTED, fontSize: 16, fontFamily:FF_BODY, transition:'color .15s, padding-left .15s' }} + onMouseEnter={e=>{ e.currentTarget.style.color='#fff'; e.currentTarget.style.paddingLeft='8px'; }} + onMouseLeave={e=>{ e.currentTarget.style.color=MUTED; e.currentTarget.style.paddingLeft='0'; }} + >{sub.label} +
  • + ))} +
  • +
+
+ ))} +
+ + {/* RIGHT — utilities */} +
+ +
+
+ {(['DE','EN'] as const).map((l,i) => ( + + {i===1 && |} + + + ))} +
+
+ {SOCIAL.map(s => )} +
+
+ +
+ {SECONDARY.map(item => ( + setOpen(false)} + style={{ fontSize: 16, color:MUTED, textDecoration:'none', fontFamily:FF_BODY, transition:'color .15s', width:'fit-content' }} + onMouseEnter={e=>(e.currentTarget.style.color=GOLD)} + onMouseLeave={e=>(e.currentTarget.style.color=MUTED)} + >{item.label} + ))} +
+ +
+ setOpen(false)} + style={{ display:'inline-block', background:'#EFBF04', color:'#101828', fontSize: 15, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'11px 24px', textDecoration:'none', transition:'background .2s, box-shadow .2s', borderRadius:0, fontFamily:FF_DISPLAY }} + onMouseEnter={e=>{ e.currentTarget.style.background='#FFD130'; e.currentTarget.style.boxShadow='0 0 18px rgba(239,191,4,0.65), 0 0 40px rgba(239,191,4,0.3)'; }} + onMouseLeave={e=>{ e.currentTarget.style.background='#EFBF04'; e.currentTarget.style.boxShadow='none'; }} + >Jetzt bewerben + setOpen(false)} + style={{ display:'inline-block', background:'transparent', color:MUTED, fontSize: 15, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'10px 24px', textDecoration:'none', transition:'border-color .2s, color .2s', borderRadius:0, fontFamily:FF_DISPLAY, border:'1.5px solid rgba(239,191,4,0.35)' }} + onMouseEnter={e=>{ e.currentTarget.style.borderColor='#EFBF04'; e.currentTarget.style.color='#EFBF04'; }} + onMouseLeave={e=>{ e.currentTarget.style.borderColor='rgba(239,191,4,0.35)'; e.currentTarget.style.color=MUTED; }} + >Mitglied werden + +
+ + setOpen(false)} + style={{ + display:'flex', alignItems:'center', gap:10, + background:'rgba(255,255,255,0.04)', + color:'rgba(255,255,255,0.45)', + fontSize:11, fontWeight:700, + textTransform:'uppercase', letterSpacing:'.14em', + padding:'10px 18px', + textDecoration:'none', + fontFamily:FF_DISPLAY, + border:'1px dashed rgba(255,255,255,0.15)', + transition:'color .2s, border-color .2s, background .2s', + }} + onMouseEnter={e=>{ + e.currentTarget.style.color='#fff'; + e.currentTarget.style.borderColor='rgba(255,255,255,0.4)'; + e.currentTarget.style.background='rgba(255,255,255,0.07)'; + }} + onMouseLeave={e=>{ + e.currentTarget.style.color='rgba(255,255,255,0.45)'; + e.currentTarget.style.borderColor='rgba(255,255,255,0.15)'; + e.currentTarget.style.background='rgba(255,255,255,0.04)'; + }} + > + Formular hochladen + +
+ +
+
+
+
+ + )} + + + {/* ═══════════════════════════════════════════════════════════ */} + {/* ══ MOBILE CHROME (<768px) — sidebar + accordion overlay ══ */} + {/* ═══════════════════════════════════════════════════════════ */} + {isMobile && ( + <> + {/* ── SIDEBAR ──────────────────────────────────── */} + + + {/* ── MOBILE OVERLAY (accordion) ───────────────── */} +
+ {/* Top bar */} +
+ setMobileOpen(false)} style={{ display:'flex', alignItems:'center', textDecoration:'none' }}> + BMP Logo + + - {/* Subnav accordion body */}
{item.sub && ( @@ -342,8 +589,8 @@ const Layout: React.FC = ({ children }) => {
    {item.sub.map(sub => (
  • - setOpen(false)} - style={{ display:'block', padding:'10px 0', textDecoration:'none', color:MUTED, fontSize:14, fontFamily:FF_BODY, minHeight:44, display:'flex', alignItems:'center' } as React.CSSProperties} + setMobileOpen(false)} + style={{ display:'flex', alignItems:'center', padding:'10px 0', textDecoration:'none', color:MUTED, fontSize:14, fontFamily:FF_BODY, minHeight:44 }} >{sub.label}
  • ))} @@ -358,13 +605,13 @@ const Layout: React.FC = ({ children }) => { {/* CTAs */}
    - setOpen(false)} + setMobileOpen(false)} style={{ display:'block', background:GOLD, color:'#101828', fontSize:14, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'13px 22px', textDecoration:'none', fontFamily:FF_DISPLAY, textAlign:'center' }} >Jetzt bewerben - setOpen(false)} + setMobileOpen(false)} style={{ display:'block', background:'transparent', color:MUTED, fontSize:14, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'12px 22px', textDecoration:'none', fontFamily:FF_DISPLAY, border:`1.5px solid rgba(239,191,4,0.35)`, textAlign:'center' }} >Mitglied werden - setOpen(false)} + setMobileOpen(false)} style={{ display:'flex', alignItems:'center', justifyContent:'center', gap:8, background:'rgba(255,255,255,0.04)', color:'rgba(255,255,255,0.5)', fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'.14em', padding:'12px 22px', textDecoration:'none', fontFamily:FF_DISPLAY, border:'1px dashed rgba(255,255,255,0.2)', textAlign:'center' }} > Formular hochladen
    @@ -372,7 +619,7 @@ const Layout: React.FC = ({ children }) => { {/* Secondary links */}
    {SECONDARY.map(item => ( - setOpen(false)} + setMobileOpen(false)} style={{ display:'inline-flex', alignItems:'center', minHeight:44, padding:'0 8px', fontSize:13, color:MUTED, textDecoration:'none', fontFamily:FF_BODY }} >{item.label} ))} @@ -384,268 +631,370 @@ const Layout: React.FC = ({ children }) => {
- ) : ( - /* ── DESKTOP: 3-column grid ────────────────── */ -
+ + )} - {/* LEFT: main nav */} -
-
    - {NAV.map((item, idx) => ( -
  • - setOpen(false)} - onMouseEnter={() => setActive(item.key)} - style={{ - display:'flex', alignItems:'center', justifyContent:'space-between', - padding:'16px 32px 16px 0', - textDecoration:'none', - color: activeKey === item.key ? GOLD : '#fff', - fontSize:'clamp(15px,1.4vw,20px)', - fontFamily:FF_DISPLAY, - fontWeight:600, textTransform:'uppercase', letterSpacing:'.03em', - transition:'color .15s, opacity .3s ease-out', - transform: open ? `translateX(${activeKey === item.key ? 6 : 0}px)` : 'translateX(-16px)', - opacity: open ? 1 : 0, - transitionDelay: open ? `${.04 + idx * .06}s` : '0s', - }} - > - {item.label} - - -
  • - ))} -
  • -
-
- - {/* MIDDLE: subnav panels */} -
- {NAV.map(item => ( -
-
Überblick
-
{item.subLabel}
-
    - {item.sub?.map(sub => ( -
  • - setOpen(false)} - style={{ display:'block', padding:'9px 0', textDecoration:'none', color:MUTED, fontSize:14, fontFamily:FF_BODY, transition:'color .15s, padding-left .15s' }} - onMouseEnter={e => { e.currentTarget.style.color = '#fff'; e.currentTarget.style.paddingLeft = '8px'; }} - onMouseLeave={e => { e.currentTarget.style.color = MUTED; e.currentTarget.style.paddingLeft = '0'; }} - >{sub.label} -
  • - ))} -
  • -
-
- ))} -
- - {/* RIGHT: utilities */} -
- - {/* Top row: close + logo */} -
- -
- BMP Logo -
-
- - {/* Bottom section */} -
- - {/* Lang + Social */} -
-
- {(['DE','EN'] as const).map((l, i) => ( - - {i === 1 && |} - - - ))} -
-
- {SOCIAL.map(s => )} -
-
- - {/* Secondary links */} -
- {SECONDARY.map(item => ( - setOpen(false)} - style={{ fontSize:13, color:MUTED, textDecoration:'none', fontFamily:FF_BODY, transition:'color .15s', width:'fit-content' }} - onMouseEnter={e => (e.currentTarget.style.color = GOLD)} - onMouseLeave={e => (e.currentTarget.style.color = MUTED)} - >{item.label} - ))} -
- - {/* CTAs */} -
- setOpen(false)} - style={{ display:'inline-block', background:GOLD, color:'#101828', fontSize:12, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'13px 28px', textDecoration:'none', fontFamily:FF_DISPLAY, transition:'background .2s, box-shadow .2s' }} - onMouseEnter={e => { e.currentTarget.style.background = '#FFD130'; e.currentTarget.style.boxShadow = '0 0 18px rgba(239,191,4,0.65), 0 0 40px rgba(239,191,4,0.3)'; }} - onMouseLeave={e => { e.currentTarget.style.background = GOLD; e.currentTarget.style.boxShadow = 'none'; }} - >Jetzt bewerben - setOpen(false)} - style={{ display:'inline-block', background:'transparent', color:MUTED, fontSize:12, fontWeight:700, textTransform:'uppercase', letterSpacing:'.12em', padding:'11px 26px', textDecoration:'none', fontFamily:FF_DISPLAY, border:`1.5px solid rgba(239,191,4,0.35)`, transition:'border-color .2s, color .2s' }} - onMouseEnter={e => { e.currentTarget.style.borderColor = GOLD; e.currentTarget.style.color = GOLD; }} - onMouseLeave={e => { e.currentTarget.style.borderColor = 'rgba(239,191,4,0.35)'; e.currentTarget.style.color = MUTED; }} - >Mitglied werden -
- setOpen(false)} - style={{ display:'flex', alignItems:'center', gap:10, background:'rgba(255,255,255,0.04)', color:'rgba(255,255,255,0.45)', fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'.14em', padding:'10px 18px', textDecoration:'none', fontFamily:FF_DISPLAY, border:'1px dashed rgba(255,255,255,0.15)', transition:'color .2s, border-color .2s, background .2s' }} - onMouseEnter={e => { e.currentTarget.style.color='#fff'; e.currentTarget.style.borderColor='rgba(255,255,255,0.4)'; e.currentTarget.style.background='rgba(255,255,255,0.07)'; }} - onMouseLeave={e => { e.currentTarget.style.color='rgba(255,255,255,0.45)'; e.currentTarget.style.borderColor='rgba(255,255,255,0.15)'; e.currentTarget.style.background='rgba(255,255,255,0.04)'; }} - > Formular hochladen -
- -
-
-
- )} -
{/* ── FLOATING CTA ─────────────────────────────── */} {location.pathname === '/' && !formVisible && ( { (e.currentTarget as HTMLElement).style.background = GOLD; (e.currentTarget as HTMLElement).style.color = '#101828'; }} - onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = NAVY; (e.currentTarget as HTMLElement).style.color = '#fff'; }} + onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = '#EFBF04'; (e.currentTarget as HTMLElement).style.color = '#101828'; }} + onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = '#111D55'; (e.currentTarget as HTMLElement).style.color = '#fff'; }} > Jetzt bewerben )} {/* ── MAIN ─────────────────────────────────────── */} -
{children}
+
{children}
{/* ── FOOTER ───────────────────────────────────── */} -
); };