refactor(pages,a11y,seo): enhance subpage metadata, semantic HTML, accessibility, and E2E regression tests

- Standardize Next.js Metadata and dynamic generateMetadata across all subpages
- Fix duplicate main landmark in publications page by replacing nested main with div
- Unify Members page spacing (space-y-10 sm:space-y-14, pt-6 md:pt-8) and responsive H2s
- Add aria-label and focus ring to CategoryNav View All links for a11y
- Derive dynamic course history semester ranges in Lectures page
- Add 3 comprehensive E2E test cases (test_08, test_09, test_10) for highlights, active border, CITE brand links, and English H1 headers
This commit is contained in:
2026-08-24 16:10:11 +09:00
parent b1640cdac4
commit f34e9bad57
7 changed files with 102 additions and 16 deletions
+10 -1
View File
@@ -1,10 +1,19 @@
import React from "react";
import type { Metadata } from "next";
import { semesters } from "../../content/lectures";
export const metadata: Metadata = {
title: "Lectures",
description: "AI Agent Networking Lab (ANL) lecture courses and curriculum history",
};
export default function LecturesPage() {
const recentSemesters = semesters.slice(0, 3);
const olderSemesters = semesters.slice(3);
const oldestSem = olderSemesters[olderSemesters.length - 1];
const newestOlderSem = olderSemesters[0];
return (
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */}
@@ -73,7 +82,7 @@ export default function LecturesPage() {
Browse all semesters
</span>
<p className="text-xs text-ink-mute font-mono">
Course history from 2016 Fall to 2024 Spring
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">
+13 -7
View File
@@ -1,7 +1,13 @@
import React from "react";
import type { Metadata } from "next";
import { activeMembers, alumni } from "../../content/members";
import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog";
export const metadata: Metadata = {
title: "Members",
description: "AI Agent Networking Lab (ANL) professor, active researchers, and alumni directory",
};
const DEGREE_LABEL: Record<string, string> = {
Professor: "Professor",
PhD: "Ph. D.",
@@ -24,16 +30,16 @@ export default function MembersPage() {
);
return (
<div className="container-content py-8 sm:py-12 space-y-12 sm:space-y-16">
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">
{/* Page Header */}
<section>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
LAB MEMBERS
</h1>
</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-8 border-t border-line">
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div className="lg:col-span-8 space-y-4">
<h2 className="font-serif text-3xl font-normal text-ink">
@@ -77,10 +83,10 @@ export default function MembersPage() {
</section>
{/* Active Researchers Section */}
<section className="space-y-8 pt-6 md:pt-10 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">
<div>
<h2 className="font-serif text-3xl font-normal text-cobalt-dark">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-cobalt-dark">
Active Researchers
</h2>
</div>
@@ -148,10 +154,10 @@ export default function MembersPage() {
</section>
{/* Alumni Section (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 md:pt-10 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">
<div>
<h2 className="font-serif text-3xl font-normal text-ink">
<h2 className="font-serif text-2xl sm:text-3xl font-normal text-ink">
Graduates
</h2>
</div>
@@ -1,4 +1,5 @@
import React from "react";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { CategoryNav } from "../_components/CategoryNav";
import { publications, patents } from "../../../content/publications";
@@ -11,6 +12,17 @@ interface PageProps {
};
}
export function generateMetadata({ params }: PageProps): Metadata {
const currentCat = PUB_CATEGORIES.find((c) => c.slug === params.category);
if (!currentCat) {
return { title: "Publications" };
}
return {
title: `${currentCat.label} | Publications`,
description: `AI Agent Networking Lab (ANL) ${currentCat.label} research inventory and records`,
};
}
// SSG static pre-rendering (● SSG) for Next.js 14
export function generateStaticParams() {
return PUB_CATEGORIES.map((cat) => ({
@@ -84,10 +96,10 @@ export default function PublicationCategoryPage({ params }: PageProps) {
{records.length === 0 ? (
<div className="bg-paper p-8 rounded-lg border border-line text-center space-y-3">
<p className="font-serif text-lg text-ink">
0.
No records found in this category.
</p>
<p className="text-xs text-ink-mute font-mono">
(D-01 )
Records will be updated periodically.
</p>
</div>
) : (
@@ -89,7 +89,8 @@ export function CategoryNav({ currentCategory }: CategoryNavProps) {
) : (
<Link
href={`/publications/${cat.slug}`}
className="inline-flex items-center text-xs font-bold text-vermillion-dark hover:underline"
aria-label={`View all ${cat.label} records`}
className="inline-flex items-center text-xs font-bold text-vermillion-dark hover:underline focus:outline-none focus:ring-1 focus:ring-vermillion-dark rounded"
>
View All &rarr;
</Link>
+6 -5
View File
@@ -1,8 +1,9 @@
import type { Metadata } from "next";
import { CategoryNav } from "./_components/CategoryNav";
import { publications } from "../../content/publications";
export const metadata = {
title: "Publications | ANL",
export const metadata: Metadata = {
title: "Publications",
description: "AI Agent Networking Lab (ANL) research publications and patents overview",
};
@@ -23,7 +24,7 @@ export default function PublicationsIndexPage() {
).filter((p): p is (typeof publications)[0] => Boolean(p));
return (
<main 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 */}
<section>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink tracking-tight">
@@ -68,13 +69,13 @@ export default function PublicationsIndexPage() {
)}
{pub.venue && (
<p className="text-xs italic text-ink-mute">
{pub.venue}
{pub.venue}{pub.volume ? `, ${pub.volume}` : ""}
</p>
)}
</article>
))}
</div>
</section>
</main>
</div>
);
}
@@ -1,6 +1,12 @@
import React from "react";
import type { Metadata } from "next";
import { standardsBodies } from "../../content/standards";
export const metadata: Metadata = {
title: "Standardization",
description: "AI Agent Networking Lab (ANL) international standardization research and contributions",
};
export default function StandardizationPage() {
return (
<div className="container-content py-8 sm:py-12 space-y-10 sm:space-y-14">