Compare commits

...
3 Commits
Author SHA1 Message Date
Godopu f3972cac27 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
2026-08-26 00:11:24 +09:00
Godopu b0bce3be8e style(members): set professor profile image container background to transparent with border only
- Remove bg-ivory from prof image wrapper container
- Apply bg-transparent and border border-line for clean transparent silhouette
- Passed all 12 E2E test gates (Exit Code 0)
2026-08-25 23:43:04 +09:00
Godopu ca6e85ce9b feat(members): replace Affiliation & Office box with Prof. Seok-Joo Koh profile image
- Copy prof_profile.png to refer_landing_page/public/images/
- Configure images.unoptimized in next.config.js for static export compatibility
- Render high-resolution portrait profile image in professor section
- All 12 quality gates passed clean (Exit Code 0)
2026-08-25 23:40:12 +09:00
14 changed files with 615 additions and 488 deletions
Vendored
BIN
View File
Binary file not shown.
@@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import Reveal from "@/components/Reveal";
import type { ResearchProject } from "../../content/types"; import type { ResearchProject } from "../../content/types";
import ProjectPageViewControls from "./ProjectPageViewControls"; import ProjectPageViewControls from "./ProjectPageViewControls";
@@ -13,6 +14,7 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
return ( return (
<section className="space-y-6"> <section className="space-y-6">
<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 className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
<div> <div>
<div className="flex items-center gap-3 mb-1"> <div className="flex items-center gap-3 mb-1">
@@ -29,6 +31,7 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
{projects.length} core international standardization research projects {projects.length} core international standardization research projects
</p> </p>
</div> </div>
</Reveal>
{/* Scroll-Snap Track: Mobile 1up, Tablet 2up, Desktop Static 3-col Grid */} {/* Scroll-Snap Track: Mobile 1up, Tablet 2up, Desktop Static 3-col Grid */}
<div <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" 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) => ( {projects.map((proj, idx) => (
<article <Reveal
key={proj.slug} key={proj.slug}
as="article"
id={`project-${proj.slug}`} id={`project-${proj.slug}`}
role="group" role="group"
aria-roledescription="slide" aria-roledescription="slide"
aria-label={`${projects.length}개 중 ${idx + 1}번째 프로젝트`} 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"> <div className="space-y-4">
{/* Header Info */} {/* Header Info */}
@@ -124,7 +130,7 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
</div> </div>
)} )}
</div> </div>
</article> </Reveal>
))} ))}
</div> </div>
+18 -3
View File
@@ -1,6 +1,7 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Reveal from "@/components/Reveal";
import { getSemesters } from "../../lib/api"; import { getSemesters } from "../../lib/api";
import type { Semester } from "../../content/types"; import type { Semester } from "../../content/types";
@@ -23,13 +24,16 @@ export default function LecturesPage() {
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14"> <div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */} {/* Page Header */}
<section> <section>
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
LECTURES LECTURES
</h1> </h1>
</Reveal>
</section> </section>
{/* Recent 3 Semesters */} {/* Recent 3 Semesters */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<Reveal variant="up">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark"> <h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Recent Courses Recent Courses
@@ -38,12 +42,18 @@ export default function LecturesPage() {
Latest 3 Semesters Latest 3 Semesters
</span> </span>
</div> </div>
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-5 sm:gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-5 sm:gap-6">
{recentSemesters.map((sem, idx) => ( {recentSemesters.map((sem, idx) => (
<div <Reveal
key={idx} key={idx}
className="bg-paper p-5 sm:p-6 rounded-lg border border-line space-y-4 flex flex-col justify-between shadow-sm" variant="up"
delay={idx * 80}
className="h-full"
>
<div
className="bg-paper p-5 sm:p-6 rounded-lg border border-line space-y-4 flex flex-col justify-between shadow-sm h-full"
> >
<div className="space-y-3"> <div className="space-y-3">
<div className="flex justify-between items-center border-b border-line pb-2.5"> <div className="flex justify-between items-center border-b border-line pb-2.5">
@@ -74,13 +84,16 @@ export default function LecturesPage() {
<span className="font-semibold text-ink">{sem.courses.length} Courses</span> <span className="font-semibold text-ink">{sem.courses.length} Courses</span>
</div> </div>
</div> </div>
</Reveal>
))} ))}
</div> </div>
</section> </section>
{/* Older Semesters (Native <details>/<summary> progressive disclosure) */} {/* Older Semesters (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<details className="group border border-line rounded-lg bg-paper p-5 sm:p-6 transition-all duration-200"> <Reveal variant="up">
<div className="border border-line rounded-lg bg-paper p-5 sm:p-6 transition-all duration-200">
<details className="group">
<summary className="flex justify-between items-center cursor-pointer list-none select-none"> <summary className="flex justify-between items-center cursor-pointer list-none select-none">
<div className="space-y-1"> <div className="space-y-1">
<span className="font-serif text-lg sm:text-xl font-normal text-ink"> <span className="font-serif text-lg sm:text-xl font-normal text-ink">
@@ -127,6 +140,8 @@ export default function LecturesPage() {
))} ))}
</div> </div>
</details> </details>
</div>
</Reveal>
</section> </section>
</div> </div>
); );
+41 -11
View File
@@ -1,6 +1,8 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Image from "next/image";
import Reveal from "@/components/Reveal";
import { getMembers, getAlumni } from "../../lib/api"; import { getMembers, getAlumni } from "../../lib/api";
import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog"; import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog";
import type { Member, Alumnus } from "../../content/types"; import type { Member, Alumnus } from "../../content/types";
@@ -42,13 +44,16 @@ export default function MembersPage() {
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14"> <div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */} {/* Page Header */}
<section> <section>
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
LAB MEMBERS LAB MEMBERS
</h1> </h1>
</Reveal>
</section> </section>
{/* Professor Section */} {/* Professor Section */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<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="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"> <div className="lg:col-span-8 space-y-4">
<h2 className="font-serif text-3xl font-normal text-ink"> <h2 className="font-serif text-3xl font-normal text-ink">
@@ -80,19 +85,25 @@ export default function MembersPage() {
</a> </a>
</div> </div>
</div> </div>
<div className="lg:col-span-4 bg-ivory p-6 rounded border border-line text-xs space-y-2 font-mono"> <div className="lg:col-span-4 flex justify-center items-center">
<div className="text-ink font-bold border-b border-line pb-1"> <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">
Affiliation &amp; Office <Image
</div> src="/images/prof_profile.png"
<p className="text-ink-mute">Kyungpook National University</p> alt="Prof. Seok-Joo Koh"
<p className="text-ink-mute">IT Building #5 Room 527</p> fill
<p className="text-ink-mute">Daegu, Republic of Korea</p> sizes="(max-width: 1024px) 224px, 240px"
className="object-cover object-top"
priority
/>
</div> </div>
</div> </div>
</div>
</Reveal>
</section> </section>
{/* Active Researchers Section */} {/* Active Researchers Section */}
<section className="space-y-8 pt-6 md:pt-8 border-t border-line"> <section className="space-y-8 pt-6 md:pt-8 border-t border-line">
<Reveal variant="up">
<div className="flex justify-between items-end"> <div className="flex justify-between items-end">
<div> <div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark"> <h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
@@ -100,17 +111,25 @@ export default function MembersPage() {
</h2> </h2>
</div> </div>
</div> </div>
</Reveal>
{/* Ph.D. Candidates / Students */} {/* Ph.D. Candidates / Students */}
<div className="space-y-4"> <div className="space-y-4">
<Reveal variant="up">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2"> <h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
Ph.D. Course ({phdStudents.length}) Ph.D. Course ({phdStudents.length})
</h3> </h3>
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{phdStudents.map((mem, idx) => ( {phdStudents.map((mem, idx) => (
<div <Reveal
key={idx} 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="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"> <div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink"> <span className="font-serif text-lg font-normal text-ink">
@@ -127,20 +146,28 @@ export default function MembersPage() {
</div> </div>
)} )}
</div> </div>
</Reveal>
))} ))}
</div> </div>
</div> </div>
{/* M.S. Candidates / Students */} {/* M.S. Candidates / Students */}
<div className="space-y-4 pt-4"> <div className="space-y-4 pt-4">
<Reveal variant="up">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2"> <h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
M.S. Course ({msStudents.length}) M.S. Course ({msStudents.length})
</h3> </h3>
</Reveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{msStudents.map((mem, idx) => ( {msStudents.map((mem, idx) => (
<div <Reveal
key={idx} 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="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"> <div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink"> <span className="font-serif text-lg font-normal text-ink">
@@ -157,6 +184,7 @@ export default function MembersPage() {
</div> </div>
)} )}
</div> </div>
</Reveal>
))} ))}
</div> </div>
</div> </div>
@@ -164,6 +192,7 @@ export default function MembersPage() {
{/* Alumni Section (Native <details>/<summary> progressive disclosure) */} {/* Alumni Section (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<Reveal variant="up">
<div className="flex justify-between items-end"> <div className="flex justify-between items-end">
<div> <div>
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink"> <h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
@@ -171,6 +200,7 @@ export default function MembersPage() {
</h2> </h2>
</div> </div>
</div> </div>
</Reveal>
<details className="group border border-line rounded-lg bg-paper p-6 transition-all duration-200"> <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"> <summary className="flex justify-between items-center cursor-pointer list-none select-none">
+31 -7
View File
@@ -2,6 +2,8 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import Reveal from "@/components/Reveal";
import Counter from "@/components/Counter";
import HeroComposition from "./_components/HeroComposition"; import HeroComposition from "./_components/HeroComposition";
import { ProjectPageView } from "./_components/ProjectPageView"; import { ProjectPageView } from "./_components/ProjectPageView";
import { getStatsSummary, getResearchAreaNames, getResearchProjects } from "../lib/api"; import { getStatsSummary, getResearchAreaNames, getResearchProjects } from "../lib/api";
@@ -40,43 +42,52 @@ export default function HomePage() {
<div className="container-content space-y-16 md:space-y-24 pt-10 md:pt-16 pb-16 md:pb-24"> <div className="container-content space-y-16 md:space-y-24 pt-10 md:pt-16 pb-16 md:pb-24">
{/* Hero Section */} {/* Hero Section */}
<section className="relative"> <section className="relative">
<Reveal variant="up">
<div className="mb-4"> <div className="mb-4">
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold"> <span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
Kyungpook National University · AI Agent Networking Lab (ANL) Kyungpook National University · AI Agent Networking Lab (ANL)
</span> </span>
</div> </div>
</Reveal>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:items-center"> <div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:items-center">
<div className="lg:col-span-7 space-y-6 lg:pt-4"> <div className="lg:col-span-7 space-y-6 lg:pt-4">
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl lg:text-6xl font-normal text-ink leading-tight"> <h1 className="font-serif text-4xl sm:text-5xl lg:text-6xl font-normal text-ink leading-tight">
Multi-Agent <br /> Multi-Agent <br />
<span className="italic font-serif text-cobalt-dark">Orchestration</span> <span className="italic font-serif text-cobalt-dark">Orchestration</span>
</h1> </h1>
<p className="text-ink-mute text-base sm:text-lg leading-relaxed max-w-2xl"> <p className="text-ink-mute text-base sm:text-lg leading-relaxed max-w-2xl mt-4">
The AI Agent Networking Laboratory (ANL) studies agent networking technologies and standard frameworks that enable AI agents to communicate and collaborate with one another for multi-agent orchestration. The AI Agent Networking Laboratory (ANL) studies agent networking technologies and standard frameworks that enable AI agents to communicate and collaborate with one another for multi-agent orchestration.
</p> </p>
</Reveal>
{/* Metrics Row (Derived from real content data) */} {/* Metrics Row (Derived from real content data) */}
<div className="pt-6 border-t border-line grid grid-cols-3 gap-4"> <div className="pt-6 border-t border-line grid grid-cols-3 gap-4">
<Reveal variant="up" delay={80}>
<div> <div>
<div className="font-serif text-3xl text-cobalt-dark font-normal"> <div className="font-serif text-3xl text-cobalt-dark font-normal">
{stats.intlPubsCount} <Counter value={stats.intlPubsCount} />
</div> </div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight"> <div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
International Journals &amp; Conference International Journals &amp; Conference
</div> </div>
</div> </div>
</Reveal>
<Reveal variant="up" delay={160}>
<div> <div>
<div className="font-serif text-3xl text-cobalt-dark font-normal"> <div className="font-serif text-3xl text-cobalt-dark font-normal">
{stats.stdDocsCount} <Counter value={stats.stdDocsCount} />
</div> </div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight"> <div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
Standardization Contributions Standardization Contributions
</div> </div>
</div> </div>
</Reveal>
<Reveal variant="up" delay={240}>
<div> <div>
<div className="font-serif text-3xl text-cobalt-dark font-normal"> <div className="font-serif text-3xl text-cobalt-dark font-normal">
{stats.patentCount} <Counter value={stats.patentCount} />
</div> </div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight"> <div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
Patent<br /> Patent<br />
@@ -85,12 +96,13 @@ export default function HomePage() {
</span> </span>
</div> </div>
</div> </div>
</Reveal>
</div> </div>
</div> </div>
<div className="w-full max-w-[500px] mx-auto my-[30px] lg:my-0 lg:max-w-none lg:mx-0 lg:col-span-5 border border-line bg-paper p-4 rounded-lg"> <Reveal variant="scale" delay={120} className="w-full max-w-[500px] mx-auto my-[30px] lg:my-0 lg:max-w-none lg:mx-0 lg:col-span-5 border border-line bg-paper p-4 rounded-lg">
<HeroComposition /> <HeroComposition />
</div> </Reveal>
</div> </div>
</section> </section>
@@ -99,6 +111,7 @@ export default function HomePage() {
{/* 14 Research Areas Grid */} {/* 14 Research Areas Grid */}
<section className="space-y-8 pt-16 md:pt-20 border-t border-line"> <section className="space-y-8 pt-16 md:pt-20 border-t border-line">
<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 className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
<div> <div>
<div className="flex items-center gap-3 mb-1"> <div className="flex items-center gap-3 mb-1">
@@ -115,6 +128,7 @@ export default function HomePage() {
{researchAreas.length} fundamental networking protocols and AI system domains {researchAreas.length} fundamental networking protocols and AI system domains
</p> </p>
</div> </div>
</Reveal>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{researchAreas.map((area, idx) => { {researchAreas.map((area, idx) => {
@@ -122,8 +136,13 @@ export default function HomePage() {
const isOdd = (idx + 1) % 2 !== 0; const isOdd = (idx + 1) % 2 !== 0;
return ( return (
<div <Reveal
key={no} key={no}
variant="up"
delay={Math.min(idx, 6) * 60}
className="h-full"
>
<div
className="bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-ink transition-colors duration-200 h-full" className="bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-ink transition-colors duration-200 h-full"
> >
<div className="space-y-3"> <div className="space-y-3">
@@ -144,6 +163,7 @@ export default function HomePage() {
</h3> </h3>
</div> </div>
</div> </div>
</Reveal>
); );
})} })}
</div> </div>
@@ -151,6 +171,7 @@ export default function HomePage() {
{/* International Standardizations Section */} {/* International Standardizations Section */}
<section className="space-y-6 pt-16 md:pt-20 border-t border-line"> <section className="space-y-6 pt-16 md:pt-20 border-t border-line">
<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 className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
<div> <div>
<div className="flex items-center gap-3 mb-1"> <div className="flex items-center gap-3 mb-1">
@@ -164,7 +185,9 @@ export default function HomePage() {
</h2> </h2>
</div> </div>
</div> </div>
</Reveal>
<Reveal variant="up">
<div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6"> <div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6">
<p className="text-ink/80 text-sm sm:text-base leading-relaxed max-w-3xl"> <p className="text-ink/80 text-sm sm:text-base leading-relaxed max-w-3xl">
Along with the research activities, we are also in pursuit of the International Standardization, from the market deployment perspective, in the following SDOs (Standard-Defining Organizations): Along with the research activities, we are also in pursuit of the International Standardization, from the market deployment perspective, in the following SDOs (Standard-Defining Organizations):
@@ -188,6 +211,7 @@ export default function HomePage() {
</Link> </Link>
</div> </div>
</div> </div>
</Reveal>
</section> </section>
</div> </div>
); );
@@ -2,6 +2,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import Reveal from "@/components/Reveal";
import { CategoryNav } from "../../_components/CategoryNav"; import { CategoryNav } from "../../_components/CategoryNav";
import { getPublications, getPatents } from "../../../../lib/api"; import { getPublications, getPatents } from "../../../../lib/api";
import { PUB_CATEGORIES } from "../../../../content/categories"; import { PUB_CATEGORIES } from "../../../../content/categories";
@@ -61,32 +62,41 @@ export function PublicationCategoryClient({ category }: { category: string }) {
})); }));
} }
// Extract unique sorted years // Extract distinct available years from date strings (YYYY-MM or YYYY)
const availableYears = Array.from( const availableYears = Array.from(
new Set( new Set(
allRecords allRecords
.map((r) => (r.publishedAt || "").match(/\b(19\d\d|20\d\d)\b/)?.[1]) .map((r) => {
const dateStr = r.publishedAt || "";
const match = dateStr.match(/\b(19\d\d|20\d\d)\b/);
return match ? match[1] : null;
})
.filter((y): y is string => Boolean(y)) .filter((y): y is string => Boolean(y))
) )
).sort((a, b) => b.localeCompare(a)); ).sort((a, b) => b.localeCompare(a));
const records = // Filter records by selected year
selectedYear === "all" const records = allRecords.filter((r) => {
? allRecords if (selectedYear === "all") return true;
: allRecords.filter((r) => (r.publishedAt || "").includes(selectedYear)); const dateStr = r.publishedAt || "";
const yr = dateStr.match(/\b(19\d\d|20\d\d)\b/)?.[1] || "";
return yr === selectedYear;
});
return ( return (
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14"> <div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */} {/* Page Header */}
<section className="space-y-1"> <section className="space-y-1">
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
{currentCat.label} {currentCat.label}
</h1> </h1>
{currentCat.subtitle && ( {currentCat.subtitle && (
<p className="font-mono text-sm text-ink-mute"> <p className="font-mono text-sm text-ink-mute mt-1">
{currentCat.subtitle} {currentCat.subtitle}
</p> </p>
)} )}
</Reveal>
</section> </section>
{/* Category Nav Cards */} {/* Category Nav Cards */}
@@ -96,6 +106,7 @@ export function PublicationCategoryClient({ category }: { category: string }) {
{/* Record List Section */} {/* Record List Section */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<Reveal variant="up">
<div className="flex flex-wrap justify-between items-center gap-4 border-b border-line pb-3"> <div className="flex flex-wrap justify-between items-center gap-4 border-b border-line pb-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="font-mono text-xs text-ink-mute uppercase">Filter Year:</span> <span className="font-mono text-xs text-ink-mute uppercase">Filter Year:</span>
@@ -128,6 +139,7 @@ export function PublicationCategoryClient({ category }: { category: string }) {
Showing {records.length} of {allRecords.length} Records Showing {records.length} of {allRecords.length} Records
</span> </span>
</div> </div>
</Reveal>
{records.length === 0 ? ( {records.length === 0 ? (
<div className="bg-paper p-8 rounded-lg border border-line text-center space-y-3"> <div className="bg-paper p-8 rounded-lg border border-line text-center space-y-3">
@@ -1,5 +1,7 @@
import React from "react"; import React from "react";
import Link from "next/link"; import Link from "next/link";
import Reveal from "@/components/Reveal";
import Counter from "@/components/Counter";
import { PUB_CATEGORIES } from "../../../content/categories"; import { PUB_CATEGORIES } from "../../../content/categories";
import { PubCategory } from "../../../content/types"; import { PubCategory } from "../../../content/types";
@@ -24,6 +26,7 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<Reveal variant="up">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark"> <h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Categories Categories
@@ -37,16 +40,22 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
</Link> </Link>
)} )}
</div> </div>
</Reveal>
<div className="grid gap-5 sm:gap-6 md:grid-cols-3"> <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 count = getCount(cat.slug);
const isActive = currentCategory === cat.slug; const isActive = currentCategory === cat.slug;
return ( return (
<div <Reveal
key={cat.slug} key={cat.slug}
className={`flex flex-col justify-between bg-paper p-5 sm:p-6 rounded-lg transition-all ${ variant="up"
delay={idx * 80}
className="h-full"
>
<div
className={`flex flex-col justify-between bg-paper p-5 sm:p-6 rounded-lg transition-all h-full ${
isActive isActive
? "border-2 border-cobalt-dark shadow-md" ? "border-2 border-cobalt-dark shadow-md"
: "border border-line shadow-sm hover:border-cobalt-dark/40" : "border border-line shadow-sm hover:border-cobalt-dark/40"
@@ -84,7 +93,7 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
<div className="mt-6 pt-4 border-t border-line flex items-baseline justify-between"> <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"> <span className="font-display text-3xl font-bold text-ink">
{count} <Counter value={count} />
<span className="text-xs font-mono text-ink-mute ml-1 font-normal"> <span className="text-xs font-mono text-ink-mute ml-1 font-normal">
{cat.slug === "patent" ? "Patents" : "Papers"} {cat.slug === "patent" ? "Patents" : "Papers"}
</span> </span>
@@ -105,6 +114,7 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
)} )}
</div> </div>
</div> </div>
</Reveal>
); );
})} })}
</div> </div>
+13 -2
View File
@@ -1,6 +1,7 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Reveal from "@/components/Reveal";
import { CategoryNav } from "./_components/CategoryNav"; import { CategoryNav } from "./_components/CategoryNav";
import { getPublications, getPatents } from "../../lib/api"; import { getPublications, getPatents } from "../../lib/api";
import type { Publication, Patent } from "../../content/types"; import type { Publication, Patent } from "../../content/types";
@@ -31,9 +32,11 @@ export default function PublicationsIndexPage() {
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14"> <div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */} {/* Page Header */}
<section> <section>
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
PUBLICATIONS PUBLICATIONS
</h1> </h1>
</Reveal>
</section> </section>
{/* Category Summary Cards */} {/* Category Summary Cards */}
@@ -43,13 +46,21 @@ export default function PublicationsIndexPage() {
{/* Highlights Section */} {/* Highlights Section */}
<section className="space-y-6 pt-6 md:pt-8 border-t border-line"> <section className="space-y-6 pt-6 md:pt-8 border-t border-line">
<Reveal variant="up">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark"> <h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Highlights Highlights
</h2> </h2>
</Reveal>
<div className="divide-y divide-line border border-line bg-paper rounded-lg overflow-hidden shadow-sm"> <div className="divide-y divide-line border border-line bg-paper rounded-lg overflow-hidden shadow-sm">
{highlights.map((pub, idx) => ( {highlights.map((pub, idx) => (
<article key={`${pub.category}-${idx}`} className="p-5 hover:bg-ivory/60 transition-colors space-y-2"> <Reveal
key={`${pub.category}-${idx}`}
as="article"
variant="up"
delay={Math.min(idx, 6) * 60}
className="p-5 hover:bg-ivory/60 transition-colors space-y-2"
>
<div className="flex flex-wrap items-center gap-2 text-xs font-mono text-ink-mute"> <div className="flex flex-wrap items-center gap-2 text-xs font-mono text-ink-mute">
<span className="px-2 py-0.5 rounded bg-ivory border border-line text-ink font-bold"> <span className="px-2 py-0.5 rounded bg-ivory border border-line text-ink font-bold">
{pub.publishedAt?.substring(0, 7) || "Recent"} {pub.publishedAt?.substring(0, 7) || "Recent"}
@@ -76,7 +87,7 @@ export default function PublicationsIndexPage() {
{pub.venue}{pub.volume ? `, ${pub.volume}` : ""} {pub.venue}{pub.volume ? `, ${pub.volume}` : ""}
</p> </p>
)} )}
</article> </Reveal>
))} ))}
</div> </div>
</section> </section>
@@ -1,6 +1,7 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Reveal from "@/components/Reveal";
import { getStandardsBodies } from "../../lib/api"; import { getStandardsBodies } from "../../lib/api";
import type { StandardsBody } from "../../content/types"; import type { StandardsBody } from "../../content/types";
@@ -16,15 +17,22 @@ export default function StandardizationPage() {
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14"> <div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */} {/* Page Header */}
<section> <section>
<Reveal variant="up">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
International Standardization International Standardization
</h1> </h1>
</Reveal>
</section> </section>
{/* Standards Bodies Section */} {/* Standards Bodies Section */}
<section className="space-y-8 sm:space-y-10 pt-6 md:pt-8 border-t border-line"> <section className="space-y-8 sm:space-y-10 pt-6 md:pt-8 border-t border-line">
{standardsBodies.map((body, idx) => ( {standardsBodies.map((body, idx) => (
<div key={idx} className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6 shadow-sm"> <Reveal
key={idx}
variant="up"
delay={idx * 120}
>
<div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6 shadow-sm">
<div className="flex flex-wrap justify-between items-start gap-4 border-b border-line pb-4"> <div className="flex flex-wrap justify-between items-start gap-4 border-b border-line pb-4">
<div> <div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -105,6 +113,7 @@ export default function StandardizationPage() {
))} ))}
</div> </div>
</div> </div>
</Reveal>
))} ))}
</section> </section>
</div> </div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

