import { useEffect, useRef, useState } from "react"; import Preloader from "./components/Preloader"; import AgeGate from "./components/AgeGate"; import Header from "./components/Header"; import Hero from "./components/Hero"; import AtmosphereCarousel from "./components/AtmosphereCarousel"; import MenuCarousel from "./components/MenuCarousel"; import VipCalculator from "./components/VipCalculator"; import Features from "./components/Features"; import Contacts from "./components/Contacts"; import Footer from "./components/Footer"; import FlavorsPage from "./pages/FlavorsPage"; import GamesPage from "./pages/GamesPage"; import MixesPage from "./pages/MixesPage"; import AiMixPage from "./pages/AiMixPage"; import BoardGamesPage from "./pages/BoardGamesPage"; import MenuPage from "./pages/MenuPage"; import TrackOrderPage from "./pages/TrackOrderPage"; import { useHashLocation } from "./hooks/useHashLocation"; import { isPrerender } from "./lib/prerender"; type CatalogPage = "flavors" | "games" | "mixes" | "ai-mix" | "board-games" | "menu" | "track" | null; function getCatalogPage(hash: string): CatalogPage { if (hash === "#/flavors") return "flavors"; if (hash === "#/games") return "games"; if (hash === "#/mixes") return "mixes"; if (hash === "#/ai-mix" || hash === "#/mix-builder") return "ai-mix"; if (hash.startsWith("#mix=")) return "ai-mix"; // share-ссылка на генерацию if (hash === "#/board-games") return "board-games"; if (hash === "#/menu" || hash === "#/tea") return "menu"; if (hash.startsWith("#/track")) return "track"; // #/track и #/track?code=XXX return null; } export default function App() { const [loaded, setLoaded] = useState(false); const hash = useHashLocation(); const catalogPage = getCatalogPage(hash); const isCatalog = catalogPage !== null; const wasCatalog = useRef(isCatalog); const homeTitle = useRef(document.title); // в пререндер-снапшоте рендерим финальное видимое состояние страницы const prerender = isPrerender(); const started = loaded || prerender; useEffect(() => { const previousOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; const t = setTimeout(() => { document.body.style.overflow = previousOverflow; setLoaded(true); }, 2450); return () => { clearTimeout(t); document.body.style.overflow = previousOverflow; }; }, []); useEffect(() => { if (catalogPage === "flavors") { document.title = "Вкусы табака | НЕОН, Нягань"; } else if (catalogPage === "games") { document.title = "Игры PS5 | НЕОН, Нягань"; } else if (catalogPage === "mixes") { document.title = "Миксы кальянов | НЕОН, Нягань"; } else if (catalogPage === "ai-mix") { document.title = "Автоподбор микса | НЕОН, Нягань"; } else if (catalogPage === "board-games") { document.title = "Настольные игры | НЕОН, Нягань"; } else if (catalogPage === "menu") { document.title = "Меню бара: Авторский чай и Пивная карта | НЕОН, Нягань"; } else if (catalogPage === "track") { document.title = "Статус заказа | НЕОН, Нягань"; } else { document.title = homeTitle.current; } }, [catalogPage]); useEffect(() => { if (!loaded) return; const returningToHome = wasCatalog.current && !isCatalog; wasCatalog.current = isCatalog; if (catalogPage === "flavors") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("flavors-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "games") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("games-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "mixes") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("mixes-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "ai-mix") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("ai-mix-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "board-games") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("board-games-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "menu") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("menu-page-title")?.focus({ preventScroll: true }); return; } if (catalogPage === "track") { window.scrollTo({ top: 0, behavior: "instant" }); document.getElementById("track-title")?.focus({ preventScroll: true }); return; } // The landing section mounts after the hash changes when leaving the catalog. const section = document.getElementById(hash.slice(1) || "home"); if (!section) return; const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; section.scrollIntoView({ block: "start", behavior: returningToHome || reducedMotion ? "instant" : "smooth", }); if (returningToHome) { section.tabIndex = -1; section.focus({ preventScroll: true }); } }, [hash, catalogPage, isCatalog, loaded]); return (