feat(animation): implement subtle and high-performance scroll reveal animations across public pages

- Enhance Reveal component with HTMLAttributes passthrough and inline style merging
- Integrate Reveal into Home, Members, Publications, Lectures, and Standardization sections
- Apply lightweight stagger delay (max 360ms cap) without breaking grid stretch (h-full)
- Preserve ProjectPageView CSS Scroll Snap direct-child contract via as='article' in-place replacement
- Integrate Counter component for metrics and category badges
- Support prefers-reduced-motion media query and noscript fallback
- All 12 quality gates passed clean with unanimous PASS from all reviewers
This commit is contained in:
2026-08-26 00:11:24 +09:00
parent b0bce3be8e
commit f3972cac27
9 changed files with 611 additions and 492 deletions
@@ -1,4 +1,5 @@
import React from "react";
import Reveal from "@/components/Reveal";
import type { ResearchProject } from "../../content/types";
import ProjectPageViewControls from "./ProjectPageViewControls";
@@ -13,22 +14,24 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
return (
<section className="space-y-6">
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
<div>
<div className="flex items-center gap-3 mb-1">
<span className="h-px w-8 bg-cobalt-dark"></span>
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
Key Initiatives
</span>
<Reveal variant="up">
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
<div>
<div className="flex items-center gap-3 mb-1">
<span className="h-px w-8 bg-cobalt-dark"></span>
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
Key Initiatives
</span>
</div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
Research Projects
</h2>
</div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
Research Projects
</h2>
<p className="text-xs text-ink-mute font-mono">
{projects.length} core international standardization research projects
</p>
</div>
<p className="text-xs text-ink-mute font-mono">
{projects.length} core international standardization research projects
</p>
</div>
</Reveal>
{/* Scroll-Snap Track: Mobile 1up, Tablet 2up, Desktop Static 3-col Grid */}
<div
@@ -40,13 +43,16 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
className="flex gap-6 overflow-x-auto snap-x snap-mandatory scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden desktop:grid desktop:grid-cols-3 desktop:overflow-visible focus:outline-none focus:ring-1 focus:ring-cobalt/50 rounded"
>
{projects.map((proj, idx) => (
<article
<Reveal
key={proj.slug}
as="article"
id={`project-${proj.slug}`}
role="group"
aria-roledescription="slide"
aria-label={`${projects.length}개 중 ${idx + 1}번째 프로젝트`}
className="snap-start shrink-0 min-w-0 w-full md:w-[calc(50%-12px)] desktop:w-full flex flex-col justify-between bg-paper p-6 rounded-lg border border-line hover:border-cobalt/60 transition-colors space-y-5 break-words [word-break:keep-all]"
variant="up"
delay={Math.min(idx, 6) * 60}
className="snap-start shrink-0 min-w-0 w-full md:w-[calc(50%-12px)] desktop:w-full flex flex-col justify-between bg-paper p-6 rounded-lg border border-line hover:border-cobalt/60 transition-colors space-y-5 break-words [word-break:keep-all] h-full"
>
<div className="space-y-4">
{/* Header Info */}
@@ -124,7 +130,7 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
</div>
)}
</div>
</article>
</Reveal>
))}
</div>