feat: Implement Next.js middleware for subdomain-based tenant routing and authentication, create the admin application's main page, and add Google site verification.

This commit is contained in:
Timo Knuth
2026-03-02 23:01:21 +01:00
parent 9d71c16883
commit 873c5e53af
4 changed files with 155 additions and 9 deletions

View File

@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import { Syne } from 'next/font/google'
import { ArrowRight, ArrowUpRight, Sun, Moon } from 'lucide-react'
import { ArrowRight, ArrowUpRight, Sun, Moon, Menu, X } from 'lucide-react'
const syne = Syne({ subsets: ['latin'], weight: ['400', '500', '600', '700', '800'] })
@@ -57,6 +57,7 @@ export default function RootPage() {
const [openFaq, setOpenFaq] = useState<number | null>(null);
const [cookieConsent, setCookieConsent] = useState<CookieConsentState>('loading')
const [showMailFallback, setShowMailFallback] = useState(false)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
useEffect(() => {
setMounted(true);
@@ -625,10 +626,67 @@ export default function RootPage() {
color: var(--gold); font-weight: 500; margin-bottom: 20px;
}
/* Mobile Navigation */
.nav-mobile-toggle { display: none; }
@media (max-width: 767px) {
.nav-mobile-toggle { display: flex; align-items: center; cursor: pointer; }
.nav-menu-btn {
background: none;
border: none;
cursor: pointer;
color: var(--ink);
padding: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.nav-links {
display: none;
position: fixed;
top: 64px;
left: 0;
right: 0;
background: var(--bg);
border-bottom: 1px solid var(--ink-faint);
padding: 24px 32px;
flex-direction: column;
gap: 12px;
z-index: 40;
}
.nav-links-mobile-open { display: flex !important; }
.nav-link { display: block; }
}
/* Improved Mobile Responsiveness */
@media (max-width: 639px) {
.nav-links .nav-link { display: none; }
.stat { border-right: none; padding-right: 0; }
.stat:nth-child(odd) { border-right: 1px solid var(--ink-faint); padding-right: 16px; }
.nav-inner { padding: 0 16px; }
.hero { padding: 120px 16px 60px; }
.hero-h1 { font-size: clamp(2rem, 6vw, 3.25rem); }
.hero-body { gap: 24px; }
.hero-image-wrapper { aspect-ratio: 1; }
.stats { grid-template-columns: repeat(2, 1fr); margin-top: 60px; }
.stat { padding: 20px 16px; border-right: none; border-bottom: 1px solid var(--ink-faint); }
.stat:nth-child(2n) { border-right: 1px solid var(--ink-faint); }
.stat:nth-last-child(-n+2) { border-bottom: none; }
.challenges-section { padding: 60px 0; }
.challenges-inner { padding: 0 16px; }
.challenges-grid { gap: 20px; }
.challenge-card { padding: 20px; }
.features { padding: 60px 0; }
.features-inner { padding: 0 16px; gap: 40px; }
.feature-item { padding: 20px 16px; gap: 16px; flex-direction: column; }
.feature-num { font-size: 2rem; min-width: auto; }
.comparison-section { padding: 60px 0; }
.comparison-inner { padding: 0 16px; }
.comp-card { padding: 20px; }
.cta-section { padding: 60px 0 80px; }
.cta-inner { padding: 0 16px; }
.aeo-section { padding: 60px 0; }
.aeo-inner { padding: 0 16px; }
.faq-section { padding: 60px 0; }
.faq-inner { padding: 0 16px; }
.footer { padding: 24px 0; }
.footer-inner { padding: 0 16px; }
}
`}</style>
@@ -639,8 +697,17 @@ export default function RootPage() {
<div className="logo">
Innungs<span className="logo-accent">App</span> <span className="logo-pro">PRO</span>
</div>
<div className="nav-links">
<a href="#leistungen" className="nav-link">Leistungen</a>
<div className="nav-mobile-toggle">
<button
className="nav-menu-btn"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="Navigation toggle"
>
{mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
<div className={`nav-links ${mobileMenuOpen ? 'nav-links-mobile-open' : ''}`}>
<a href="#leistungen" className="nav-link" onClick={() => setMobileMenuOpen(false)}>Leistungen</a>
<button
onClick={toggleTheme}
@@ -651,11 +718,14 @@ export default function RootPage() {
{theme === 'theme-dark' ? <Sun size={18} /> : <Moon size={18} />}
</button>
<Link href="/login" className="nav-link">Login</Link>
<Link href="/login" className="nav-link" onClick={() => setMobileMenuOpen(false)}>Login</Link>
<a
href={CONTACT_WEBMAIL_HREF}
className="btn-primary"
onClick={() => handleContactCtaClick('nav')}
onClick={() => {
handleContactCtaClick('nav')
setMobileMenuOpen(false)
}}
target="_blank"
rel="noreferrer"
>