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,5 +1,7 @@
import React from "react";
import Link from "next/link";
import Reveal from "@/components/Reveal";
import Counter from "@/components/Counter";
import { PUB_CATEGORIES } from "../../../content/categories";
import { PubCategory } from "../../../content/types";
@@ -24,87 +26,95 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Categories
</h2>
{currentCategory && (
<Link
href="/publications"
className="font-mono text-xs text-ink-mute hover:text-ink hover:underline transition-colors"
>
&larr; Overview
</Link>
)}
</div>
<Reveal variant="up">
<div className="flex justify-between items-center">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Categories
</h2>
{currentCategory && (
<Link
href="/publications"
className="font-mono text-xs text-ink-mute hover:text-ink hover:underline transition-colors"
>
&larr; Overview
</Link>
)}
</div>
</Reveal>
<div className="grid gap-5 sm:gap-6 md:grid-cols-3">
{PUB_CATEGORIES.map((cat) => {
{PUB_CATEGORIES.map((cat, idx) => {
const count = getCount(cat.slug);
const isActive = currentCategory === cat.slug;
return (
<div
<Reveal
key={cat.slug}
className={`flex flex-col justify-between bg-paper p-5 sm:p-6 rounded-lg transition-all ${
isActive
? "border-2 border-cobalt-dark shadow-md"
: "border border-line shadow-sm hover:border-cobalt-dark/40"
}`}
variant="up"
delay={idx * 80}
className="h-full"
>
<div className="space-y-3">
<div className="flex justify-between items-center">
<span
className={`font-mono text-xs font-bold uppercase tracking-wider ${
isActive ? "text-cobalt-dark" : "text-ink-mute"
<div
className={`flex flex-col justify-between bg-paper p-5 sm:p-6 rounded-lg transition-all h-full ${
isActive
? "border-2 border-cobalt-dark shadow-md"
: "border border-line shadow-sm hover:border-cobalt-dark/40"
}`}
>
<div className="space-y-3">
<div className="flex justify-between items-center">
<span
className={`font-mono text-xs font-bold uppercase tracking-wider ${
isActive ? "text-cobalt-dark" : "text-ink-mute"
}`}
>
Category
</span>
{isActive && (
<span className="font-mono text-[0.65rem] font-bold px-2 py-0.5 rounded bg-cobalt-dark/10 text-cobalt-dark uppercase">
Current
</span>
)}
</div>
<h3
className={`font-serif text-xl ${
isActive ? "text-cobalt-dark font-normal" : "text-ink font-normal"
}`}
>
Category
</span>
{isActive && (
<span className="font-mono text-[0.65rem] font-bold px-2 py-0.5 rounded bg-cobalt-dark/10 text-cobalt-dark uppercase">
Current
</span>
)}
{cat.label}
{cat.subtitle && (
<span className="block text-xs font-mono text-ink-mute mt-1 font-normal">
{cat.subtitle}
</span>
)}
</h3>
</div>
<h3
className={`font-serif text-xl ${
isActive ? "text-cobalt-dark font-normal" : "text-ink font-normal"
}`}
>
{cat.label}
{cat.subtitle && (
<span className="block text-xs font-mono text-ink-mute mt-1 font-normal">
{cat.subtitle}
<div className="mt-6 pt-4 border-t border-line flex items-baseline justify-between">
<span className="font-display text-3xl font-bold text-ink">
<Counter value={count} />
<span className="text-xs font-mono text-ink-mute ml-1 font-normal">
{cat.slug === "patent" ? "Patents" : "Papers"}
</span>
</span>
{isActive ? (
<span className="inline-flex items-center text-xs font-bold text-cobalt-dark font-mono">
Active View
</span>
) : (
<Link
href={`/publications/${cat.slug}`}
aria-label={`View all ${cat.label} records`}
className="inline-flex items-center text-xs font-bold text-vermillion-dark hover:underline focus:outline-none focus:ring-1 focus:ring-vermillion-dark rounded"
>
View All &rarr;
</Link>
)}
</h3>
</div>
</div>
<div className="mt-6 pt-4 border-t border-line flex items-baseline justify-between">
<span className="font-display text-3xl font-bold text-ink">
{count}
<span className="text-xs font-mono text-ink-mute ml-1 font-normal">
{cat.slug === "patent" ? "Patents" : "Papers"}
</span>
</span>
{isActive ? (
<span className="inline-flex items-center text-xs font-bold text-cobalt-dark font-mono">
Active View
</span>
) : (
<Link
href={`/publications/${cat.slug}`}
aria-label={`View all ${cat.label} records`}
className="inline-flex items-center text-xs font-bold text-vermillion-dark hover:underline focus:outline-none focus:ring-1 focus:ring-vermillion-dark rounded"
>
View All &rarr;
</Link>
)}
</div>
</div>
</Reveal>
);
})}
</div>