feat(web): Phase 11 UI/UX — TOC, dark mode toggle, /docs index

- Install rehype-slug (proper heading anchors) + github-slugger (matching TOC)
- TOC component: auto-generated from h2/h3 headings, clickable anchors
- Dark mode toggle: ThemeToggle (localStorage + system default), class-based
- /docs index page (lists all docs by section)
- Markdown.tsx uses rehype-slug for stable heading ids
- globals.css: @custom-variant dark (.dark class) for class-based dark mode
- layout.tsx: nav includes ThemeToggle

Note: per user instruction, installed real deps (rehype-slug, github-slugger,
@types/hast) instead of hacky inline any-cast hacks.
This commit is contained in:
asepharyana
2026-08-20 13:21:53 +07:00
parent b998826b71
commit 1dd16ebcba
11 changed files with 260 additions and 25 deletions
+4 -4
View File
@@ -5,6 +5,7 @@ import { getDocument, getRelated, listRevisions } from "@mcpedia/core";
import { WEBHOOK_SECRET } from "@mcpedia/config";
import Markdown from "@/components/Markdown";
import DocForm from "@/components/DocForm";
import TOC from "@/components/TOC";
// Render at request time. The content lives in Postgres (populated by the
// indexer/worker), which is not available at build time (CI has no DB), so we
@@ -76,6 +77,8 @@ export default async function DocPage({ params, searchParams }: DocPageProps) {
)}
</div>
<TOC source={doc.body} />
<Markdown source={doc.body} />
{related.length > 0 && (
@@ -84,10 +87,7 @@ export default async function DocPage({ params, searchParams }: DocPageProps) {
<ul className="text-sm space-y-1">
{related.map((r) => (
<li key={r.slug}>
<Link
href={`/${r.slug}`}
className="hover:underline"
>
<Link href={`/${r.slug}`} className="hover:underline">
{r.title}
</Link>
</li>