返回 CodeWhale
docs-sidebar.tsx
根目录 / web / components / docs-sidebar.tsx
1 "use client";
2
3 import Link from "next/link";
4 import { usePathname } from "next/navigation";
5 import { docsTopicIsCurrent } from "@/lib/docs-navigation";
6 import {
7 DOC_CATEGORY_LABELS,
8 docTopicHref,
9 docTopicIsExternal,
10 getTopicsByCategory,
11 } from "@/lib/docs-map";
12 import { getDocsShell, pickText } from "@/lib/i18n/dictionaries";
13
14 /**
15 * The one docs navigation: every registered topic, grouped by category,
16 * with the current route marked. Chrome strings come from the docs-shell
17 * dictionary; topic names are docs-map pairs resolved through `pickText`.
18 */
19 export function DocsSidebar({ locale }: { locale: string }) {
20 const t = getDocsShell(locale);
21 const pathname = usePathname();
22 const byCategory = getTopicsByCategory();
23
24 return (
25 <aside className="docs-sidebar min-w-0">
26 <div className="lg:sticky lg:top-24">
27 <div className="docs-sidebar-heading">
28 <Link href={`/${locale}/docs`}>
29 <span>{t.sidebarHeading}</span>
30 <span aria-hidden="true">→</span>
31 </Link>
32 </div>
33 <nav aria-label={t.sidebarAria}>
34 {[...byCategory.entries()].map(([category, topics]) => (
35 <div key={category} className="docs-sidebar-group">
36 <div className="docs-sidebar-category">
37 {pickText(DOC_CATEGORY_LABELS[category], locale)}
38 </div>
39 <ul>
40 {topics.map((topic) => {
41 const isCurrent = docsTopicIsCurrent(topic, locale, pathname);
42 const isExternal = docTopicIsExternal(topic);
43 return (
44 <li key={topic.id}>
45 <Link
46 href={docTopicHref(topic, locale)}
47 target={isExternal ? "_blank" : undefined}
48 rel={isExternal ? "noreferrer" : undefined}
49 aria-current={isCurrent ? "page" : undefined}
50 className={
51 isCurrent
52 ? "docs-sidebar-link docs-sidebar-link-current"
53 : "docs-sidebar-link"
54 }
55 >
56 <span>{pickText(topic.label, locale)}</span>
57 {isExternal && <span aria-hidden="true">↗</span>}
58 </Link>
59 </li>
60 );
61 })}
62 </ul>
63 </div>
64 ))}
65 </nav>
66 </div>
67 </aside>
68 );
69 }
70
70 lines Plain Text