Corrige l'overlay de chargement bloqué en navigation, l'ajoute au CV

- L'intro se rendait puis se retirait selon le pathname, laissant un
  overlay opaque figé au retour vers l'accueil depuis /cv
- Overlay conservé sur / et /cv : le nœud DOM persiste, le display:none
  posé par GSAP tient
- L'animation d'intro (F + barre + balayage) se joue aussi sur /cv

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3hzMzvei419MwkKFZkvMX
This commit is contained in:
franck 2026-09-08 19:52:29 +04:00
parent ec005b1622
commit 3352651d33

View file

@ -4,6 +4,9 @@ import { useEffect } from "react";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import gsap from "gsap"; import gsap from "gsap";
// Pages qui ont l'écran de chargement (avec/sans slash final selon la config).
const WITH_INTRO = new Set(["/", "/cv", "/cv/"]);
export default function Intro() { export default function Intro() {
const pathname = usePathname(); const pathname = usePathname();
@ -12,17 +15,18 @@ export default function Intro() {
const reveal = gsap.utils.toArray<HTMLElement>("[data-reveal]"); const reveal = gsap.utils.toArray<HTMLElement>("[data-reveal]");
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
// No reveal targets (e.g. error / not-found pages) or reduced motion: skip the intro. if (reduce) {
if (reduce || reveal.length === 0) {
gsap.set(overlay, { display: "none" }); gsap.set(overlay, { display: "none" });
return; return;
} }
gsap.set(reveal, { autoAlpha: 0, y: 12 }); if (reveal.length) gsap.set(reveal, { autoAlpha: 0, y: 12 });
const tl = gsap.timeline({ const tl = gsap.timeline({
defaults: { ease: "power3.out" }, defaults: { ease: "power3.out" },
onComplete: () => gsap.set(reveal, { clearProps: "all" }), onComplete: () => {
if (reveal.length) gsap.set(reveal, { clearProps: "all" });
},
}); });
tl.to("[data-intro-mark]", { autoAlpha: 1, scale: 1, duration: 0.45, ease: "power2.out" }, 0) tl.to("[data-intro-mark]", { autoAlpha: 1, scale: 1, duration: 0.45, ease: "power2.out" }, 0)
@ -32,17 +36,16 @@ export default function Intro() {
{ scaleX: 1, duration: 0.85, ease: "power2.inOut" }, { scaleX: 1, duration: 0.85, ease: "power2.inOut" },
0.1, 0.1,
) )
.to(overlay, { yPercent: -100, duration: 0.5, ease: "power3.inOut" }, ">-0.1") .to(overlay, { yPercent: -100, duration: 0.5, ease: "power3.inOut" }, ">-0.1");
.to(reveal, { autoAlpha: 1, y: 0, duration: 0.5, stagger: 0.07 }, "<0.2")
.set(overlay, { display: "none" });
return () => { if (reveal.length) {
tl.kill(); tl.to(reveal, { autoAlpha: 1, y: 0, duration: 0.5, stagger: 0.07 }, "<0.2");
gsap.set(reveal, { clearProps: "all" }); }
};
tl.set(overlay, { display: "none" });
}, []); }, []);
if (pathname !== "/") return null; if (!WITH_INTRO.has(pathname)) return null;
return ( return (
<div <div