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
+118 -93
View File
@@ -2,6 +2,7 @@
import React, { useEffect, useState } from "react";
import Image from "next/image";
import Reveal from "@/components/Reveal";
import { getMembers, getAlumni } from "../../lib/api";
import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog";
import type { Member, Alumnus } from "../../content/types";
@@ -43,125 +44,147 @@ export default function MembersPage() {
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */}
<section>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
LAB MEMBERS
</h1>
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
LAB MEMBERS
</h1>
</Reveal>
</section>
{/* Professor Section */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div className="lg:col-span-8 space-y-4">
<h2 className="font-serif text-3xl font-normal text-ink">
Prof. Seok-Joo Koh
</h2>
<div className="text-sm text-ink-mute leading-relaxed space-y-2">
<p>
Professor at the School of Computer Science and Engineering, Kyungpook National University, and Dean of the College of IT Engineering. He directs the AI Agent Networking Laboratory (ANL), leading research on QUIC/gRPC transport, A2A/ACP protocols, MCP &amp; SKILL architectures, and multi-agent orchestration, and serves as Project Editor in ISO/IEC JTC1, ITU-T, and IEC TC100.
</p>
<div>
<ProfessorDetailsDialog />
<Reveal variant="up">
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div className="lg:col-span-8 space-y-4">
<h2 className="font-serif text-3xl font-normal text-ink">
Prof. Seok-Joo Koh
</h2>
<div className="text-sm text-ink-mute leading-relaxed space-y-2">
<p>
Professor at the School of Computer Science and Engineering, Kyungpook National University, and Dean of the College of IT Engineering. He directs the AI Agent Networking Laboratory (ANL), leading research on QUIC/gRPC transport, A2A/ACP protocols, MCP &amp; SKILL architectures, and multi-agent orchestration, and serves as Project Editor in ISO/IEC JTC1, ITU-T, and IEC TC100.
</p>
<div>
<ProfessorDetailsDialog />
</div>
</div>
<div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono">
<a
href="mailto:sjkoh@knu.ac.kr"
className="text-cobalt-dark hover:underline font-bold"
>
sjkoh@knu.ac.kr
</a>
<span className="text-ink-mute">|</span>
<a
href="https://github.com/sjkoh12"
target="_blank"
rel="noopener noreferrer"
className="text-ink hover:text-cobalt-dark hover:underline"
>
GitHub Profile
</a>
</div>
</div>
<div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono">
<a
href="mailto:sjkoh@knu.ac.kr"
className="text-cobalt-dark hover:underline font-bold"
>
sjkoh@knu.ac.kr
</a>
<span className="text-ink-mute">|</span>
<a
href="https://github.com/sjkoh12"
target="_blank"
rel="noopener noreferrer"
className="text-ink hover:text-cobalt-dark hover:underline"
>
GitHub Profile
</a>
<div className="lg:col-span-4 flex justify-center items-center">
<div className="relative w-48 h-48 sm:w-56 sm:h-56 md:w-60 md:h-60 rounded-xl overflow-hidden border border-line bg-transparent">
<Image
src="/images/prof_profile.png"
alt="Prof. Seok-Joo Koh"
fill
sizes="(max-width: 1024px) 224px, 240px"
className="object-cover object-top"
priority
/>
</div>
</div>
</div>
<div className="lg:col-span-4 flex justify-center items-center">
<div className="relative w-48 h-48 sm:w-56 sm:h-56 md:w-60 md:h-60 rounded-xl overflow-hidden border border-line bg-transparent">
<Image
src="/images/prof_profile.png"
alt="Prof. Seok-Joo Koh"
fill
sizes="(max-width: 1024px) 224px, 240px"
className="object-cover object-top"
priority
/>
</div>
</div>
</div>
</Reveal>
</section>
{/* Active Researchers Section */}
<section className="space-y-8 pt-6 md:pt-8 border-t border-line">
<div className="flex justify-between items-end">
<div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Active Researchers
</h2>
<Reveal variant="up">
<div className="flex justify-between items-end">
<div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Active Researchers
</h2>
</div>
</div>
</div>
</Reveal>
{/* Ph.D. Candidates / Students */}
<div className="space-y-4">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
Ph.D. Course ({phdStudents.length})
</h3>
<Reveal variant="up">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
Ph.D. Course ({phdStudents.length})
</h3>
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{phdStudents.map((mem, idx) => (
<div
<Reveal
key={idx}
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors"
variant="up"
delay={Math.min(idx, 6) * 60}
className="h-full"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt-dark">
{DEGREE_LABEL[mem.degree] || mem.degree}
</span>
</div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
with {mem.affiliation}
<div
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors h-full"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt-dark">
{DEGREE_LABEL[mem.degree] || mem.degree}
</span>
</div>
)}
</div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
with {mem.affiliation}
</div>
)}
</div>
</Reveal>
))}
</div>
</div>
{/* M.S. Candidates / Students */}
<div className="space-y-4 pt-4">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
M.S. Course ({msStudents.length})
</h3>
<Reveal variant="up">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
M.S. Course ({msStudents.length})
</h3>
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{msStudents.map((mem, idx) => (
<div
<Reveal
key={idx}
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors"
variant="up"
delay={Math.min(idx, 6) * 60}
className="h-full"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt-dark">
{DEGREE_LABEL[mem.degree] || mem.degree}
</span>
</div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
with {mem.affiliation}
<div
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors h-full"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt-dark">
{DEGREE_LABEL[mem.degree] || mem.degree}
</span>
</div>
)}
</div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
with {mem.affiliation}
</div>
)}
</div>
</Reveal>
))}
</div>
</div>
@@ -169,13 +192,15 @@ export default function MembersPage() {
{/* Alumni Section (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<div className="flex justify-between items-end">
<div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
Graduates
</h2>
<Reveal variant="up">
<div className="flex justify-between items-end">
<div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
Graduates
</h2>
</div>
</div>
</div>
</Reveal>
<details className="group border border-line rounded-lg bg-paper p-6 transition-all duration-200">
<summary className="flex justify-between items-center cursor-pointer list-none select-none">