Files
AgentCompany/landing/components/ui/reveal.tsx
T
ZacharyZhang-NY b1e2374c7b Rebuild landing design system on the adaline pebble/meadow palette
Foundation for the adaline-based landing rebuild:
- globals.css: warm-cream light theme + Material-3 dark theme mapped onto the
  existing CSS-var names; CSS-keyframe entrance + IntersectionObserver reveal
  motion (to replace framer-motion incrementally)
- layout.tsx: self-host Instrument Sans/Serif, Newsreader and JetBrains Mono via
  next/font/google; drop the external Google Fonts <link>
- _headers: tighten CSP style/font-src to 'self' now that fonts are local
- components/ui: Container, Reveal, Eyebrow, Badge, Button, SectionHeading
- lib/landing-content.ts: feature-section copy for the six product screens
- public/images: six product screenshots optimized to WebP
- add reicon-react/reicon-brands (bundled, CSP-safe SVG icons)

Business logic (D1 download counter, platform metadata, theme, SEO) unchanged.
2026-07-07 21:41:12 -04:00

60 lines
1.4 KiB
TypeScript

"use client";
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
/**
* Scroll-reveal wrapper. Starts hidden (via the `.reveal` class) and marks
* itself in view the first time it intersects the viewport, letting CSS handle
* the rise-and-fade. Honours reduced-motion through the stylesheet.
*/
export function Reveal({
children,
delay = 0,
className = "",
}: {
children: ReactNode;
delay?: number;
className?: string;
}) {
const ref = useRef<HTMLDivElement | null>(null);
const [inView, setInView] = useState(false);
useEffect(() => {
const node = ref.current;
if (!node) {
return;
}
if (typeof IntersectionObserver === "undefined") {
setInView(true);
return;
}
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
setInView(true);
observer.disconnect();
break;
}
}
},
{ threshold: 0.2, rootMargin: "0px 0px -10% 0px" },
);
observer.observe(node);
return () => observer.disconnect();
}, []);
return (
<div
ref={ref}
className={`reveal ${className}`}
data-in-view={inView}
style={delay ? ({ "--reveal-delay": `${delay}ms` } as CSSProperties) : undefined}
>
{children}
</div>
);
}