Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3972cac27 | ||
|
|
b0bce3be8e | ||
|
|
ca6e85ce9b |
@@ -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,22 +14,24 @@ export function ProjectPageView({ projects: projectsProp }: ProjectPageViewProps
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-6">
|
<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">
|
<Reveal variant="up">
|
||||||
<div>
|
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
|
||||||
<div className="flex items-center gap-3 mb-1">
|
<div>
|
||||||
<span className="h-px w-8 bg-cobalt-dark"></span>
|
<div className="flex items-center gap-3 mb-1">
|
||||||
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
<span className="h-px w-8 bg-cobalt-dark"></span>
|
||||||
Key Initiatives
|
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
||||||
</span>
|
Key Initiatives
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
||||||
|
Research Projects
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
<p className="text-xs text-ink-mute font-mono">
|
||||||
Research Projects
|
{projects.length} core international standardization research projects
|
||||||
</h2>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-ink-mute font-mono">
|
</Reveal>
|
||||||
{projects.length} core international standardization research projects
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 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>
|
||||||
|
|
||||||
|
|||||||
@@ -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,110 +24,124 @@ 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>
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
<Reveal variant="up">
|
||||||
LECTURES
|
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
||||||
</h1>
|
LECTURES
|
||||||
|
</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">
|
||||||
<div className="flex justify-between items-center">
|
<Reveal variant="up">
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
<div className="flex justify-between items-center">
|
||||||
Recent Courses
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
||||||
</h2>
|
Recent Courses
|
||||||
<span className="font-mono text-xs text-ink-mute hidden sm:inline">
|
</h2>
|
||||||
Latest 3 Semesters
|
<span className="font-mono text-xs text-ink-mute hidden sm:inline">
|
||||||
</span>
|
Latest 3 Semesters
|
||||||
</div>
|
</span>
|
||||||
|
</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="space-y-3">
|
<div
|
||||||
<div className="flex justify-between items-center border-b border-line pb-2.5">
|
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"
|
||||||
<span className="font-serif text-lg sm:text-xl font-normal text-ink">
|
>
|
||||||
{sem.term} {sem.year}
|
<div className="space-y-3">
|
||||||
</span>
|
<div className="flex justify-between items-center border-b border-line pb-2.5">
|
||||||
<span className="font-mono text-[0.7rem] uppercase tracking-wider text-vermillion-dark font-bold px-2 py-0.5 rounded bg-vermillion-dark/10">
|
<span className="font-serif text-lg sm:text-xl font-normal text-ink">
|
||||||
Latest
|
{sem.term} {sem.year}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="font-mono text-[0.7rem] uppercase tracking-wider text-vermillion-dark font-bold px-2 py-0.5 rounded bg-vermillion-dark/10">
|
||||||
|
Latest
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-2.5 pt-1">
|
||||||
|
{sem.courses.map((c, cIdx) => (
|
||||||
|
<li key={cIdx} className="space-y-0.5">
|
||||||
|
<div className="font-serif text-sm sm:text-base text-ink leading-snug">
|
||||||
|
{c.en}
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-ink-mute">
|
||||||
|
Code: {c.code} {c.note && `(${c.note})`}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className="space-y-2.5 pt-1">
|
<div className="pt-3 border-t border-line/60 font-mono text-xs text-ink-mute flex justify-between items-center">
|
||||||
{sem.courses.map((c, cIdx) => (
|
<span>Total Offerings</span>
|
||||||
<li key={cIdx} className="space-y-0.5">
|
<span className="font-semibold text-ink">{sem.courses.length} Courses</span>
|
||||||
<div className="font-serif text-sm sm:text-base text-ink leading-snug">
|
</div>
|
||||||
{c.en}
|
|
||||||
</div>
|
|
||||||
<div className="font-mono text-xs text-ink-mute">
|
|
||||||
Code: {c.code} {c.note && `(${c.note})`}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Reveal>
|
||||||
<div className="pt-3 border-t border-line/60 font-mono text-xs text-ink-mute flex justify-between items-center">
|
|
||||||
<span>Total Offerings</span>
|
|
||||||
<span className="font-semibold text-ink">{sem.courses.length} Courses</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</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">
|
||||||
<summary className="flex justify-between items-center cursor-pointer list-none select-none">
|
<div className="border border-line rounded-lg bg-paper p-5 sm:p-6 transition-all duration-200">
|
||||||
<div className="space-y-1">
|
<details className="group">
|
||||||
<span className="font-serif text-lg sm:text-xl font-normal text-ink">
|
<summary className="flex justify-between items-center cursor-pointer list-none select-none">
|
||||||
Browse all semesters
|
<div className="space-y-1">
|
||||||
</span>
|
<span className="font-serif text-lg sm:text-xl font-normal text-ink">
|
||||||
<p className="text-xs text-ink-mute font-mono">
|
Browse all semesters
|
||||||
Course history from {oldestSem ? `${oldestSem.year} ${oldestSem.term}` : "2004 Spring"} to {newestOlderSem ? `${newestOlderSem.year} ${newestOlderSem.term}` : "2024 Fall"} ({olderSemesters.length} Semesters)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<span className="font-mono text-xs text-vermillion-dark font-bold border border-vermillion-dark px-3.5 py-1.5 rounded group-open:bg-vermillion-dark group-open:text-white dark:group-open:text-ivory transition-colors">
|
|
||||||
<span className="group-open:hidden">Open ▾</span>
|
|
||||||
<span className="hidden group-open:inline">Close ▴</span>
|
|
||||||
</span>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
<div className="mt-6 pt-6 border-t border-line grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 sm:gap-6">
|
|
||||||
{olderSemesters.map((sem, idx) => (
|
|
||||||
<div
|
|
||||||
key={idx}
|
|
||||||
className="bg-ivory p-5 rounded-lg border border-line space-y-3 shadow-sm hover:border-cobalt-dark/40 transition-colors"
|
|
||||||
>
|
|
||||||
<div className="font-serif text-base sm:text-lg font-normal text-ink border-b border-line pb-2 flex justify-between items-center">
|
|
||||||
<span>
|
|
||||||
{sem.term} {sem.year}
|
|
||||||
</span>
|
|
||||||
<span className="font-mono text-xs text-ink-mute">
|
|
||||||
{sem.courses.length} Courses
|
|
||||||
</span>
|
</span>
|
||||||
|
<p className="text-xs text-ink-mute font-mono">
|
||||||
|
Course history from {oldestSem ? `${oldestSem.year} ${oldestSem.term}` : "2004 Spring"} to {newestOlderSem ? `${newestOlderSem.year} ${newestOlderSem.term}` : "2024 Fall"} ({olderSemesters.length} Semesters)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="font-mono text-xs text-vermillion-dark font-bold border border-vermillion-dark px-3.5 py-1.5 rounded group-open:bg-vermillion-dark group-open:text-white dark:group-open:text-ivory transition-colors">
|
||||||
|
<span className="group-open:hidden">Open ▾</span>
|
||||||
|
<span className="hidden group-open:inline">Close ▴</span>
|
||||||
|
</span>
|
||||||
|
</summary>
|
||||||
|
|
||||||
<ul className="space-y-2">
|
<div className="mt-6 pt-6 border-t border-line grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 sm:gap-6">
|
||||||
{sem.courses.map((c, cIdx) => (
|
{olderSemesters.map((sem, idx) => (
|
||||||
<li key={cIdx} className="space-y-0.5">
|
<div
|
||||||
<div className="font-serif text-sm text-ink leading-snug">
|
key={idx}
|
||||||
{c.en}
|
className="bg-ivory p-5 rounded-lg border border-line space-y-3 shadow-sm hover:border-cobalt-dark/40 transition-colors"
|
||||||
</div>
|
>
|
||||||
<div className="font-mono text-[0.7rem] text-ink-mute">
|
<div className="font-serif text-base sm:text-lg font-normal text-ink border-b border-line pb-2 flex justify-between items-center">
|
||||||
Code: {c.code} {c.note && `(${c.note})`}
|
<span>
|
||||||
</div>
|
{sem.term} {sem.year}
|
||||||
</li>
|
</span>
|
||||||
))}
|
<span className="font-mono text-xs text-ink-mute">
|
||||||
</ul>
|
{sem.courses.length} Courses
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{sem.courses.map((c, cIdx) => (
|
||||||
|
<li key={cIdx} className="space-y-0.5">
|
||||||
|
<div className="font-serif text-sm text-ink leading-snug">
|
||||||
|
{c.en}
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-[0.7rem] text-ink-mute">
|
||||||
|
Code: {c.code} {c.note && `(${c.note})`}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
))}
|
</details>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</Reveal>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,121 +44,147 @@ 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>
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
<Reveal variant="up">
|
||||||
LAB MEMBERS
|
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
||||||
</h1>
|
LAB MEMBERS
|
||||||
|
</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">
|
||||||
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
<Reveal variant="up">
|
||||||
<div className="lg:col-span-8 space-y-4">
|
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
||||||
<h2 className="font-serif text-3xl font-normal text-ink">
|
<div className="lg:col-span-8 space-y-4">
|
||||||
Prof. Seok-Joo Koh
|
<h2 className="font-serif text-3xl font-normal text-ink">
|
||||||
</h2>
|
Prof. Seok-Joo Koh
|
||||||
<div className="text-sm text-ink-mute leading-relaxed space-y-2">
|
</h2>
|
||||||
<p>
|
<div className="text-sm text-ink-mute leading-relaxed space-y-2">
|
||||||
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 & SKILL architectures, and multi-agent orchestration, and serves as Project Editor in ISO/IEC JTC1, ITU-T, and IEC TC100.
|
<p>
|
||||||
</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 & SKILL architectures, and multi-agent orchestration, and serves as Project Editor in ISO/IEC JTC1, ITU-T, and IEC TC100.
|
||||||
<div>
|
</p>
|
||||||
<ProfessorDetailsDialog />
|
<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>
|
</div>
|
||||||
<div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono">
|
<div className="lg:col-span-4 flex justify-center items-center">
|
||||||
<a
|
<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">
|
||||||
href="mailto:sjkoh@knu.ac.kr"
|
<Image
|
||||||
className="text-cobalt-dark hover:underline font-bold"
|
src="/images/prof_profile.png"
|
||||||
>
|
alt="Prof. Seok-Joo Koh"
|
||||||
sjkoh@knu.ac.kr
|
fill
|
||||||
</a>
|
sizes="(max-width: 1024px) 224px, 240px"
|
||||||
<span className="text-ink-mute">|</span>
|
className="object-cover object-top"
|
||||||
<a
|
priority
|
||||||
href="https://github.com/sjkoh12"
|
/>
|
||||||
target="_blank"
|
</div>
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-ink hover:text-cobalt-dark hover:underline"
|
|
||||||
>
|
|
||||||
GitHub Profile ↗
|
|
||||||
</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">
|
</Reveal>
|
||||||
<div className="text-ink font-bold border-b border-line pb-1">
|
|
||||||
Affiliation & Office
|
|
||||||
</div>
|
|
||||||
<p className="text-ink-mute">Kyungpook National University</p>
|
|
||||||
<p className="text-ink-mute">IT Building #5 Room 527</p>
|
|
||||||
<p className="text-ink-mute">Daegu, Republic of Korea</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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">
|
||||||
<div className="flex justify-between items-end">
|
<Reveal variant="up">
|
||||||
<div>
|
<div className="flex justify-between items-end">
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
<div>
|
||||||
Active Researchers
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
||||||
</h2>
|
Active Researchers
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
|
|
||||||
{/* Ph.D. Candidates / Students */}
|
{/* Ph.D. Candidates / Students */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
|
<Reveal variant="up">
|
||||||
Ph.D. Course ({phdStudents.length})
|
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
|
||||||
</h3>
|
Ph.D. Course ({phdStudents.length})
|
||||||
|
</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="flex justify-between items-baseline">
|
<div
|
||||||
<span className="font-serif text-lg font-normal text-ink">
|
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors h-full"
|
||||||
{mem.ko}
|
>
|
||||||
</span>
|
<div className="flex justify-between items-baseline">
|
||||||
<span className="font-mono text-xs text-cobalt-dark">
|
<span className="font-serif text-lg font-normal text-ink">
|
||||||
{DEGREE_LABEL[mem.degree] || mem.degree}
|
{mem.ko}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<span className="font-mono text-xs text-cobalt-dark">
|
||||||
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
|
{DEGREE_LABEL[mem.degree] || mem.degree}
|
||||||
{mem.affiliation && (
|
</span>
|
||||||
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
|
|
||||||
with {mem.affiliation}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* M.S. Candidates / Students */}
|
{/* M.S. Candidates / Students */}
|
||||||
<div className="space-y-4 pt-4">
|
<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">
|
<Reveal variant="up">
|
||||||
M.S. Course ({msStudents.length})
|
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
|
||||||
</h3>
|
M.S. Course ({msStudents.length})
|
||||||
|
</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="flex justify-between items-baseline">
|
<div
|
||||||
<span className="font-serif text-lg font-normal text-ink">
|
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors h-full"
|
||||||
{mem.ko}
|
>
|
||||||
</span>
|
<div className="flex justify-between items-baseline">
|
||||||
<span className="font-mono text-xs text-cobalt-dark">
|
<span className="font-serif text-lg font-normal text-ink">
|
||||||
{DEGREE_LABEL[mem.degree] || mem.degree}
|
{mem.ko}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<span className="font-mono text-xs text-cobalt-dark">
|
||||||
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
|
{DEGREE_LABEL[mem.degree] || mem.degree}
|
||||||
{mem.affiliation && (
|
</span>
|
||||||
<div className="text-xs text-vermillion-dark pt-1 border-t border-line/40">
|
|
||||||
with {mem.affiliation}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,13 +192,15 @@ 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">
|
||||||
<div className="flex justify-between items-end">
|
<Reveal variant="up">
|
||||||
<div>
|
<div className="flex justify-between items-end">
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
<div>
|
||||||
Graduates
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
||||||
</h2>
|
Graduates
|
||||||
|
</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">
|
||||||
|
|||||||
+125
-101
@@ -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,57 +42,67 @@ 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">
|
||||||
<div className="mb-4">
|
<Reveal variant="up">
|
||||||
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
<div className="mb-4">
|
||||||
Kyungpook National University · AI Agent Networking Lab (ANL)
|
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
||||||
</span>
|
Kyungpook National University · AI Agent Networking Lab (ANL)
|
||||||
</div>
|
</span>
|
||||||
|
</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">
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl lg:text-6xl font-normal text-ink leading-tight">
|
<Reveal variant="up">
|
||||||
Multi-Agent <br />
|
<h1 className="font-serif text-4xl sm:text-5xl lg:text-6xl font-normal text-ink leading-tight">
|
||||||
<span className="italic font-serif text-cobalt-dark">Orchestration</span>
|
Multi-Agent <br />
|
||||||
</h1>
|
<span className="italic font-serif text-cobalt-dark">Orchestration</span>
|
||||||
<p className="text-ink-mute text-base sm:text-lg leading-relaxed max-w-2xl">
|
</h1>
|
||||||
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 className="text-ink-mute text-base sm:text-lg leading-relaxed max-w-2xl mt-4">
|
||||||
</p>
|
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>
|
||||||
|
</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">
|
||||||
<div>
|
<Reveal variant="up" delay={80}>
|
||||||
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
<div>
|
||||||
{stats.intlPubsCount}
|
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
||||||
|
<Counter value={stats.intlPubsCount} />
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
||||||
|
International Journals & Conference
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
</Reveal>
|
||||||
International Journals & Conference
|
<Reveal variant="up" delay={160}>
|
||||||
|
<div>
|
||||||
|
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
||||||
|
<Counter value={stats.stdDocsCount} />
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
||||||
|
Standardization Contributions
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
<div>
|
<Reveal variant="up" delay={240}>
|
||||||
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
<div>
|
||||||
{stats.stdDocsCount}
|
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
||||||
|
<Counter value={stats.patentCount} />
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
||||||
|
Patent<br />
|
||||||
|
<span className="text-[0.68rem] tracking-normal font-sans normal-case text-ink-mute">
|
||||||
|
(IoT Architecture & Protocols)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
</Reveal>
|
||||||
Standardization Contributions
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="font-serif text-3xl text-cobalt-dark font-normal">
|
|
||||||
{stats.patentCount}
|
|
||||||
</div>
|
|
||||||
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1 leading-tight">
|
|
||||||
Patent<br />
|
|
||||||
<span className="text-[0.68rem] tracking-normal font-sans normal-case text-ink-mute">
|
|
||||||
(IoT Architecture & Protocols)
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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,22 +111,24 @@ 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">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
|
<Reveal variant="up">
|
||||||
<div>
|
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
|
||||||
<div className="flex items-center gap-3 mb-1">
|
<div>
|
||||||
<span className="h-px w-8 bg-cobalt-dark"></span>
|
<div className="flex items-center gap-3 mb-1">
|
||||||
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
<span className="h-px w-8 bg-cobalt-dark"></span>
|
||||||
Core Domains
|
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
||||||
</span>
|
Core Domains
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
||||||
|
Research Areas
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
<p className="text-xs text-ink-mute font-mono">
|
||||||
Research Areas
|
{researchAreas.length} fundamental networking protocols and AI system domains
|
||||||
</h2>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-ink-mute font-mono">
|
</Reveal>
|
||||||
{researchAreas.length} fundamental networking protocols and AI system domains
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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,28 +136,34 @@ export default function HomePage() {
|
|||||||
const isOdd = (idx + 1) % 2 !== 0;
|
const isOdd = (idx + 1) % 2 !== 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Reveal
|
||||||
key={no}
|
key={no}
|
||||||
className="bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-ink transition-colors duration-200 h-full"
|
variant="up"
|
||||||
|
delay={Math.min(idx, 6) * 60}
|
||||||
|
className="h-full"
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<div
|
||||||
<div className="flex justify-between items-center">
|
className="bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-ink transition-colors duration-200 h-full"
|
||||||
<span
|
>
|
||||||
className={`font-mono text-xs font-bold ${
|
<div className="space-y-3">
|
||||||
isOdd ? "text-vermillion-dark" : "text-cobalt-dark"
|
<div className="flex justify-between items-center">
|
||||||
}`}
|
<span
|
||||||
>
|
className={`font-mono text-xs font-bold ${
|
||||||
{no}
|
isOdd ? "text-vermillion-dark" : "text-cobalt-dark"
|
||||||
</span>
|
}`}
|
||||||
<span className="font-mono text-[0.68rem] text-ink-mute uppercase tracking-wider">
|
>
|
||||||
Topic #{no}
|
{no}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="font-mono text-[0.68rem] text-ink-mute uppercase tracking-wider">
|
||||||
|
Topic #{no}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="font-serif text-base font-normal text-ink leading-snug">
|
||||||
|
{area}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-serif text-base font-normal text-ink leading-snug">
|
|
||||||
{area}
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@@ -151,43 +171,47 @@ 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">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
|
<Reveal variant="up">
|
||||||
<div>
|
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 border-b border-line pb-4">
|
||||||
<div className="flex items-center gap-3 mb-1">
|
<div>
|
||||||
<span className="h-px w-8 bg-cobalt-dark"></span>
|
<div className="flex items-center gap-3 mb-1">
|
||||||
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
<span className="h-px w-8 bg-cobalt-dark"></span>
|
||||||
Global Engagement
|
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
|
||||||
</span>
|
Global Engagement
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
||||||
|
International Standardizations
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
|
|
||||||
International Standardizations
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
|
|
||||||
<div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6">
|
<Reveal variant="up">
|
||||||
<p className="text-ink/80 text-sm sm:text-base leading-relaxed max-w-3xl">
|
<div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6">
|
||||||
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):
|
<p className="text-ink/80 text-sm sm:text-base leading-relaxed max-w-3xl">
|
||||||
</p>
|
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):
|
||||||
|
</p>
|
||||||
|
|
||||||
<ul className="grid grid-cols-1 md:grid-cols-2 gap-3 pt-2">
|
<ul className="grid grid-cols-1 md:grid-cols-2 gap-3 pt-2">
|
||||||
{INTERNATIONAL_SDOS.map((sdo, idx) => (
|
{INTERNATIONAL_SDOS.map((sdo, idx) => (
|
||||||
<li key={idx} className="flex items-start gap-2.5 text-sm text-ink font-sans">
|
<li key={idx} className="flex items-start gap-2.5 text-sm text-ink font-sans">
|
||||||
<span className="inline-block w-1.5 h-1.5 rounded-full bg-cobalt-dark mt-2 shrink-0"></span>
|
<span className="inline-block w-1.5 h-1.5 rounded-full bg-cobalt-dark mt-2 shrink-0"></span>
|
||||||
<span>{sdo}</span>
|
<span>{sdo}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className="pt-4 border-t border-line/60">
|
<div className="pt-4 border-t border-line/60">
|
||||||
<Link
|
<Link
|
||||||
href="/standardization"
|
href="/standardization"
|
||||||
className="inline-flex items-center gap-2 font-mono text-xs font-semibold uppercase tracking-wider text-cobalt-dark hover:text-ink transition-colors draw-underline"
|
className="inline-flex items-center gap-2 font-mono text-xs font-semibold uppercase tracking-wider text-cobalt-dark hover:text-ink transition-colors draw-underline"
|
||||||
>
|
>
|
||||||
<span>Please refer to here for details →</span>
|
<span>Please refer to here for details →</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+56
-44
@@ -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">
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
<Reveal variant="up">
|
||||||
{currentCat.label}
|
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
||||||
</h1>
|
{currentCat.label}
|
||||||
{currentCat.subtitle && (
|
</h1>
|
||||||
<p className="font-mono text-sm text-ink-mute">
|
{currentCat.subtitle && (
|
||||||
{currentCat.subtitle}
|
<p className="font-mono text-sm text-ink-mute mt-1">
|
||||||
</p>
|
{currentCat.subtitle}
|
||||||
)}
|
</p>
|
||||||
|
)}
|
||||||
|
</Reveal>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Category Nav Cards */}
|
{/* Category Nav Cards */}
|
||||||
@@ -96,38 +106,40 @@ 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">
|
||||||
<div className="flex flex-wrap justify-between items-center gap-4 border-b border-line pb-3">
|
<Reveal variant="up">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap justify-between items-center gap-4 border-b border-line pb-3">
|
||||||
<span className="font-mono text-xs text-ink-mute uppercase">Filter Year:</span>
|
<div className="flex items-center gap-2">
|
||||||
<select
|
<span className="font-mono text-xs text-ink-mute uppercase">Filter Year:</span>
|
||||||
value={selectedYear}
|
<select
|
||||||
onChange={(e) => setSelectedYear(e.target.value)}
|
value={selectedYear}
|
||||||
className="px-2.5 py-1 text-xs border border-line rounded bg-paper text-ink focus:outline-none focus:ring-1 focus:ring-cobalt font-mono"
|
onChange={(e) => setSelectedYear(e.target.value)}
|
||||||
>
|
className="px-2.5 py-1 text-xs border border-line rounded bg-paper text-ink focus:outline-none focus:ring-1 focus:ring-cobalt font-mono"
|
||||||
<option value="all">All Years ({allRecords.length})</option>
|
|
||||||
{availableYears.map((yr) => {
|
|
||||||
const yrCount = allRecords.filter((r) => (r.publishedAt || "").includes(yr)).length;
|
|
||||||
return (
|
|
||||||
<option key={yr} value={yr}>
|
|
||||||
{yr} ({yrCount})
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
{selectedYear !== "all" && (
|
|
||||||
<button
|
|
||||||
onClick={() => setSelectedYear("all")}
|
|
||||||
className="text-xs text-cobalt-dark hover:underline font-mono"
|
|
||||||
>
|
>
|
||||||
Reset
|
<option value="all">All Years ({allRecords.length})</option>
|
||||||
</button>
|
{availableYears.map((yr) => {
|
||||||
)}
|
const yrCount = allRecords.filter((r) => (r.publishedAt || "").includes(yr)).length;
|
||||||
</div>
|
return (
|
||||||
|
<option key={yr} value={yr}>
|
||||||
|
{yr} ({yrCount})
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
{selectedYear !== "all" && (
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedYear("all")}
|
||||||
|
className="text-xs text-cobalt-dark hover:underline font-mono"
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<span className="font-mono text-xs text-ink-mute uppercase">
|
<span className="font-mono text-xs text-ink-mute uppercase">
|
||||||
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,87 +26,95 @@ export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex justify-between items-center">
|
<Reveal variant="up">
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
<div className="flex justify-between items-center">
|
||||||
Categories
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
||||||
</h2>
|
Categories
|
||||||
{currentCategory && (
|
</h2>
|
||||||
<Link
|
{currentCategory && (
|
||||||
href="/publications"
|
<Link
|
||||||
className="font-mono text-xs text-ink-mute hover:text-ink hover:underline transition-colors"
|
href="/publications"
|
||||||
>
|
className="font-mono text-xs text-ink-mute hover:text-ink hover:underline transition-colors"
|
||||||
← Overview
|
>
|
||||||
</Link>
|
← Overview
|
||||||
)}
|
</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"
|
||||||
isActive
|
delay={idx * 80}
|
||||||
? "border-2 border-cobalt-dark shadow-md"
|
className="h-full"
|
||||||
: "border border-line shadow-sm hover:border-cobalt-dark/40"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<div
|
||||||
<div className="flex justify-between items-center">
|
className={`flex flex-col justify-between bg-paper p-5 sm:p-6 rounded-lg transition-all h-full ${
|
||||||
<span
|
isActive
|
||||||
className={`font-mono text-xs font-bold uppercase tracking-wider ${
|
? "border-2 border-cobalt-dark shadow-md"
|
||||||
isActive ? "text-cobalt-dark" : "text-ink-mute"
|
: "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
|
{cat.label}
|
||||||
</span>
|
{cat.subtitle && (
|
||||||
{isActive && (
|
<span className="block text-xs font-mono text-ink-mute mt-1 font-normal">
|
||||||
<span className="font-mono text-[0.65rem] font-bold px-2 py-0.5 rounded bg-cobalt-dark/10 text-cobalt-dark uppercase">
|
{cat.subtitle}
|
||||||
Current
|
</span>
|
||||||
</span>
|
)}
|
||||||
)}
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3
|
<div className="mt-6 pt-4 border-t border-line flex items-baseline justify-between">
|
||||||
className={`font-serif text-xl ${
|
<span className="font-display text-3xl font-bold text-ink">
|
||||||
isActive ? "text-cobalt-dark font-normal" : "text-ink font-normal"
|
<Counter value={count} />
|
||||||
}`}
|
<span className="text-xs font-mono text-ink-mute ml-1 font-normal">
|
||||||
>
|
{cat.slug === "patent" ? "Patents" : "Papers"}
|
||||||
{cat.label}
|
|
||||||
{cat.subtitle && (
|
|
||||||
<span className="block text-xs font-mono text-ink-mute mt-1 font-normal">
|
|
||||||
{cat.subtitle}
|
|
||||||
</span>
|
</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 →
|
||||||
|
</Link>
|
||||||
)}
|
)}
|
||||||
</h3>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Reveal>
|
||||||
<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 →
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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>
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
<Reveal variant="up">
|
||||||
PUBLICATIONS
|
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
||||||
</h1>
|
PUBLICATIONS
|
||||||
|
</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">
|
||||||
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
<Reveal variant="up">
|
||||||
Highlights
|
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
|
||||||
</h2>
|
Highlights
|
||||||
|
</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,95 +17,103 @@ 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>
|
||||||
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
<Reveal variant="up">
|
||||||
International Standardization
|
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
|
||||||
</h1>
|
International Standardization
|
||||||
|
</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
|
||||||
<div className="flex flex-wrap justify-between items-start gap-4 border-b border-line pb-4">
|
key={idx}
|
||||||
<div>
|
variant="up"
|
||||||
<div className="flex items-center gap-2">
|
delay={idx * 120}
|
||||||
<span className="font-mono text-xs text-cobalt-dark font-bold uppercase">
|
>
|
||||||
[{body.scope}]
|
<div className="bg-paper p-6 sm:p-8 rounded-lg border border-line space-y-6 shadow-sm">
|
||||||
</span>
|
<div className="flex flex-wrap justify-between items-start gap-4 border-b border-line pb-4">
|
||||||
{body.role && (
|
<div>
|
||||||
<span className="bg-vermillion-dark text-ivory font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold">
|
<div className="flex items-center gap-2">
|
||||||
{body.role}
|
<span className="font-mono text-xs text-cobalt-dark font-bold uppercase">
|
||||||
|
[{body.scope}]
|
||||||
</span>
|
</span>
|
||||||
)}
|
{body.role && (
|
||||||
</div>
|
<span className="bg-vermillion-dark text-ivory font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold">
|
||||||
<h2 className="font-serif text-2xl font-normal text-ink mt-1">
|
{body.role}
|
||||||
{body.org}
|
|
||||||
</h2>
|
|
||||||
<p className="text-xs text-ink-mute font-mono mt-0.5">
|
|
||||||
{body.full} ({body.period})
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="font-mono text-xs text-ink-mute bg-ivory border border-line px-3 py-1.5 rounded">
|
|
||||||
Projects: {body.projects.length}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 3-Tier Hierarchy: Projects & Documents */}
|
|
||||||
<div className="space-y-6">
|
|
||||||
{body.projects.map((proj, pIdx) => (
|
|
||||||
<div key={pIdx} className="bg-ivory p-6 rounded border border-line space-y-3">
|
|
||||||
<div className="font-serif text-lg font-normal text-ink border-b border-line/60 pb-2 flex justify-between items-center">
|
|
||||||
<div>
|
|
||||||
<span className="font-mono text-xs text-cobalt-dark font-bold mr-2">
|
|
||||||
{proj.wg}
|
|
||||||
</span>
|
</span>
|
||||||
<span>{proj.name}</span>
|
)}
|
||||||
</div>
|
|
||||||
<span className="font-mono text-xs text-ink-mute">
|
|
||||||
{proj.documents.length} Docs
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<h2 className="font-serif text-2xl font-normal text-ink mt-1">
|
||||||
{proj.documents.length > 0 ? (
|
{body.org}
|
||||||
<div className="space-y-3 pt-1">
|
</h2>
|
||||||
{proj.documents.map((doc, dIdx) => (
|
<p className="text-xs text-ink-mute font-mono mt-0.5">
|
||||||
<div
|
{body.full} ({body.period})
|
||||||
key={dIdx}
|
</p>
|
||||||
className="bg-paper p-4 rounded border border-line/60 space-y-1.5"
|
|
||||||
>
|
|
||||||
<div className="flex justify-between items-start gap-4">
|
|
||||||
<h3 className="font-serif text-base font-normal text-ink leading-snug">
|
|
||||||
“{doc.title}”
|
|
||||||
</h3>
|
|
||||||
<span
|
|
||||||
className={`font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold shrink-0 ${
|
|
||||||
doc.status === "InProgress"
|
|
||||||
? "bg-vermillion-dark text-ivory"
|
|
||||||
: "bg-cobalt-dark text-ivory"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{doc.status}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="font-mono text-xs text-ink-mute flex justify-between">
|
|
||||||
<span>{doc.ref}</span>
|
|
||||||
{doc.publishedAt && (
|
|
||||||
<span className="text-ink">{doc.publishedAt}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="text-xs text-ink-mute font-mono italic">
|
|
||||||
Project specification in progress
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
|
<div className="font-mono text-xs text-ink-mute bg-ivory border border-line px-3 py-1.5 rounded">
|
||||||
|
Projects: {body.projects.length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 3-Tier Hierarchy: Projects & Documents */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
{body.projects.map((proj, pIdx) => (
|
||||||
|
<div key={pIdx} className="bg-ivory p-6 rounded border border-line space-y-3">
|
||||||
|
<div className="font-serif text-lg font-normal text-ink border-b border-line/60 pb-2 flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<span className="font-mono text-xs text-cobalt-dark font-bold mr-2">
|
||||||
|
{proj.wg}
|
||||||
|
</span>
|
||||||
|
<span>{proj.name}</span>
|
||||||
|
</div>
|
||||||
|
<span className="font-mono text-xs text-ink-mute">
|
||||||
|
{proj.documents.length} Docs
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{proj.documents.length > 0 ? (
|
||||||
|
<div className="space-y-3 pt-1">
|
||||||
|
{proj.documents.map((doc, dIdx) => (
|
||||||
|
<div
|
||||||
|
key={dIdx}
|
||||||
|
className="bg-paper p-4 rounded border border-line/60 space-y-1.5"
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-start gap-4">
|
||||||
|
<h3 className="font-serif text-base font-normal text-ink leading-snug">
|
||||||
|
“{doc.title}”
|
||||||
|
</h3>
|
||||||
|
<span
|
||||||
|
className={`font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold shrink-0 ${
|
||||||
|
doc.status === "InProgress"
|
||||||
|
? "bg-vermillion-dark text-ivory"
|
||||||
|
: "bg-cobalt-dark text-ivory"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{doc.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-ink-mute flex justify-between">
|
||||||
|
<span>{doc.ref}</span>
|
||||||
|
{doc.publishedAt && (
|
||||||
|
<span className="text-ink">{doc.publishedAt}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-xs text-ink-mute font-mono italic">
|
||||||
|
Project specification in progress
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Reveal>
|
||||||
))}
|
))}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
@@ -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,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 |
Reference in New Issue
Block a user