import { Link } from '@tanstack/react-router' import { Box, Burger, Container, Drawer, Group, Menu, SimpleGrid, Stack, Text, UnstyledButton, } from '@pikku/mantine/core' import { useDisclosure } from '@mantine/hooks' import { m } from '@/i18n/messages' import { useLocale, getLocale, type Locale } from '@/i18n/config' import { asI18n } from '@pikku/react' import { ChevronDown, Facebook, Instagram, Mail, Phone } from 'lucide-react' import { BrandMark } from './Brand' /** * Public-site chrome that mirrors seminarhof-drawehn.de (header + footer) so the * app's anonymous public pages (availability / events / enquiry) feel like one * cohesive website with the marketing site. Marketing destinations link out to * the live WordPress site; the app's own pages (events) stay internal. * * Nav labels are kept in German on purpose — they're the marketing site's * canonical labels (brand chrome), not app content. The DE/EN switcher toggles * the app's i18n language, which drives the page body, not these labels. * * Social/contact glyphs use lucide-react (the app's icon set) — the closest * equivalent to the live site's Font Awesome icons, not pixel-identical. */ const SITE = 'https://seminarhof-drawehn.de' const PHONE_HREF = 'tel:+491724695132' const PHONE_LABEL = '+49 172 4695132' const EMAIL = 'info@seminarhof-drawehn.de' const TAGLINE = 'Retreats · Fortbildungen · Workation' type NavChild = { label: string; href: string; internal?: boolean } type NavEntry = { label: string; href: string; internal?: boolean; children?: NavChild[] } const ext = (path: string) => `${SITE}${path}` const LEFT_NAV: NavEntry[] = [ { label: 'Unser Seminarhof', href: ext('/seminarhof/'), children: [ { label: 'Seminarräume', href: ext('/seminarhof/') }, { label: 'Verpflegung', href: ext('/verpflegung/') }, { label: 'Unterkunft', href: ext('/unterkunft/') }, { label: 'Holistic Bodywork', href: ext('/holistic-bodywork/') }, ], }, { label: 'Anreise', href: ext('/anreise/') }, { label: 'Galerie', href: ext('/galerie/') }, { label: 'FAQ', href: ext('/faq/') }, ] const RIGHT_NAV: NavEntry[] = [ { label: 'Veranstaltungen', href: '/events', internal: true }, { label: 'Kontakt', href: ext('/kontakt/'), children: [ { label: 'Kontakt', href: ext('/kontakt/') }, { label: 'Über uns', href: ext('/ueber-uns/') }, { label: 'Gästebuch', href: ext('/gaestebuch/') }, { label: 'Jobs', href: ext('/jobs/') }, ], }, { label: 'Downloads', href: ext('/downloads/') }, ] const FOOTER_COLUMNS: { heading: string; links: NavChild[] }[] = [ { heading: 'Unser Seminarhof', links: [ { label: 'Seminarräume', href: ext('/seminarhof/') }, { label: 'Verpflegung', href: ext('/verpflegung/') }, { label: 'Unterkunft', href: ext('/unterkunft/') }, ], }, { heading: 'Angebote', links: [ { label: 'Veranstaltungen', href: '/events', internal: true }, { label: 'Holistic Bodywork', href: ext('/holistic-bodywork/') }, { label: 'Jobs', href: ext('/jobs/') }, ], }, { heading: 'Info', links: [ { label: 'FAQ', href: ext('/faq/') }, { label: 'Kontakt', href: ext('/kontakt/') }, { label: 'Downloads', href: ext('/downloads/') }, ], }, { heading: 'Rechtliches', links: [ { label: 'Impressum', href: ext('/impressum/') }, { label: 'Datenschutz', href: ext('/datenschutz/') }, ], }, ] const NAV_ITEM_STYLE: React.CSSProperties = { color: '#ffffff', fontFamily: "'Open Sans', sans-serif", fontSize: '14.4px', fontWeight: 400, textDecoration: 'none', lineHeight: 1, cursor: 'pointer', background: 'none', border: 'none', padding: 0, } /** A single top-level nav entry: plain external/internal link, or a hover menu. */ function NavTopItem({ entry, onNavigate }: { entry: NavEntry; onNavigate?: () => void }) { if (entry.children) { return ( {entry.label} {entry.children.map((c) => { const itemStyle = { color: '#ffffff', fontFamily: "'Open Sans', sans-serif", fontSize: '14px' } return c.internal ? ( {asI18n(`${c.label}`)} ) : ( {asI18n(`${c.label}`)} ) })} ) } if (entry.internal) { return ( {entry.label} ) } return ( {entry.label} ) } function LanguageSwitcher() { const { setLocale } = useLocale() const current = (getLocale() || 'de').slice(0, 2).toUpperCase() return ( {current} {['de', 'en'].map((lng) => ( setLocale(lng as Locale)} style={{ color: '#ffffff', fontFamily: "'Open Sans', sans-serif", fontSize: '14px' }} > {asI18n(`${lng.toUpperCase()}`)} ))} ) } function SocialIcons({ color = '#ffffff', size = 18 }: { color?: string; size?: number }) { const link = { color, display: 'flex' } as React.CSSProperties return ( ) } const BRAND_STYLE: React.CSSProperties = { fontFamily: "'Nunito', sans-serif", fontWeight: 500, fontSize: '32px', color: '#ffffff', textDecoration: 'none', lineHeight: 1, whiteSpace: 'nowrap', } export function SeminarhofHeader() { useLocale() const [opened, { toggle, close }] = useDisclosure(false) return ( // display:contents so the sticky nav row below isn't trapped in this short // header's containing block — its sticky context becomes the full-height // MarketingShell column, giving page-wide sticky behaviour. {/* Top utility bar */} {asI18n(`${TAGLINE}`)} {PHONE_LABEL} {EMAIL} {/* Sticky nav row */} {/* Left group (desktop) */} {LEFT_NAV.map((e) => ( ))} {/* Mobile burger */} {/* Mobile brand — in-flow so it can't overlap the burger / switcher */} Seminarhof Drawehn {/* Right group (desktop) */} {RIGHT_NAV.map((e) => ( ))} {/* Mobile: language switcher stays visible on the right */} {/* Centered brand (desktop) — absolutely positioned so it stays centred regardless of the left/right group widths. On mobile the in-flow brand above is used instead, to avoid overlap. */} Seminarhof Drawehn {/* Mobile drawer */} {[...LEFT_NAV, ...RIGHT_NAV].map((e) => e.children ? ( {asI18n(`${e.label}`)} {e.children.map((c) => ( ))} ) : ( ) )} ) } function DrawerLink({ child, onNavigate, indent, }: { child: NavChild onNavigate: () => void indent?: boolean }) { const style: React.CSSProperties = { color: '#ffffff', fontFamily: "'Open Sans', sans-serif", fontSize: 16, textDecoration: 'none', paddingLeft: indent ? 12 : 0, } return child.internal ? ( {child.label} ) : ( {child.label} ) } export function SeminarhofFooter() { useLocale() const year = new Date().getFullYear() const footerLinkStyle: React.CSSProperties = { color: '#ffffff', fontFamily: "'Open Sans', sans-serif", fontSize: 15, textDecoration: 'none', } return ( {/* Link columns band */} {FOOTER_COLUMNS.map((col) => ( {asI18n(`${col.heading}`)} {col.links.map((l) => l.internal ? ( {l.label} ) : ( {l.label} ) )} ))} {/* Copyright band */} {asI18n(`© ${year} `)}{m.common__brand__name()} {/* Centered wheel logo */} ) }