diff --git a/src/App.svelte b/src/App.svelte index 4967b2f..6c6d110 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -38,10 +38,11 @@ let resizeTimer = null // Active la transition seulement après le premier paint à la bonne position. - // Sans ça, un chargement sur /expertise slide depuis l'accueil. + // Double rAF : le premier laisse passer un paint avec le bon translateX, + // le second active is-animated — évite l'animation parasite au chargement. $effect(() => { if (slides.all.length > 0 && !isReady) { - requestAnimationFrame(() => { isReady = true }) + requestAnimationFrame(() => requestAnimationFrame(() => { isReady = true })) } }) diff --git a/src/views/Portfolio.svelte b/src/views/Portfolio.svelte index 9510344..b5ef44b 100644 --- a/src/views/Portfolio.svelte +++ b/src/views/Portfolio.svelte @@ -15,6 +15,9 @@ const projects = $derived(data?.projects ?? []) const currentProject = $derived(projects[currentIndex] ?? null) + // Capture du hash synchrone avant que tout effect puisse le modifier + const initialHash = window.location.hash.slice(1) + // --- Ancres --- function setAnchor(index) { const slug = projects[index]?.slug @@ -28,10 +31,8 @@ // Initialisation depuis l'ancre URL — une seule fois quand projects est prêt $effect(() => { - if (projects.length === 0) return - const hash = window.location.hash.slice(1) - if (!hash) return - const idx = projects.findIndex(p => p.slug === hash) + if (projects.length === 0 || !initialHash) return + const idx = projects.findIndex(p => p.slug === initialHash) if (idx > 0) currentIndex = idx }) @@ -61,11 +62,17 @@ }) // --- Effect: reset when slide deactivated --- + // wasActive évite que clearAnchor() s'exécute au montage initial + // (isActive est false avant l'initialisation des slides) + let wasActive = false $effect(() => { - if (!isActive) { + if (isActive) { + wasActive = true + } else if (wasActive) { nav.reset() currentIndex = 0 clearAnchor() + wasActive = false } })