+10 -3
View File
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useEffect, useRef, type ElementType, type ReactNode } from "react"; import { useEffect, useRef, type ElementType, type ReactNode, type HTMLAttributes } from "react";
type Variant = "up" | "left" | "right" | "scale"; type Variant = "up" | "left" | "right" | "scale";
@@ -18,7 +18,9 @@ export default function Reveal({
delay = 0, delay = 0,
as: Tag = "div", as: Tag = "div",
className = "", className = "",
}: { style,
...rest
}: HTMLAttributes<HTMLElement> & {
children: ReactNode; children: ReactNode;
variant?: Variant; variant?: Variant;
delay?: number; delay?: number;
@@ -47,12 +49,17 @@ export default function Reveal({
return () => io.disconnect(); return () => io.disconnect();
}, []); }, []);
const combinedStyle = delay
? { ...style, transitionDelay: `${delay}ms` }
: style;
return ( return (
<Tag <Tag
ref={ref} ref={ref}
data-variant={variant} data-variant={variant}
style={delay ? { transitionDelay: `${delay}ms` } : undefined} style={combinedStyle}
className={`reveal ${className}`} className={`reveal ${className}`}
{...rest}
> >
{children} {children}
</Tag> </Tag>
+3
View File
@@ -3,6 +3,9 @@ const nextConfig = {
output: "export", output: "export",
trailingSlash: true, trailingSlash: true,
reactStrictMode: true, reactStrictMode: true,
images: {
unoptimized: true,
},
}; };
module.exports = nextConfig; module.exports = nextConfig;
Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB