Fertig, kein weißes flickern

This commit is contained in:
knuthtimo-lab 2025-09-16 14:16:00 +02:00
parent 3cbe01e458
commit b78438104c
3 changed files with 122 additions and 51 deletions

View File

@ -3,43 +3,60 @@ import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index"; import { Suspense, lazy } from "react";
import Services from "./pages/Services";
import About from "./pages/About"; // Lazy load pages for better performance
import ClientsProjects from "./pages/ClientsProjects"; const Index = lazy(() => import("./pages/Index"));
import Locations from "./pages/Locations"; const Services = lazy(() => import("./pages/Services"));
import Careers from "./pages/Careers"; const About = lazy(() => import("./pages/About"));
import Contact from "./pages/Contact"; const ClientsProjects = lazy(() => import("./pages/ClientsProjects"));
import Legal from "./pages/Legal"; const Locations = lazy(() => import("./pages/Locations"));
import Privacy from "./pages/Privacy"; const Careers = lazy(() => import("./pages/Careers"));
import Terms from "./pages/Terms"; const Contact = lazy(() => import("./pages/Contact"));
import NotFound from "./pages/NotFound"; const Legal = lazy(() => import("./pages/Legal"));
const Privacy = lazy(() => import("./pages/Privacy"));
const Terms = lazy(() => import("./pages/Terms"));
const NotFound = lazy(() => import("./pages/NotFound"));
const queryClient = new QueryClient(); const queryClient = new QueryClient();
// Loading component to prevent white flash
const PageLoader = () => (
<div className="flex min-h-screen items-center justify-center bg-background">
<div className="relative">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-accent"></div>
<div className="absolute inset-0 animate-pulse rounded-full h-12 w-12 border-2 border-accent/20"></div>
</div>
</div>
);
const App = () => ( const App = () => (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<TooltipProvider> <TooltipProvider>
<Toaster /> <Toaster />
<Sonner /> <Sonner />
<BrowserRouter> <BrowserRouter>
<Routes> <Suspense fallback={<PageLoader />}>
<Route path="/" element={<Index />} /> <div className="page-transition">
<Route path="/services-and-specialties" element={<Services />} /> <Routes>
<Route path="/about-us" element={<About />} /> <Route path="/" element={<Index />} />
<Route path="/clients-and-projects" element={<ClientsProjects />} /> <Route path="/services-and-specialties" element={<Services />} />
<Route path="/locations" element={<Locations />} /> <Route path="/about-us" element={<About />} />
<Route path="/careers" element={<Careers />} /> <Route path="/clients-and-projects" element={<ClientsProjects />} />
<Route path="/contact-us" element={<Contact />} /> <Route path="/locations" element={<Locations />} />
<Route path="/legal" element={<Legal />} /> <Route path="/careers" element={<Careers />} />
<Route path="/privacy" element={<Privacy />} /> <Route path="/contact-us" element={<Contact />} />
<Route path="/terms" element={<Terms />} /> <Route path="/legal" element={<Legal />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} <Route path="/privacy" element={<Privacy />} />
<Route path="*" element={<NotFound />} /> <Route path="/terms" element={<Terms />} />
</Routes> {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} />
</Routes>
</div>
</Suspense>
</BrowserRouter> </BrowserRouter>
</TooltipProvider> </TooltipProvider>
</QueryClientProvider> </QueryClientProvider>
); );
export default App; export default App;

View File

