Container-ready via docker/ compose (frontend nginx + backend Node). Compose adjusted for Coolify on the prod server: frontend uses expose:80 (no host binding — host 8080 is taken by the Coolify proxy; Traefik routes visigine.de), backend ALLOWED_ORIGINS=https://visigine.de. Secrets stay in server/.env (git-ignored); see server/.env.example. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
1.8 KiB
JavaScript
67 lines
1.8 KiB
JavaScript
import { useEffect } from 'react'
|
|
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom'
|
|
import Navigation from './components/Navigation/Navigation'
|
|
import Hero from './components/Hero/Hero'
|
|
import Features from './components/Features/Features'
|
|
import HowItWorks from './components/HowItWorks/HowItWorks'
|
|
import Analyzer from './components/Analyzer/Analyzer'
|
|
import Pricing from './components/Pricing/Pricing'
|
|
import Footer from './components/Footer/Footer'
|
|
import Impressum from './pages/Impressum'
|
|
import Datenschutz from './pages/Datenschutz'
|
|
import Admin from './pages/Admin'
|
|
import './App.css'
|
|
|
|
function HomePage() {
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach(e => {
|
|
if (e.isIntersecting) e.target.classList.add('visible')
|
|
})
|
|
},
|
|
{ threshold: 0.1 }
|
|
)
|
|
document.querySelectorAll('.reveal').forEach(el => observer.observe(el))
|
|
return () => observer.disconnect()
|
|
}, [])
|
|
|
|
return (
|
|
<main>
|
|
<Hero />
|
|
<Features />
|
|
<HowItWorks />
|
|
<Analyzer />
|
|
<Pricing />
|
|
</main>
|
|
)
|
|
}
|
|
|
|
function Layout() {
|
|
const location = useLocation()
|
|
const isLegal = location.pathname === '/impressum' || location.pathname === '/datenschutz'
|
|
const isAdmin = location.pathname === '/admin'
|
|
|
|
return (
|
|
<>
|
|
{!isAdmin && <Navigation />}
|
|
<Routes>
|
|
<Route path="/" element={<HomePage />} />
|
|
<Route path="/impressum" element={<Impressum />} />
|
|
<Route path="/datenschutz" element={<Datenschutz />} />
|
|
<Route path="/admin" element={<Admin />} />
|
|
</Routes>
|
|
{!isAdmin && !isLegal && <Footer />}
|
|
{isLegal && <Footer minimal />}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<BrowserRouter>
|
|
<Layout />
|
|
</BrowserRouter>
|
|
)
|
|
}
|