banner and intro fix

This commit is contained in:
Kismet Hasanaj
2026-05-03 01:06:11 +02:00
parent af798cc58c
commit d66c54088a
4 changed files with 106 additions and 32 deletions
+54 -23
View File
@@ -31,6 +31,8 @@ import { openCookieBanner } from "@/components/CookieBanner";
// Type for the mouse-pointer position used to move the background glow.
type PointerState = { x: number; y: number };
const INTRO_SEEN_KEY = "novarix-intro-seen";
const INTRO_EVENT = "novarix:start-intro";
export default function HomePage() {
// ---------------------------------------------------------------------------
@@ -40,43 +42,72 @@ export default function HomePage() {
// pointer — the mouse position (in % of page width/height). Used by the
// soft glow that follows the cursor in the background.
// ---------------------------------------------------------------------------
const [showIntro, setShowIntro] = useState(false);
const [showIntro, setShowIntro] = useState(() => {
if (typeof document === "undefined") return false;
return document.documentElement.dataset.showIntro === "1";
});
const [pointer, setPointer] = useState<PointerState>({ x: 50, y: 22 });
// ---------------------------------------------------------------------------
// INTRO OVERLAY EFFECT
// Plays the animated logo + wordmark the first time someone visits the
// site in this browser tab. We remember they've seen it using
// sessionStorage so it doesn't replay on every navigation. The intro lasts
// a little under 4 seconds, with a softer fade into the main page.
// site in this browser tab. We decide before hydration whether to play it,
// which avoids the homepage flashing briefly before the intro appears.
// After the user accepts cookies on their first visit, we trigger the intro
// immediately from the banner close action.
// ---------------------------------------------------------------------------
useEffect(() => {
function playIntro() {
document.documentElement.dataset.showIntro = "1";
setShowIntro(true);
try {
window.sessionStorage.setItem(INTRO_SEEN_KEY, "true");
} catch {
/* storage unavailable — silently ignore */
}
const timer = window.setTimeout(() => {
document.documentElement.dataset.showIntro = "0";
setShowIntro(false);
}, 3950);
return timer;
}
let timer: number | null = null;
try {
const introSeen = window.sessionStorage.getItem("novarix-intro-seen");
// Only set the "seen" flag if the user has accepted cookies. Without
// consent we still play the intro — we just don't remember it played.
const introSeen = window.sessionStorage.getItem(INTRO_SEEN_KEY);
const consent = window.localStorage.getItem("novarix-cookie-consent");
const shouldPlayNow =
document.documentElement.dataset.showIntro === "1" &&
consent === "ack" &&
!introSeen;
if (!introSeen) {
// Sync once with sessionStorage on first client mount.
if (shouldPlayNow) {
timer = playIntro();
} else {
document.documentElement.dataset.showIntro = "0";
// eslint-disable-next-line react-hooks/set-state-in-effect
setShowIntro(true);
if (consent === "ack") {
window.sessionStorage.setItem("novarix-intro-seen", "true");
}
// The SVG's built-in stroke + fill animation lasts ~3s.
// We hold a little longer so the page underneath can ease in while
// the overlay fades away.
const timer = window.setTimeout(() => {
setShowIntro(false);
}, 3950);
return () => window.clearTimeout(timer);
setShowIntro(false);
}
} catch {
/* storage unavailable — silently skip the intro */
document.documentElement.dataset.showIntro = "0";
// eslint-disable-next-line react-hooks/set-state-in-effect
setShowIntro(false);
}
function handleStartIntro() {
if (timer !== null) window.clearTimeout(timer);
timer = playIntro();
}
window.addEventListener(INTRO_EVENT, handleStartIntro);
return () => {
if (timer !== null) window.clearTimeout(timer);
window.removeEventListener(INTRO_EVENT, handleStartIntro);
};
}, []);
// ---------------------------------------------------------------------------