@ -1,10 +1,18 @@
import React from 'react'; import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Menu, X } from 'lucide-react'; import { Menu, X } from 'lucide-react';
import content from '@/content/content.json'; import content from '@/content/content.json';
const Header = () => { const Header = () => {
const [isOpen, setIsOpen] = React.useState(false); const [isOpen, setIsOpen] = React.useState(false);
const location = useLocation();
// Function to convert nav item to route path
const getRoutePath = (item: string) => {
if (item === 'Home') return '/';
return `/${item.toLowerCase().replace(/\s+/g, '-').replace('&', 'and')}`;
};
return ( return (
<> <>
@ -17,9 +25,9 @@ const Header = () => {
<span className="text-sm text-muted"> <span className="text-sm text-muted">
Professional welding services across Texas Get your quote today Professional welding services across Texas Get your quote today
</span> </span>
<a href="/contact-us" className="text-accent hover:text-accent/80 text-sm font-medium ml-2"> <Link to="/contact-us" className="text-accent hover:text-accent/80 text-sm font-medium ml-2">
Learn more Learn more
</a> </Link>
</div> </div>
</div> </div>
</div> </div>
@ -30,28 +38,34 @@ const Header = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="flex h-16 items-center justify-between"> <div className="flex h-16 items-center justify-between">
{/* Logo - IIT Logo */} {/* Logo - IIT Logo */}
<a href="/" className="flex items-center focus-ring rounded-md"> <Link to="/" className="flex items-center focus-ring rounded-md">
<img <img
src="/IIT-Logo-Web.png" src="/IIT-Logo-Web.png"
alt="IIT Welding" alt="IIT Welding"
className="h-10 w-auto" className="h-10 w-auto"
/> />
</a> </Link>
{/* Desktop Navigation - Dispel Style */} {/* Desktop Navigation - Dispel Style */}
<nav className="hidden md:flex items-center space-x-8" aria-label="Primary navigation"> <nav className="hidden md:flex items-center space-x-8" aria-label="Primary navigation">
{content.nav.map((item) => ( {content.nav.map((item) => {
<a const routePath = getRoutePath(item);
key={item} const isActive = location.pathname === routePath;
href={`/${item.toLowerCase().replace(/\s+/g, '-').replace('&', 'and')}`}
className="text-black hover:text-gray-600 transition-smooth focus-ring rounded-md px-2 py-1 font-medium" return (
> <Link
{item} key={item}
</a> to={routePath}
))} className={`text-black hover:text-gray-600 transition-smooth focus-ring rounded-md px-2 py-1 font-medium ${
isActive ? 'text-blue-600 font-semibold' : ''
}`}
>
{item}
</Link>
);
})}
</nav> </nav>
{/* Mobile Menu Button */} {/* Mobile Menu Button */}
<button <button
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
@ -67,16 +81,23 @@ const Header = () => {
{isOpen && ( {isOpen && (
<nav className="md:hidden py-4 border-t border-slate-600" aria-label="Mobile navigation"> <nav className="md:hidden py-4 border-t border-slate-600" aria-label="Mobile navigation">
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
{content.nav.map((item) => ( {content.nav.map((item) => {
<a const routePath = getRoutePath(item);
key={item} const isActive = location.pathname === routePath;
href={`/${item.toLowerCase().replace(/\s+/g, '-').replace('&', 'and')}`}
className="text-black hover:text-gray-600 transition-smooth focus-ring rounded-md px-2 py-2 font-medium" return (
onClick={() => setIsOpen(false)} <Link
> key={item}
{item} to={routePath}
</a> className={`text-black hover:text-gray-600 transition-smooth focus-ring rounded-md px-2 py-2 font-medium ${
))} isActive ? 'text-blue-600 font-semibold' : ''
}`}
onClick={() => setIsOpen(false)}
>
{item}
</Link>
);
})}
</div> </div>
</nav> </nav>
)} )}

View File

@ -71,15 +71,48 @@
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
/* Prevent layout shift and ensure consistent background */
overflow-x: hidden;
background-color: hsl(210 24% 8%) !important;
} }
body { body {
@apply bg-background text-foreground font-sans antialiased; @apply bg-background text-foreground font-sans antialiased;
color-scheme: dark; color-scheme: dark;
/* Prevent white flash during navigation */
background-color: hsl(210 24% 8%) !important;
min-height: 100vh;
}
/* Prevent flash of unstyled content */
#root {
background-color: hsl(210 24% 8%);
min-height: 100vh;
} }
} }
@layer components { @layer components {
/* Page transition styles */
.page-transition {
opacity: 1;
transition: opacity 0.2s ease-in-out;
background-color: hsl(210 24% 8%);
min-height: 100vh;
}
.page-transition-enter {
opacity: 0;
}
.page-transition-exit {
opacity: 1;
}
.page-transition-exit-active {
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
/* Hero section styling */ /* Hero section styling */
.hero-gradient { .hero-gradient {
background: var(--gradient-hero); background: var(--gradient-hero);
@ -860,4 +893,4 @@
transform: none; transform: none;
} }
} }
} }