Skip to content

Commit 11ae130

Browse files
JohnMcLearclaude
andauthored
fix(docs): render every sidebar link, not just /docs/docker (#396)
Only `/docs/docker` had a corresponding `app/docs/<slug>/page.tsx`, so the other 17 sidebar links 404'd and `/docs` itself rendered an empty `<div>` next to a sidebar full of dead links. The Next.js rewrite was started in commit e9ebe3d ("Started with integrating documentation") and only completed the docker page in be54131. This finishes the migration without hand-porting each markdown file to JSX: - `app/docs/[slug]/page.tsx` reads `docs-content/<slug>.md` at build time, parses with `marked` (already a dep), and renders into a `.markdown-body` article. `generateStaticParams` enumerates the slugs so all pages are pre-rendered into the static export. - The 17 markdown files are vendored into `docs-content/` from `etherpad/doc/` (canonical upstream source). - The `app/docs/page.tsx` index now lists the available pages grouped by section instead of being empty. - The hard-coded `app/docs/docker/page.tsx` is removed; the dynamic route handles docker uniformly. - `DocSidebar` had two links pointing at `/docs/plugins`; the API one now points at `/docs/pluginfw` (matching the upstream filename `pluginfw.md`). The Easysync entries point at the original PDFs, which are now hosted under `public/easysync/`. - `app/index.css` gains a `.markdown-body` typography block for the dark theme: headings, lists, tables, code blocks, blockquotes. Verified with `pnpm build`: 17 doc routes generate static HTML, and the rendered pages contain the expected headings and code blocks. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 01657b2 commit 11ae130

24 files changed

Lines changed: 3914 additions & 223 deletions

app/docs/[slug]/page.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { marked } from 'marked';
4+
import { notFound } from 'next/navigation';
5+
6+
const DOCS_DIR = path.join(process.cwd(), 'docs-content');
7+
8+
export const dynamicParams = false;
9+
10+
export function generateStaticParams() {
11+
return fs
12+
.readdirSync(DOCS_DIR)
13+
.filter((f) => f.endsWith('.md'))
14+
.map((f) => ({ slug: f.replace(/\.md$/, '') }));
15+
}
16+
17+
export default async function Page({
18+
params,
19+
}: {
20+
params: Promise<{ slug: string }>;
21+
}) {
22+
const { slug } = await params;
23+
const filePath = path.join(DOCS_DIR, `${slug}.md`);
24+
25+
if (!fs.existsSync(filePath)) {
26+
notFound();
27+
}
28+
29+
const source = fs.readFileSync(filePath, 'utf8');
30+
const html = await marked.parse(source, { async: true });
31+
32+
return (
33+
<article
34+
className="markdown-body"
35+
dangerouslySetInnerHTML={{ __html: html }}
36+
/>
37+
);
38+
}

app/docs/docker/page.tsx

Lines changed: 0 additions & 217 deletions
This file was deleted.

app/docs/page.tsx

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,75 @@
1-
export default function Page () {
2-
return <div className="dark:bg-gray-800">
1+
import Link from 'next/link';
32

4-
</div>
3+
const sections = [
4+
{
5+
title: 'Getting Started',
6+
items: [
7+
{ slug: 'docker', label: 'Docker', blurb: 'Run Etherpad in a container.' },
8+
{ slug: 'cli', label: 'CLI', blurb: 'Command-line installation and bin scripts.' },
9+
{ slug: 'demo', label: 'Demo', blurb: 'Try Etherpad without installing.' },
10+
{ slug: 'cookies', label: 'Cookies', blurb: 'Cookies set by Etherpad.' },
11+
],
12+
},
13+
{
14+
title: 'Customisation',
15+
items: [
16+
{ slug: 'plugins', label: 'Plugins', blurb: 'Find and install plugins.' },
17+
{ slug: 'skins', label: 'Skins', blurb: 'Theme the editor.' },
18+
{ slug: 'localization', label: 'Localization', blurb: 'Translate the UI.' },
19+
{ slug: 'stats', label: 'Stats', blurb: 'Built-in metrics.' },
20+
],
21+
},
22+
{
23+
title: 'API',
24+
items: [
25+
{ slug: 'httpAPI', label: 'HTTP API', blurb: 'REST endpoints for managing pads.' },
26+
{ slug: 'hooksServerSide', label: 'Server-side hooks', blurb: 'Extend Etherpad on the server.' },
27+
{ slug: 'hooksClientSide', label: 'Client-side hooks', blurb: 'Extend Etherpad in the browser.' },
28+
{ slug: 'pluginfw', label: 'Plugin framework', blurb: 'Build your own plugin.' },
29+
{ slug: 'editbar', label: 'Editbar', blurb: 'Toolbar API.' },
30+
{ slug: 'toolbar', label: 'Toolbar', blurb: 'Toolbar registration.' },
31+
{ slug: 'editorinfo', label: 'EditorInfo', blurb: 'Editor introspection API.' },
32+
{ slug: 'changeset', label: 'Changeset', blurb: 'Changeset library reference.' },
33+
{ slug: 'embedParameters', label: 'Embed parameters', blurb: 'Tune the embedded pad.' },
34+
],
35+
},
36+
];
37+
38+
export default function Page() {
39+
return (
40+
<article className="markdown-body">
41+
<h1>Etherpad Documentation</h1>
42+
<p>
43+
Etherpad is a real-time collaborative editor. Pick a topic below, or
44+
use the sidebar to jump to a specific page.
45+
</p>
46+
{sections.map((section) => (
47+
<section key={section.title}>
48+
<h2>{section.title}</h2>
49+
<ul>
50+
{section.items.map((item) => (
51+
<li key={item.slug}>
52+
<Link href={`/docs/${item.slug}`}>{item.label}</Link>
53+
{' — '}
54+
{item.blurb}
55+
</li>
56+
))}
57+
</ul>
58+
</section>
59+
))}
60+
<h2>Easysync (legacy)</h2>
61+
<ul>
62+
<li>
63+
<a href="/easysync/easysync-full-description.pdf">
64+
Easysync full description
65+
</a>{' '}
66+
— original protocol paper.
67+
</li>
68+
<li>
69+
<a href="/easysync/easysync-notes.pdf">Easysync notes</a>
70+
accompanying notes.
71+
</li>
72+
</ul>
73+
</article>
74+
);
575
}

0 commit comments

Comments
 (0)