diff --git a/apps/docs/scripts/auth-cli.ts b/apps/docs/scripts/auth-cli.ts index de914bd..046988a 100644 --- a/apps/docs/scripts/auth-cli.ts +++ b/apps/docs/scripts/auth-cli.ts @@ -184,17 +184,34 @@ async function main() { const searchResponse = await request("/api/search", { headers }); assert.equal(searchResponse.status, 200); const searchIndex = await searchResponse.json(); - assert.ok(searchIndex.some((doc: { slug: string; searchText: string }) => doc.slug === "pretext/04-chapter" && doc.searchText.includes("getSegmentMetrics"))); + assert.ok(searchIndex.some((doc: { slug: string; searchText: string }) => doc.slug === "source-studies/pretext/measurement-cache" && doc.searchText.includes("getSegmentMetrics"))); + for (const doc of searchIndex as { slug: string; sourceSlug: string }[]) { + assert.ok(!doc.slug.split("/").some((part) => /^\d+-/.test(part)), doc.slug); + const legacy = await request(`/docs/${doc.sourceSlug}`, { headers }); + assert.equal(legacy.status, 308, doc.sourceSlug); + assert.equal(new URL(legacy.headers.get("location")!, base).pathname, `/docs/${doc.slug}`); + } let home = ""; let purpose = ""; for (const route of routes) { const response = await request(route, { headers }); - assert.equal(response.status, 200, route); - if (route === "/") home = await response.text(); - if (route === "/docs/04-endor-purpose-draft") purpose = await response.text(); + const alias = (searchIndex as { sourceSlug: string }[]).some((doc) => route === `/docs/${doc.sourceSlug}`); + assert.equal(response.status, alias ? 308 : 200, route); + if (alias) continue; + const html = await response.text(); + if (route === "/") home = html; + if (route === "/docs/endor/endor-purpose-draft") purpose = html; + if (route.startsWith("/docs/")) { + assert.ok(html.includes('aria-label="文档选择"'), route); + assert.ok(html.includes(''), route); + assert.ok(!html.includes('class="nav-back"'), route); + const ids = [...html.matchAll(/ match[1]); + assert.equal(new Set(ids).size, ids.length, `Unique heading anchors: ${route}`); + for (const id of ids) assert.ok(html.includes(`href="#${id}"`), `TOC anchor: ${route}#${id}`); + } } assert.ok(home.includes("资料库")); - assert.ok(home.includes("/docs/pretext/00-overview")); + assert.ok(home.includes("/docs/source-studies/pretext/overview")); // Inline preview and zoom dialog must both use the compressed browser asset. assert.equal( [...purpose.matchAll(/]*\bsrc="\/figures\/endor-review-gate\.webp"/g)].length, diff --git a/apps/docs/src/components/Shell.tsx b/apps/docs/src/components/Shell.tsx index ef4880f..533ea44 100644 --- a/apps/docs/src/components/Shell.tsx +++ b/apps/docs/src/components/Shell.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { useRouter } from "next/router"; import { Icon } from "@/components/Icon"; import { useEffect, useRef, useState, type ReactNode } from "react"; import type { DocLink } from "@/lib/docs"; @@ -36,9 +37,6 @@ export function Navigation({ return (