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 { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import Services from "./pages/Services";
import About from "./pages/About";
import ClientsProjects from "./pages/ClientsProjects";
import Locations from "./pages/Locations";
import Careers from "./pages/Careers";
import Contact from "./pages/Contact";
import Legal from "./pages/Legal";
import Privacy from "./pages/Privacy";
import Terms from "./pages/Terms";
import NotFound from "./pages/NotFound";
import { Suspense, lazy } from "react";
// Lazy load pages for better performance
const Index = lazy(() => import("./pages/Index"));
const Services = lazy(() => import("./pages/Services"));
const About = lazy(() => import("./pages/About"));
const ClientsProjects = lazy(() => import("./pages/ClientsProjects"));
const Locations = lazy(() => import("./pages/Locations"));
const Careers = lazy(() => import("./pages/Careers"));
const Contact = lazy(() => import("./pages/Contact"));
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();
// 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 = () => (
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<Toaster />
<Sonner />
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/services-and-specialties" element={<Services />} />
<Route path="/about-us" element={<About />} />
<Route path="/clients-and-projects" element={<ClientsProjects />} />
<Route path="/locations" element={<Locations />} />
<Route path="/careers" element={<Careers />} />
<Route path="/contact-us" element={<Contact />} />
<Route path="/legal" element={<Legal />} />
<Route path="/privacy" element={<Privacy />} />
<Route path="/terms" element={<Terms />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} />
</Routes>
<Suspense fallback={<PageLoader />}>
<div className="page-transition">
<Routes>
<Route path="/" element={<Index />} />
<Route path="/services-and-specialties" element={<Services />} />
<Route path="/about-us" element={<About />} />
<Route path="/clients-and-projects" element={<ClientsProjects />} />
<Route path="/locations" element={<Locations />} />
<Route path="/careers" element={<Careers />} />
<Route path="/contact-us" element={<Contact />} />
<Route path="/legal" element={<Legal />} />
<Route path="/privacy" element={<Privacy />} />
<Route path="/terms" element={<Terms />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} />
</Routes>
</div>
</Suspense>
</BrowserRouter>
</TooltipProvider>
</QueryClientProvider>
);
export default App;
export default App;

View File

@ -1,10 +1,18 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Menu, X } from 'lucide-react';
import content from '@/content/content.json';
const Header = () => {
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 (
<>
@ -17,9 +25,9 @@ const Header = () => {
<span className="text-sm text-muted">
Professional welding services across Texas Get your quote today
</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
</a>
</Link>
</div>
</div>
</div>
@ -30,28 +38,34 @@ const Header = () => {
<div className="container mx-auto px-4">
<div className="flex h-16 items-center justify-between">
{/* Logo - IIT Logo */}
<a href="/" className="flex items-center focus-ring rounded-md">
<Link to="/" className="flex items-center focus-ring rounded-md">
<img
src="/IIT-Logo-Web.png"
alt="IIT Welding"
className="h-10 w-auto"
/>
</a>
</Link>
{/* Desktop Navigation - Dispel Style */}
<nav className="hidden md:flex items-center space-x-8" aria-label="Primary navigation">
{content.nav.map((item) => (
<a
key={item}
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"
>
{item}
</a>
))}
{content.nav.map((item) => {
const routePath = getRoutePath(item);
const isActive = location.pathname === routePath;
return (
<Link
key={item}
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>
{/* Mobile Menu Button */}
<button
onClick={() => setIsOpen(!isOpen)}
@ -67,16 +81,23 @@ const Header = () => {
{isOpen && (
<nav className="md:hidden py-4 border-t border-slate-600" aria-label="Mobile navigation">
<div className="flex flex-col space-y-4">
{content.nav.map((item) => (
<a
key={item}
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"
onClick={() => setIsOpen(false)}
>
{item}
</a>
))}
{content.nav.map((item) => {
const routePath = getRoutePath(item);
const isActive = location.pathname === routePath;
return (
<Link
key={item}
to={routePath}
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>
</nav>
)}

View File

@ -71,15 +71,48 @@
html {
scroll-behavior: smooth;
/* Prevent layout shift and ensure consistent background */
overflow-x: hidden;
background-color: hsl(210 24% 8%) !important;
}
body {
@apply bg-background text-foreground font-sans antialiased;
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 {
/* 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-gradient {
background: var(--gradient-hero);
@ -860,4 +893,4 @@
transform: none;
}
}
}
}