Files
0pt/hooks/use-reveal.ts
T
adminandClaude Sonnet 4.6 240a42b2b7 fix: reveal animations for standalone pages on direct load
RouteReveal layout component applies in-view on every route change.
useReveal hook falls back to immediate rAF when element is already visible.
bestall/page.tsx: added missing useReveal ref.
katalog/[id]/page.tsx: DatasetView uses useReveal directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:20:10 +02:00

50 lines
1.4 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
/**
* Wire a section so its descendants carrying `.reveal` (+ optional
* `.reveal-left|-right|-scale|-fade` and `.delay-N`) animate in when the
* section scrolls into view. Matches the keyframes in globals.css.
*
* If the section is already visible on mount (e.g. top-of-page navigation),
* reveals are applied immediately via rAF instead of waiting for scroll.
*/
export function useReveal<T extends HTMLElement = HTMLElement>() {
const ref = useRef<T>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const applyReveal = () => {
el
.querySelectorAll(
".reveal, .reveal-left, .reveal-right, .reveal-scale, .reveal-fade",
)
.forEach((n) => n.classList.add("in-view"));
};
// If the element's top edge is already within the viewport, apply immediately.
const rect = el.getBoundingClientRect();
if (rect.top < window.innerHeight * 0.9) {
requestAnimationFrame(applyReveal);
return;
}
// Otherwise use IntersectionObserver for scroll-triggered reveal.
const io = new IntersectionObserver(
(entries) =>
entries.forEach((e) => {
if (e.isIntersecting) {
applyReveal();
io.unobserve(el);
}
}),
{ threshold: 0.15, rootMargin: "0px 0px -10% 0px" },
);
io.observe(el);
return () => io.disconnect();
}, []);
return ref;
}