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:
parent
9d71c16883
commit
873c5e53af
|
|
@ -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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ const PUBLIC_PREFIXES = [
|
|||
const PUBLIC_EXACT_PATHS = ['/']
|
||||
|
||||
// Reserved subdomains that shouldn't be treated as tenant slugs
|
||||
const RESERVED_SUBDOMAINS = ['www', 'app', 'admin', 'localhost', 'superadmin', 'api']
|
||||
const RESERVED_SUBDOMAINS = [
|
||||
'www', 'app', 'admin', 'localhost', 'superadmin', 'api',
|
||||
'logo.png', 'favicon.ico', 'robots.txt', 'sitemap.xml',
|
||||
'apple-touch-icon', 'android-chrome', 'manifest'
|
||||
]
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const url = request.nextUrl
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
google-site-verification: googleccd5315437d68a49.html
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
> build
|
||||
> turbo build
|
||||
|
||||
Turborepo did not find the correct binary for your platform.
|
||||
We will attempt to install it now.
|
||||
Installation has succeeded.
|
||||
|
||||
Attention:
|
||||
Turborepo now collects completely anonymous telemetry regarding usage.
|
||||
This information is used to shape the Turborepo roadmap and prioritize features.
|
||||
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
|
||||
https://turborepo.dev/docs/telemetry
|
||||
|
||||
• turbo 2.8.10
|
||||
• Packages in scope: @innungsapp/admin, @innungsapp/mobile, @innungsapp/shared
|
||||
• Running build in 3 packages
|
||||
• Remote caching disabled
|
||||
@innungsapp/admin:build: cache miss, executing 680b5ccc77f9c5aa
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: > @innungsapp/admin@0.1.0 build /mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin
|
||||
@innungsapp/admin:build: > next build
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: Downloading swc package @next/swc-linux-x64-gnu... to /home/tknuth/.cache/next-swc
|
||||
@innungsapp/admin:build: Downloading swc package @next/swc-linux-x64-musl... to /home/tknuth/.cache/next-swc
|
||||
@innungsapp/admin:build: ▲ Next.js 15.3.4
|
||||
@innungsapp/admin:build: - Environments: .env.local
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: Creating an optimized production build ...
|
||||
@innungsapp/admin:build: glob error [Error: EIO: i/o error, scandir '/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin/node_modules/next/dist/esm/client/dev/error-overlay'] {
|
||||
@innungsapp/admin:build: errno: -5,
|
||||
@innungsapp/admin:build: code: 'EIO',
|
||||
@innungsapp/admin:build: syscall: 'scandir',
|
||||
@innungsapp/admin:build: path: '/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin/node_modules/next/dist/esm/client/dev/error-overlay'
|
||||
@innungsapp/admin:build: }
|
||||
@innungsapp/admin:build: <w> [webpack.cache.PackFileCacheStrategy] Restoring pack from /mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin/.next/cache/webpack/server-production.pack failed: Error: No such label 'restore cache container' for WebpackLogger.timeEnd()
|
||||
@innungsapp/admin:build: Failed to compile.
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: Error: EIO: i/o error, scandir '/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin/node_modules/next/dist/esm/client/dev/error-overlay'
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: HookWebpackError: Cannot read properties of undefined (reading 'server')
|
||||
@innungsapp/admin:build: at makeWebpackError (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:29:315788)
|
||||
@innungsapp/admin:build: at /mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:29:106487
|
||||
@innungsapp/admin:build: at eval (eval at create (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:14:9224), <anonymous>:20:1)
|
||||
@innungsapp/admin:build: -- inner error --
|
||||
@innungsapp/admin:build: TypeError: Cannot read properties of undefined (reading 'server')
|
||||
@innungsapp/admin:build: at FlightClientEntryPlugin.createActionAssets (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/build/webpack/plugins/flight-client-entry-plugin.js:665:68)
|
||||
@innungsapp/admin:build: at /mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/build/webpack/plugins/flight-client-entry-plugin.js:170:25
|
||||
@innungsapp/admin:build: at fn (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:29:70201)
|
||||
@innungsapp/admin:build: at _next7 (eval at create (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:14:9224), <anonymous>:12:17)
|
||||
@innungsapp/admin:build: at eval (eval at create (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:14:9224), <anonymous>:31:1)
|
||||
@innungsapp/admin:build: caused by plugins in Compilation.hooks.processAssets
|
||||
@innungsapp/admin:build: TypeError: Cannot read properties of undefined (reading 'server')
|
||||
@innungsapp/admin:build: at FlightClientEntryPlugin.createActionAssets (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/build/webpack/plugins/flight-client-entry-plugin.js:665:68)
|
||||
@innungsapp/admin:build: at /mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/build/webpack/plugins/flight-client-entry-plugin.js:170:25
|
||||
@innungsapp/admin:build: at fn (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:29:70201)
|
||||
@innungsapp/admin:build: at _next7 (eval at create (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:14:9224), <anonymous>:12:17)
|
||||
@innungsapp/admin:build: at eval (eval at create (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/node_modules/.pnpm/next@15.3.4_babel-plugin-react-compiler@1.0.0_react-dom@19.0.0_react@19.0.0__react@19.0.0/node_modules/next/dist/compiled/webpack/bundle5.js:14:9224), <anonymous>:31:1)
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build:
|
||||
@innungsapp/admin:build: > Build failed because of webpack errors
|
||||
@innungsapp/admin:build: ELIFECYCLE Command failed with exit code 1.
|
||||
@innungsapp/admin:build: ERROR: command finished with error: command (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin) /mnt/c/Users/a931627/AppData/Roaming/npm/pnpm run build exited (1)
|
||||
@innungsapp/admin#build: command (/mnt/c/Users/a931627/Documents/stadtwerke-saas-analysis/innungsapp/apps/admin) /mnt/c/Users/a931627/AppData/Roaming/npm/pnpm run build exited (1)
|
||||
|
||||
Tasks: 0 successful, 1 total
|
||||
Cached: 0 cached, 1 total
|
||||
Time: 5m33.353s
|
||||
Failed: @innungsapp/admin#build
|
||||
|
||||
ERROR run failed: command exited (1)
|
||||
Loading…
Reference in New Issue