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 (
);
}