Compare commits

...
2 Commits
Author SHA1 Message Date
Godopu a2b626b192 feat(theme,ui): apply pure white background in light mode and improve accessibility
- Update light mode theme tokens to pure white (#ffffff) background and soft gray borders
- Add supports-[height:100dvh] fallback to ProfessorDetailsDialog max-height
- Add aria-hidden to decorative arrows in Header mobile navigation
2026-08-22 22:10:09 +09:00
Godopu 44c21ab59e feat(members,header): overhaul members page with CV dialog and english-ify navigation
- Rewrite Members page to English: LAB MEMBERS, Prof. Seok-Joo Koh, Active Researchers, and Graduates
- Add ProfessorDetailsDialog component with comprehensive CV modal
- Standardize degree course label mappings (Ph. D., M. S.)
- Translate mobile navigation panel and header aria-labels to English
- Update E2E test suite assertions for the updated members structure
2026-08-21 23:16:06 +09:00
6 changed files with 343 additions and 84 deletions
+93 -11
View File
@@ -1,16 +1,98 @@
`body > header > div.hidden.border-b.border-line.desktop\:block > div > span:nth-child(3)` `body > main > div > section.space-y-3 > div > span.font-mono.text-xs.tracking-widest.uppercase.text-cobalt-dark.font-bold`
- "Daegu / South Korea" 로 수정 - 삭제
`body > footer > div.container-content.grid.gap-12.py-16.lg\:grid-cols-12 > div.lg\:col-span-5 > h3``body > footer > div.container-content.grid.gap-12.py-16.lg\:grid-cols-12 > div.lg\:col-span-5 > h3` 앞에 favicon logo 넣어서 `body > header > div.container-content.flex.h-\[4\.25rem\].items-center.justify-between.gap-4.my-2.sm\:my-3 > a`와 같이 변경해줘. `body > main > div > section.space-y-3 > h1`
- 연구실 구성원 -> "LAB MEMBERS"
`body > footer > div.border-t.border-line > div > p.kicker.text-ink-mute` `body > main > div > section.space-y-3 > p`
-거해줘. -
`body > footer > div.container-content.grid.gap-12.py-16.lg\:grid-cols-12 > div.lg\:col-span-4 > address` `body > main > div > section:nth-child(2) > div.font-mono.text-xs.text-cobalt-dark.uppercase.tracking-widest.font-bold`
- 교수 정보, 이메일 주소, 주소 순으로 배치 - 삭제
Footer 레이아웃을 조금 더 구조적이고 모던하게 보이도록 레이아웃을 변경 `body > main > div > section:nth-child(2) > div.font-mono.text-xs.text-cobalt-dark.uppercase.tracking-widest.font-bold`
- "고석주 교수" -> "Prof. Seok-Joo Koh"로 변경
`body > main > div > section.relative > div.grid.grid-cols-1.lg\:grid-cols-12.gap-8.lg\:items-center > div.lg\:col-span-7.space-y-6.lg\:pt-4 > div` `body > main > div > section:nth-child(2) > div.bg-paper.p-8.rounded-lg.border.border-line.grid.grid-cols-1.lg\:grid-cols-12.gap-8.items-center > div.lg\:col-span-8.space-y-4 > div.flex.items-baseline.gap-3 > span`
- International Journals & Conference, Standardization Contributions, Patent 순으로 배치 - 삭제
- "PATENT" -> "PATENT\n(IoT Architecture \& Protocols) 수정
`body > main > div > section:nth-child(2) > div.bg-paper.p-8.rounded-lg.border.border-line.grid.grid-cols-1.lg\:grid-cols-12.gap-8.items-center > div.lg\:col-span-8.space-y-4 > p`
- 다음 세부 커리어를 기반으로 설명 작성 (영어로) 및 details 링크 연결.
- details 링크 클릭 시 modal dialog를 통해 아래 세부 내용 보여주기
```
# Education
- KAIST, Management Science, B. S., 1992. 2.
- KAIST, Management Science, M. S., 1994. 2.
- KAIST, Industrial Engineering, Ph. D., 1998. 8.
# Career
2024. 3 - Present
Dean
College of IT Engineering (CITE)
Kyungpook National University (KNU)
2015. 12 - Present
Director
Institute of Software Education (SWEDU)
Kyungpook National University (KNU)
2004. 3 - Present
Professor
School of Computer Science and Engineering (CSE)
College of IT Engineering (CITE)
Kyungpook National University (KNU)
1998. 8 - 2004. 2
Senior Researcher
Protocol Engineering Center (PEC)
Electronics Telecommunications Research Institute (ETRI)
# International Standardization
- ISO/IEC JTC1 SC6/WG7: Reliable/Mobile Multicasting (1999 ~ 2019): Project Editor
- ISO/IEC JTC1 SC41/WG5: Internet-of-Things (IoT) Applications (2020 ~ Present): Project Editor
- ITU-T SG13: Mobility Management (1999 ~ 2015): Project Editor
- ITU-T SG20: VLC-based IoT (2018 ~ 2020): Project Editor
- IEC TC100: Multimedia Systems and Equipment (2018 ~ Present): Project Editor, TA15 TAM, WG11 Convenor
# Membership on Academic Society
- KIPS (Korea Information Processing Society)
- KICS (Korean Institute of Communications and Information Sciences)
- KIISE (Korean Institute of Information Scientists and Engineers)
- IEEE (Institute of Electrical and Electronics Engineers)
```
`body > main > div > section.space-y-8.pt-6.md\:pt-10.border-t.border-line > div.flex.justify-between.items-end > div > div`
- 삭제
`body > main > div > section.space-y-8.pt-6.md\:pt-10.border-t.border-line > div.flex.justify-between.items-end > div > h2`
- "재학 연구원" -> Active Researchers
- 글자색 변경: primary color
`body > main > div > section.space-y-8.pt-6.md\:pt-10.border-t.border-line > div:nth-child(2)`
- PhD -> Ph. D
- PhDCandidate -> Ph. D. Candidate
- PhDStudent -> Ph. D. Student
`body > main > div > section.space-y-8.pt-6.md\:pt-10.border-t.border-line > div.space-y-4.pt-4`
- MSCandidate -> M. S. Candidate
- MSStudent -> M. S. Student
`body > main > div > section:nth-child(4) > div > div > div`
- 삭제
`body > main > div > section:nth-child(4) > div > div > h2`
- 졸업생 목록 -> "Graduates"
`body > main > div > section:nth-child(4) > details > summary > div > span`
- 영어로 작성
`body > main > div > section:nth-child(4) > details > summary > div > p`
- 영어로 작성
`body > main > div > section:nth-child(4) > details > summary > span > span.group-open\:hidden`
- 전체 보기 -> Open
- 삭제된 component들의 크기를 반영하여 화면 비율 조정
+5 -5
View File
@@ -41,10 +41,10 @@
--ink-rgb: 10 10 10; --ink-rgb: 10 10 10;
--ink-soft-rgb: 38 36 32; --ink-soft-rgb: 38 36 32;
--ink-mute-rgb: 107 101 91; --ink-mute-rgb: 107 114 128;
--ivory-rgb: 245 241 232; --ivory-rgb: 255 255 255;
--paper-rgb: 236 230 214; --paper-rgb: 248 249 250;
--line-rgb: 216 209 192; --line-rgb: 229 231 235;
--vermillion-rgb: 217 52 43; --vermillion-rgb: 217 52 43;
--vermillion-dark-rgb: 168 35 28; --vermillion-dark-rgb: 168 35 28;
--cobalt-rgb: 78 119 255; --cobalt-rgb: 78 119 255;
@@ -61,7 +61,7 @@
--cobalt: rgb(var(--cobalt-rgb)); --cobalt: rgb(var(--cobalt-rgb));
--cobalt-dark: rgb(var(--cobalt-dark-rgb)); --cobalt-dark: rgb(var(--cobalt-dark-rgb));
--grain-color: rgba(10, 10, 10, 0.022); --grain-color: rgba(10, 10, 10, 0.015);
/* CUSTOMIZATION HOOK — MOTION: global reveal timing */ /* CUSTOMIZATION HOOK — MOTION: global reveal timing */
--reveal-duration: 600ms; --reveal-duration: 600ms;
@@ -0,0 +1,179 @@
"use client";
import React, { useRef } from "react";
// CUSTOMIZATION HOOK: Detailed career & background data for Prof. Seok-Joo Koh
const EDUCATION = [
"KAIST, Management Science, B. S., 1992. 2.",
"KAIST, Management Science, M. S., 1994. 2.",
"KAIST, Industrial Engineering, Ph. D., 1998. 8.",
];
const CAREER = [
{
period: "2024. 3 - Present",
role: "Dean",
org: "College of IT Engineering (CITE)",
inst: "Kyungpook National University (KNU)",
},
{
period: "2015. 12 - Present",
role: "Director",
org: "Institute of Software Education (SWEDU)",
inst: "Kyungpook National University (KNU)",
},
{
period: "2004. 3 - Present",
role: "Professor",
org: "School of Computer Science and Engineering (CSE), College of IT Engineering (CITE)",
inst: "Kyungpook National University (KNU)",
},
{
period: "1998. 8 - 2004. 2",
role: "Senior Researcher",
org: "Protocol Engineering Center (PEC)",
inst: "Electronics Telecommunications Research Institute (ETRI)",
},
];
const STANDARDIZATION = [
"ISO/IEC JTC1 SC6/WG7: Reliable/Mobile Multicasting (1999 ~ 2019): Project Editor",
"ISO/IEC JTC1 SC41/WG5: Internet-of-Things (IoT) Applications (2020 ~ Present): Project Editor",
"ITU-T SG13: Mobility Management (1999 ~ 2015): Project Editor",
"ITU-T SG20: VLC-based IoT (2018 ~ 2020): Project Editor",
"IEC TC100: Multimedia Systems and Equipment (2018 ~ Present): Project Editor, TA15 TAM, WG11 Convenor",
];
const MEMBERSHIPS = [
"KIPS (Korea Information Processing Society)",
"KICS (Korean Institute of Communications and Information Sciences)",
"KIISE (Korean Institute of Information Scientists and Engineers)",
"IEEE (Institute of Electrical and Electronics Engineers)",
];
export function ProfessorDetailsDialog() {
const dialogRef = useRef<HTMLDialogElement>(null);
const handleOpen = () => {
dialogRef.current?.showModal();
};
const handleClose = () => {
dialogRef.current?.close();
};
const handleBackdropClick = (e: React.MouseEvent<HTMLDialogElement>) => {
if (e.target === dialogRef.current) {
dialogRef.current?.close();
}
};
return (
<>
<button
type="button"
onClick={handleOpen}
className="inline-flex items-center gap-1 font-mono text-xs font-semibold text-cobalt-dark hover:underline focus:outline-none focus:ring-1 focus:ring-cobalt-dark rounded"
aria-haspopup="dialog"
>
<span>Details </span>
</button>
<dialog
ref={dialogRef}
aria-labelledby="prof-dialog-title"
onClick={handleBackdropClick}
className="bg-paper text-ink border border-line rounded-lg p-0 max-w-2xl w-[92vw] max-h-[85vh] supports-[height:100dvh]:max-h-[85dvh] backdrop:bg-ink/50 backdrop:backdrop-blur-sm open:flex open:flex-col shadow-2xl m-auto"
>
{/* Modal Header */}
<div className="flex items-center justify-between border-b border-line p-6 bg-paper sticky top-0 z-10">
<div>
<span className="font-mono text-xs text-cobalt-dark uppercase tracking-wider font-bold">
Curriculum Vitae
</span>
<h2
id="prof-dialog-title"
className="font-serif text-2xl font-normal text-ink mt-0.5"
>
Prof. Seok-Joo Koh
</h2>
</div>
<button
type="button"
onClick={handleClose}
aria-label="Close dialog"
className="p-1.5 rounded border border-line hover:bg-ivory text-ink-mute hover:text-ink transition-colors font-mono text-xs"
>
Close
</button>
</div>
{/* Modal Scrollable Content */}
<div className="p-6 sm:p-8 space-y-8 overflow-y-auto overscroll-contain text-sm">
{/* Education */}
<section className="space-y-3">
<h3 className="font-mono text-xs font-bold uppercase tracking-wider text-cobalt-dark border-b border-line pb-1.5">
Education
</h3>
<ul className="space-y-2 text-ink/90 font-sans">
{EDUCATION.map((edu, idx) => (
<li key={idx} className="flex items-start gap-2.5">
<span className="inline-block w-1.5 h-1.5 rounded-full bg-cobalt-dark mt-2 shrink-0"></span>
<span>{edu}</span>
</li>
))}
</ul>
</section>
{/* Career */}
<section className="space-y-3">
<h3 className="font-mono text-xs font-bold uppercase tracking-wider text-cobalt-dark border-b border-line pb-1.5">
Career
</h3>
<div className="space-y-4">
{CAREER.map((car, idx) => (
<div key={idx} className="border-l-2 border-line pl-3 space-y-0.5">
<div className="font-mono text-xs text-ink-mute">{car.period}</div>
<div className="font-medium text-ink">
{car.role} · <span className="text-ink-mute font-normal">{car.org}</span>
</div>
<div className="text-xs text-ink-soft">{car.inst}</div>
</div>
))}
</div>
</section>
{/* International Standardization */}
<section className="space-y-3">
<h3 className="font-mono text-xs font-bold uppercase tracking-wider text-cobalt-dark border-b border-line pb-1.5">
International Standardization
</h3>
<ul className="space-y-2.5 text-ink/90 font-sans">
{STANDARDIZATION.map((std, idx) => (
<li key={idx} className="flex items-start gap-2.5 leading-relaxed">
<span className="inline-block w-1.5 h-1.5 rounded-full bg-cobalt-dark mt-2 shrink-0"></span>
<span>{std}</span>
</li>
))}
</ul>
</section>
{/* Membership on Academic Society */}
<section className="space-y-3">
<h3 className="font-mono text-xs font-bold uppercase tracking-wider text-cobalt-dark border-b border-line pb-1.5">
Membership on Academic Society
</h3>
<ul className="grid grid-cols-1 sm:grid-cols-2 gap-2 text-ink/90 font-sans">
{MEMBERSHIPS.map((mem, idx) => (
<li key={idx} className="flex items-start gap-2">
<span className="inline-block w-1.5 h-1.5 rounded-full bg-cobalt-dark mt-2 shrink-0"></span>
<span>{mem}</span>
</li>
))}
</ul>
</section>
</div>
</dialog>
</>
);
}
+46 -53
View File
@@ -1,74 +1,73 @@
import React from "react"; import React from "react";
import { activeMembers, alumni } from "../../content/members"; import { activeMembers, alumni } from "../../content/members";
import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog";
const DEGREE_LABEL: Record<string, string> = {
Professor: "Professor",
PhD: "Ph. D.",
PhDCandidate: "Ph. D. Candidate",
PhDStudent: "Ph. D. Student",
MSCandidate: "M. S. Candidate",
MSStudent: "M. S. Student",
MS: "M. S.",
};
export default function MembersPage() { export default function MembersPage() {
const professor = activeMembers.find((m) => m.degree === "Professor");
const phdStudents = activeMembers.filter( const phdStudents = activeMembers.filter(
(m) => m.degree === "PhD" || m.degree === "PhDCandidate" || m.degree === "PhDStudent" (m) =>
m.degree === "PhD" ||
m.degree === "PhDCandidate" ||
m.degree === "PhDStudent"
); );
const msStudents = activeMembers.filter( const msStudents = activeMembers.filter(
(m) => m.degree === "MSCandidate" || m.degree === "MSStudent" (m) => m.degree === "MSCandidate" || m.degree === "MSStudent"
); );
return ( return (
<div className="container-content space-y-12 md:space-y-16 pt-10 md:pt-16 pb-16 md:pb-24"> <div className="container-content py-8 sm:py-12 space-y-12 sm:space-y-16">
{/* Header */} {/* Page Header */}
<section className="space-y-3"> <section>
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-cobalt-dark"></span>
<span className="font-mono text-xs tracking-widest uppercase text-cobalt-dark font-bold">
People &amp; Researchers
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink"> <h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
LAB MEMBERS
</h1> </h1>
<p className="text-ink-mute text-base max-w-2xl">
16, IT 60 .
</p>
</section> </section>
{/* Professor Section */} {/* Professor Section */}
<section className="space-y-6 pt-6 md:pt-10 border-t border-line"> <section className="space-y-6 pt-6 md:pt-10 border-t border-line">
<div className="font-mono text-xs text-cobalt-dark uppercase tracking-widest font-bold">
Faculty
</div>
<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">
<div className="flex items-baseline gap-3"> <h2 className="font-serif text-3xl font-normal text-ink">
<h2 className="font-serif text-3xl font-normal text-ink"> Prof. Seok-Joo Koh
{professor?.ko || "고석주"} </h2>
</h2> <div className="text-sm text-ink-mute leading-relaxed space-y-2">
<span className="font-mono text-sm text-ink-mute"> <p>
{professor?.en || "Seok-Joo Koh"}, Professor Professor at the School of Computer Science and Engineering, Kyungpook National University, and Dean of the College of IT Engineering. He directs the AI Agent Networking Laboratory (ANL), leading research on QUIC/gRPC transport, A2A/ACP protocols, MCP &amp; SKILL architectures, and multi-agent orchestration, and serves as Project Editor in ISO/IEC JTC1, ITU-T, and IEC TC100.
</span> </p>
<div>
<ProfessorDetailsDialog />
</div>
</div> </div>
<p className="text-sm text-ink-mute leading-relaxed">
· AI (ANL) .
QUIC/gRPC , A2A/ACP , MCP &amp; SKILL .
</p>
<div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono"> <div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono">
<a <a
href="mailto:sjkoh@knu.ac.kr" href="mailto:sjkoh@knu.ac.kr"
className="text-cobalt-dark hover:underline" className="text-cobalt-dark hover:underline font-bold"
> >
sjkoh@knu.ac.kr sjkoh@knu.ac.kr
</a> </a>
<span className="text-ink-mute"></span> <span className="text-ink-mute">|</span>
<a <a
href="https://github.com/sjkoh12" href="https://github.com/sjkoh12"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
className="text-cobalt-dark hover:underline" className="text-ink hover:text-cobalt-dark hover:underline"
> >
GitHub @sjkoh12 GitHub Profile
</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 bg-ivory p-6 rounded border border-line text-xs space-y-2 font-mono">
<div className="text-ink font-bold border-b border-line pb-1"> <div className="text-ink font-bold border-b border-line pb-1">
Affiliation & Office Affiliation &amp; Office
</div> </div>
<p className="text-ink-mute">Kyungpook National University</p> <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">IT Building #5 Room 527</p>
@@ -81,11 +80,8 @@ export default function MembersPage() {
<section className="space-y-8 pt-6 md:pt-10 border-t border-line"> <section className="space-y-8 pt-6 md:pt-10 border-t border-line">
<div className="flex justify-between items-end"> <div className="flex justify-between items-end">
<div> <div>
<div className="font-mono text-xs text-cobalt-dark uppercase tracking-widest font-bold"> <h2 className="font-serif text-3xl font-normal text-cobalt-dark">
Active Researchers ({activeMembers.length} Members) Active Researchers
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
</h2> </h2>
</div> </div>
</div> </div>
@@ -106,7 +102,7 @@ export default function MembersPage() {
{mem.ko} {mem.ko}
</span> </span>
<span className="font-mono text-xs text-cobalt-dark"> <span className="font-mono text-xs text-cobalt-dark">
{mem.degree} {DEGREE_LABEL[mem.degree] || mem.degree}
</span> </span>
</div> </div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div> <div className="font-mono text-xs text-ink-mute">{mem.en}</div>
@@ -136,7 +132,7 @@ export default function MembersPage() {
{mem.ko} {mem.ko}
</span> </span>
<span className="font-mono text-xs text-cobalt-dark"> <span className="font-mono text-xs text-cobalt-dark">
{mem.degree} {DEGREE_LABEL[mem.degree] || mem.degree}
</span> </span>
</div> </div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div> <div className="font-mono text-xs text-ink-mute">{mem.en}</div>
@@ -155,11 +151,8 @@ export default function MembersPage() {
<section className="space-y-6 pt-6 md:pt-10 border-t border-line"> <section className="space-y-6 pt-6 md:pt-10 border-t border-line">
<div className="flex justify-between items-end"> <div className="flex justify-between items-end">
<div> <div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-widest font-bold"> <h2 className="font-serif text-3xl font-normal text-ink">
Alumni Inventory ({alumni.length} Graduates) Graduates
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
</h2> </h2>
</div> </div>
</div> </div>
@@ -168,15 +161,15 @@ export default function MembersPage() {
<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-xl font-normal text-ink"> <span className="font-serif text-xl font-normal text-ink">
{alumni.length} Browse all graduates
</span> </span>
<p className="text-xs text-ink-mute font-mono"> <p className="text-xs text-ink-mute font-mono">
2007 2026 (Ph.D.) (M.S.) Ph. D. and M. S. graduates conferred from 2007 to 2026
</p> </p>
</div> </div>
<span className="font-mono text-xs text-vermillion-dark font-bold border border-vermillion-dark px-3 py-1.5 rounded group-open:bg-vermillion-dark group-open:text-white dark:group-open:text-ivory transition-colors"> <span className="font-mono text-xs text-vermillion-dark font-bold border border-vermillion-dark px-3 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"> </span> <span className="group-open:hidden">Open </span>
<span className="hidden group-open:inline"> </span> <span className="hidden group-open:inline">Close </span>
</span> </span>
</summary> </summary>
@@ -191,7 +184,7 @@ export default function MembersPage() {
{alum.ko} ({alum.en}) {alum.ko} ({alum.en})
</span> </span>
<span className="font-mono text-xs text-ink-mute"> <span className="font-mono text-xs text-ink-mute">
{alum.degree} {DEGREE_LABEL[alum.degree] || alum.degree}
</span> </span>
</div> </div>
<div className="font-mono text-xs text-ink-mute flex justify-between"> <div className="font-mono text-xs text-ink-mute flex justify-between">
+13 -12
View File
@@ -12,11 +12,11 @@ const NAV_SETTLE_MS = 300; // ms — 라우트 전환 직후 방향 판정 유
// CUSTOMIZATION HOOK: edit nav labels / routes here. // CUSTOMIZATION HOOK: edit nav labels / routes here.
const navItems = [ const navItems = [
{ href: "/", ko: "홈", en: "Home", no: "01" }, { href: "/", en: "Home", no: "01" },
{ href: "/members", ko: "구성원", en: "Members", no: "02" }, { href: "/members", en: "Members", no: "02" },
{ href: "/publications", ko: "논문", en: "Publications", no: "03" }, { href: "/publications", en: "Publications", no: "03" },
{ href: "/lectures", ko: "강의", en: "Lectures", no: "04" }, { href: "/lectures", en: "Lectures", no: "04" },
{ href: "/standardization", ko: "표준화", en: "Standardization", no: "05" }, { href: "/standardization", en: "Standardization", no: "05" },
]; ];
export default function Header() { export default function Header() {
@@ -170,7 +170,7 @@ export default function Header() {
{/* Desktop nav — small caps, wide tracking (visible at >= 1240px) */} {/* Desktop nav — small caps, wide tracking (visible at >= 1240px) */}
<div className="hidden items-center gap-4 desktop:flex"> <div className="hidden items-center gap-4 desktop:flex">
<nav className="flex items-center gap-2" aria-label="주 메뉴"> <nav className="flex items-center gap-2" aria-label="Main Navigation">
{navItems.map((item) => { {navItems.map((item) => {
const active = isActive(item.href); const active = isActive(item.href);
return ( return (
@@ -206,7 +206,7 @@ export default function Header() {
<button <button
type="button" type="button"
className="inline-flex items-center justify-center border border-ink p-2 text-ink transition hover:bg-ink hover:text-ivory" className="inline-flex items-center justify-center border border-ink p-2 text-ink transition hover:bg-ink hover:text-ivory"
aria-label={open ? "메뉴 닫기" : "메뉴 열기"} aria-label={open ? "Close menu" : "Open menu"}
aria-expanded={open} aria-expanded={open}
aria-controls="mobile-menu" aria-controls="mobile-menu"
onClick={() => setOpen((v) => !v)} onClick={() => setOpen((v) => !v)}
@@ -227,7 +227,7 @@ export default function Header() {
<nav <nav
id="mobile-menu" id="mobile-menu"
className="mobile-menu-panel border-t border-ink bg-ivory desktop:hidden" className="mobile-menu-panel border-t border-ink bg-ivory desktop:hidden"
aria-label="모바일 메뉴" aria-label="Mobile Navigation"
> >
<ul className="container-content flex flex-col py-2"> <ul className="container-content flex flex-col py-2">
{navItems.map((item) => { {navItems.map((item) => {
@@ -252,14 +252,15 @@ export default function Header() {
> >
{item.no} {item.no}
</span> </span>
<span className="headline-ko text-lg">{item.ko}</span> <span className="font-sans text-base">{item.en}</span>
</span> </span>
<span <span
className={`text-[0.7rem] font-semibold uppercase tracking-[0.18em] ${ aria-hidden="true"
active ? "text-white dark:text-ivory" : "text-ink-mute" className={`text-xs font-mono ${
active ? "text-white/80 dark:text-ivory/80" : "text-ink-mute"
}`} }`}
> >
{item.en}
</span> </span>
</Link> </Link>
</li> </li>
+7 -3
View File
@@ -54,12 +54,16 @@ class TestANLHomepageE2E(unittest.TestCase):
html = self.read_html("members.html") html = self.read_html("members.html")
# Professor profile # Professor profile
self.assertIn("고석주", html) self.assertIn("Prof. Seok-Joo Koh", html)
self.assertIn("Seok-Joo Koh", html) self.assertIn("Seok-Joo Koh", html)
self.assertIn("sjkoh@knu.ac.kr", html) self.assertIn("sjkoh@knu.ac.kr", html)
# Members content sanity checks # Sections & Degree formatting checks
self.assertIn("Members", html) self.assertIn("LAB MEMBERS", html)
self.assertIn("Active Researchers", html)
self.assertIn("Graduates", html)
self.assertIn("Ph. D. Candidate", html)
self.assertIn("Project Editor", html)
def test_03_publications_category_routes(self): def test_03_publications_category_routes(self):
"""TC-T1-F5: Verify Publications categories SSG static pages.""" """TC-T1-F5: Verify Publications categories SSG static pages."""