Files
agentlens/apps/web/src/components/animate-on-scroll.tsx
Vectry 64c827ee84 feat: add command palette, accessibility, scroll animations, demo workspace, and keyboard navigation
- COMP-139: Command palette for quick navigation
- COMP-140: Accessibility improvements
- COMP-141: Scroll animations with animate-on-scroll component
- COMP-143: Demo workspace with seed data and demo banner
- COMP-145: Keyboard navigation and shortcuts help

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-10 18:06:36 +00:00

61 lines
1.2 KiB
TypeScript

"use client";
import { useEffect, useRef, ReactNode } from "react";
interface AnimateOnScrollProps {
children: ReactNode;
className?: string;
delay?: number;
threshold?: number;
}
export function AnimateOnScroll({
children,
className = "",
delay = 0,
threshold = 0.15,
}: AnimateOnScrollProps) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const prefersReduced = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReduced) {
el.setAttribute("data-animate", "visible");
return;
}
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.setAttribute("data-animate", "visible");
observer.unobserve(entry.target);
}
}
},
{ threshold }
);
observer.observe(el);
return () => observer.disconnect();
}, [threshold]);
return (
<div
ref={ref}
data-animate="hidden"
className={className}
style={{ animationDelay: delay ? `${delay}ms` : undefined }}
>
{children}
</div>
);
}