import React, { Suspense, useEffect, useRef } from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate, useLocation } from 'react-router-dom'; import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import { ScrollToPlugin } from 'gsap/ScrollToPlugin'; import Navbar from './components/Navbar'; import Footer from './components/Footer'; import BackToTop from './components/BackToTop'; import { BlogSeoRoute, LocationSeoRoute, ServiceSeoRoute, blogRoutes, locationRoutes, serviceRoutes, legacyRedirects } from './src/routes/seoRoutes'; // Register GSAP plugins globally gsap.registerPlugin(ScrollTrigger, ScrollToPlugin); import HomePage from './src/pages/HomePage'; const AboutPage = React.lazy(() => import('./src/pages/AboutPage')); const ServicesPage = React.lazy(() => import('./src/pages/ServicesPage')); const BlogPage = React.lazy(() => import('./src/pages/BlogPage')); const ContactPage = React.lazy(() => import('./src/pages/ContactPage')); const LocationsPage = React.lazy(() => import('./src/pages/LocationsPage')); const PrivacyPolicyPage = React.lazy(() => import('./src/pages/PrivacyPolicyPage')); const TermsOfServicePage = React.lazy(() => import('./src/pages/TermsOfServicePage')); // Grain Overlay Component const GrainOverlay = () => (
); const RouteFallback = () => (
Loading page...
); const AppContent: React.FC = () => { const location = useLocation(); const lenisRef = useRef(null); useEffect(() => { if (typeof window === 'undefined') { return; } const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); const finePointer = window.matchMedia('(pointer: fine) and (hover: hover)'); if (prefersReducedMotion.matches || !finePointer.matches) { return; } let active = true; let ticker: ((time: number) => void) | null = null; void import('@studio-freight/lenis').then(({ default: Lenis }) => { if (!active) { return; } const lenis = new Lenis({ duration: 1.2, easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), direction: 'vertical', gestureDirection: 'vertical', smooth: true, smoothTouch: false, touchMultiplier: 2, } as any); lenisRef.current = lenis; lenis.on('scroll', ScrollTrigger.update); ticker = (time: number) => { lenis.raf(time * 1000); }; gsap.ticker.add(ticker); gsap.ticker.lagSmoothing(0); }); return () => { active = false; if (ticker) { gsap.ticker.remove(ticker); } lenisRef.current?.destroy(); lenisRef.current = null; }; }, []); useEffect(() => { lenisRef.current?.scrollTo(0, { immediate: true }); }, [location.pathname]); return (
}> } /> } /> } /> } /> } /> } /> } /> } /> {/* SEO Location Pages */} {locationRoutes.map((data) => ( } /> ))} {/* SEO Service Pages */} {serviceRoutes.map((data) => ( } /> ))} {/* Authority Blog Posts */} {blogRoutes.map((data) => ( } /> ))} {/* Legacy URL redirects — preserve old flat URLs */} {legacyRedirects.map(({ from, to }) => ( } /> ))}
); }; export default function App() { return ( ); }