@karimsa/mdxserve 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +233 -2
- package/client/App.tsx +7 -0
- package/client/CodeBlock.tsx +395 -0
- package/client/CrossFade.tsx +72 -0
- package/client/DocContext.ts +14 -0
- package/client/DocView.tsx +107 -0
- package/client/ErrorBox.tsx +23 -0
- package/client/Heading.tsx +31 -0
- package/client/HomeEmptyState.tsx +101 -0
- package/client/HomeView.tsx +78 -0
- package/client/ListingView.tsx +663 -0
- package/client/MdSection.tsx +234 -0
- package/client/MdSectionEditor.tsx +233 -0
- package/client/Mermaid.tsx +435 -0
- package/client/RenderErrorBoundary.tsx +40 -0
- package/client/Table.tsx +14 -0
- package/client/TaskCheckbox.tsx +38 -0
- package/client/api.ts +138 -0
- package/client/app.css +372 -0
- package/client/builtins/Badge.tsx +109 -0
- package/client/builtins/Button.tsx +111 -0
- package/client/builtins/Callout.tsx +97 -0
- package/client/builtins/Card.tsx +111 -0
- package/client/builtins/Chart.tsx +875 -0
- package/client/builtins/Diff.tsx +722 -0
- package/client/builtins/Dropdown.tsx +417 -0
- package/client/builtins/FileTree.tsx +87 -0
- package/client/builtins/Kbd.tsx +18 -0
- package/client/builtins/Screenshot.tsx +209 -0
- package/client/builtins/Sparkline.tsx +63 -0
- package/client/builtins/Tabs.tsx +169 -0
- package/client/builtins/Tooltip.tsx +52 -0
- package/client/builtins/chart-data.ts +133 -0
- package/client/builtins/index.ts +167 -0
- package/client/design/base/editor.css +151 -0
- package/client/design/base/prose.css +143 -0
- package/client/design/base/reset.css +79 -0
- package/client/design/tokens/colors.css +188 -0
- package/client/design/tokens/elevation.css +42 -0
- package/client/design/tokens/fonts.css +6 -0
- package/client/design/tokens/motion.css +76 -0
- package/client/design/tokens/spacing.css +34 -0
- package/client/design/tokens/typography.css +56 -0
- package/client/doc-module-cache.ts +17 -0
- package/client/editor-link.ts +27 -0
- package/client/entry.tsx +51 -0
- package/client/export-doc.ts +80 -0
- package/client/export-save.ts +96 -0
- package/client/favicon.svg +1 -0
- package/client/file-system-access.d.ts +29 -0
- package/client/format.ts +17 -0
- package/client/hooks.ts +34 -0
- package/client/lucide-icons.d.ts +9 -0
- package/client/mdx-components-base.ts +32 -0
- package/client/mdx-components.ts +18 -0
- package/client/mermaid-chart.ts +109 -0
- package/client/mermaid-direction.ts +73 -0
- package/client/motion.ts +104 -0
- package/client/platform.ts +16 -0
- package/client/route-path.ts +15 -0
- package/client/router.ts +452 -0
- package/client/shell/AppShell.tsx +401 -0
- package/client/shell/Footer.tsx +33 -0
- package/client/shell/NotFoundView.tsx +22 -0
- package/client/shell/Sidebar.tsx +169 -0
- package/client/shell/StandaloneShell.tsx +65 -0
- package/client/shell/TocRail.tsx +53 -0
- package/client/shell/TopBar.tsx +117 -0
- package/client/shell/use-doc-width.ts +61 -0
- package/client/shell/useToc.ts +77 -0
- package/client/ssr-entry.tsx +22 -0
- package/client/standalone-entry.tsx +51 -0
- package/client/state.ts +90 -0
- package/client/theme.ts +65 -0
- package/client/ui/Breadcrumb.tsx +49 -0
- package/client/ui/ConfirmDeleteDialog.tsx +113 -0
- package/client/ui/ExpandModal.tsx +342 -0
- package/client/ui/Icon.tsx +114 -0
- package/client/ui/IconButton.tsx +63 -0
- package/client/ui/Kbd.tsx +17 -0
- package/client/ui/PageNav.tsx +77 -0
- package/client/ui/ResizeHandle.tsx +201 -0
- package/client/ui/SearchDialog.tsx +187 -0
- package/client/ui/Tag.tsx +44 -0
- package/client/ui/Toast.tsx +189 -0
- package/client/ui/TocList.tsx +71 -0
- package/client/ui/icon-set.ts +102 -0
- package/client/ui/toast-count.ts +28 -0
- package/dist/cli.js +5091 -0
- package/dist/registry.json +703 -0
- package/dist/render-worker.js +145 -0
- package/package.json +113 -5
- package/skills/mdxserve/SKILL.md +178 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/rendering/render-worker.ts
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parentPort } from "node:worker_threads";
|
|
5
|
+
import { ESModulesEvaluator, ModuleRunner } from "vite/module-runner";
|
|
6
|
+
if (!parentPort) {
|
|
7
|
+
throw new Error("render-worker.ts must be run inside a node:worker_threads Worker");
|
|
8
|
+
}
|
|
9
|
+
var port = parentPort;
|
|
10
|
+
function toPosix(filePath) {
|
|
11
|
+
return filePath.split(path.sep).join("/");
|
|
12
|
+
}
|
|
13
|
+
var nextInvokeId = 0;
|
|
14
|
+
var pendingInvokes = /* @__PURE__ */ new Map();
|
|
15
|
+
var transport = {
|
|
16
|
+
invoke(data) {
|
|
17
|
+
const invokeId = nextInvokeId++;
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
pendingInvokes.set(invokeId, { resolve });
|
|
20
|
+
const message = { type: "invoke", invokeId, payload: data };
|
|
21
|
+
port.postMessage(message);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var runner = new ModuleRunner(
|
|
26
|
+
{
|
|
27
|
+
transport,
|
|
28
|
+
hmr: false,
|
|
29
|
+
// Have Node remap `Error.stack` frames through each module's sourcemap
|
|
30
|
+
// as they're generated, so an error thrown while evaluating a doc
|
|
31
|
+
// already points at the original .md/.mdx source — no separate
|
|
32
|
+
// `vite.ssrFixStacktrace()` pass needed (that was a main-thread-only
|
|
33
|
+
// API tied to the main-thread module graph). "node" is what Vite's own
|
|
34
|
+
// `createServerModuleRunner` resolves to by default in a real Node
|
|
35
|
+
// process (see `resolveSourceMapOptions` in dist/node/chunks/node.js);
|
|
36
|
+
// passing it explicitly here just makes that intentional rather than
|
|
37
|
+
// incidental.
|
|
38
|
+
sourcemapInterceptor: "node"
|
|
39
|
+
},
|
|
40
|
+
new ESModulesEvaluator()
|
|
41
|
+
);
|
|
42
|
+
var USE_LAYOUT_EFFECT_WARNING = "useLayoutEffect does nothing on the server";
|
|
43
|
+
function withConsoleErrorFilter(fn) {
|
|
44
|
+
const original = console.error;
|
|
45
|
+
console.error = (...args) => {
|
|
46
|
+
const first = args[0];
|
|
47
|
+
if (typeof first === "string" && first.includes(USE_LAYOUT_EFFECT_WARNING)) return;
|
|
48
|
+
original.apply(console, args);
|
|
49
|
+
};
|
|
50
|
+
try {
|
|
51
|
+
return fn();
|
|
52
|
+
} finally {
|
|
53
|
+
console.error = original;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function firstFrameFor(stack, absPath) {
|
|
57
|
+
const escaped = absPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
58
|
+
const re = new RegExp(`${escaped}:(\\d+):(\\d+)`);
|
|
59
|
+
for (const rawLine of stack.split("\n")) {
|
|
60
|
+
const match = re.exec(rawLine);
|
|
61
|
+
if (match) {
|
|
62
|
+
return { line: Number(match[1]), column: Number(match[2]) };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
function pathForms(docPath) {
|
|
68
|
+
let real = docPath;
|
|
69
|
+
try {
|
|
70
|
+
real = fs.realpathSync.native(docPath);
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
return [.../* @__PURE__ */ new Set([docPath, toPosix(docPath), real, toPosix(real)])];
|
|
74
|
+
}
|
|
75
|
+
function outcomeFromError(err, docPath) {
|
|
76
|
+
if (!(err instanceof Error)) {
|
|
77
|
+
return { ok: false, message: String(err) };
|
|
78
|
+
}
|
|
79
|
+
const stack = err.stack;
|
|
80
|
+
let line;
|
|
81
|
+
let column;
|
|
82
|
+
if (stack) {
|
|
83
|
+
for (const form of pathForms(docPath)) {
|
|
84
|
+
({ line, column } = firstFrameFor(stack, form));
|
|
85
|
+
if (line !== void 0) break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { ok: false, message: err.message, stack, line, column };
|
|
89
|
+
}
|
|
90
|
+
async function handleRender(msg) {
|
|
91
|
+
const { id, ssrEntryPath, docPath } = msg;
|
|
92
|
+
let outcome;
|
|
93
|
+
try {
|
|
94
|
+
invalidateDocModules();
|
|
95
|
+
const [ssrEntry, docModule] = await Promise.all([
|
|
96
|
+
runner.import(toPosix(ssrEntryPath)),
|
|
97
|
+
runner.import(toPosix(docPath))
|
|
98
|
+
]);
|
|
99
|
+
if (!docModule.default) {
|
|
100
|
+
outcome = { ok: false, message: `${docPath} has no default export.` };
|
|
101
|
+
} else {
|
|
102
|
+
withConsoleErrorFilter(() => ssrEntry.renderDoc(docModule.default));
|
|
103
|
+
outcome = { ok: true };
|
|
104
|
+
}
|
|
105
|
+
} catch (err) {
|
|
106
|
+
outcome = outcomeFromError(err, docPath);
|
|
107
|
+
}
|
|
108
|
+
const result = { type: "result", id, outcome };
|
|
109
|
+
port.postMessage(result);
|
|
110
|
+
}
|
|
111
|
+
var sharedIds;
|
|
112
|
+
function invalidateDocModules() {
|
|
113
|
+
for (const [id, node] of runner.evaluatedModules.idToModuleMap) {
|
|
114
|
+
if (sharedIds?.has(id)) continue;
|
|
115
|
+
runner.evaluatedModules.invalidateModule(node);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function handleWarm(msg) {
|
|
119
|
+
let outcome;
|
|
120
|
+
try {
|
|
121
|
+
await runner.import(toPosix(msg.ssrEntryPath));
|
|
122
|
+
sharedIds = new Set(runner.evaluatedModules.idToModuleMap.keys());
|
|
123
|
+
outcome = { ok: true };
|
|
124
|
+
} catch (err) {
|
|
125
|
+
outcome = err instanceof Error ? { ok: false, message: err.message, stack: err.stack } : { ok: false, message: String(err) };
|
|
126
|
+
}
|
|
127
|
+
const result = { type: "result", id: msg.id, outcome };
|
|
128
|
+
port.postMessage(result);
|
|
129
|
+
}
|
|
130
|
+
port.on("message", (msg) => {
|
|
131
|
+
if (msg.type === "invoke-response") {
|
|
132
|
+
const pending = pendingInvokes.get(msg.invokeId);
|
|
133
|
+
if (!pending) return;
|
|
134
|
+
pendingInvokes.delete(msg.invokeId);
|
|
135
|
+
pending.resolve(msg.response);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (msg.type === "warm") {
|
|
139
|
+
void handleWarm(msg);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (msg.type === "render") {
|
|
143
|
+
void handleRender(msg);
|
|
144
|
+
}
|
|
145
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,114 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@karimsa/mdxserve",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Serve a directory of Markdown/MDX files, like `serve` but for docs",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/karimsa/mdxserve.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/karimsa/mdxserve#readme",
|
|
11
|
+
"bugs": "https://github.com/karimsa/mdxserve/issues",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"markdown",
|
|
14
|
+
"mdx",
|
|
15
|
+
"docs",
|
|
16
|
+
"cli"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"bin": "dist/cli.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"client",
|
|
23
|
+
"!client/design-ref",
|
|
24
|
+
"skills"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsx scripts/build.ts",
|
|
28
|
+
"registry": "tsx scripts/build-registry.ts",
|
|
29
|
+
"dev": "tsx scripts/build-registry.ts && tsx src/index.ts serve -w example",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"format": "prettier --write .",
|
|
32
|
+
"format:check": "prettier --check .",
|
|
33
|
+
"lint": "oxlint",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"prepack": "yarn build",
|
|
36
|
+
"smoke": "bash scripts/smoke-pack.sh"
|
|
37
|
+
},
|
|
38
|
+
"packageManager": "yarn@4.18.0",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.12"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@fontsource-variable/jetbrains-mono": "5.3.0",
|
|
47
|
+
"@fontsource-variable/manrope": "5.3.0",
|
|
48
|
+
"@mdx-js/mdx": "3.1.1",
|
|
49
|
+
"@mdx-js/react": "3.1.1",
|
|
50
|
+
"@mdx-js/rollup": "3.1.1",
|
|
51
|
+
"@tailwindcss/vite": "4.3.3",
|
|
52
|
+
"@tanstack/react-query": "5.101.4",
|
|
53
|
+
"@tippyjs/react": "4.2.6",
|
|
54
|
+
"@tiptap/core": "3.29.2",
|
|
55
|
+
"@tiptap/extension-image": "3.29.2",
|
|
56
|
+
"@tiptap/extension-list": "3.29.2",
|
|
57
|
+
"@tiptap/extension-table": "3.29.2",
|
|
58
|
+
"@tiptap/markdown": "3.29.2",
|
|
59
|
+
"@tiptap/pm": "3.29.2",
|
|
60
|
+
"@tiptap/react": "3.29.2",
|
|
61
|
+
"@tiptap/starter-kit": "3.29.2",
|
|
62
|
+
"@trpc/client": "11.18.0",
|
|
63
|
+
"@trpc/server": "11.18.0",
|
|
64
|
+
"@trpc/tanstack-react-query": "11.18.0",
|
|
65
|
+
"@vitejs/plugin-react": "6.0.5",
|
|
66
|
+
"commander": "15.0.0",
|
|
67
|
+
"date-fns": "4.4.0",
|
|
68
|
+
"diff": "9.0.0",
|
|
69
|
+
"framer-motion": "13.0.0",
|
|
70
|
+
"hast-util-to-html": "9.0.5",
|
|
71
|
+
"jotai": "2.20.2",
|
|
72
|
+
"lockfile": "1.0.4",
|
|
73
|
+
"lucide-react": "1.30.0",
|
|
74
|
+
"mdast-util-from-markdown": "2.0.3",
|
|
75
|
+
"mdast-util-mdx": "3.0.0",
|
|
76
|
+
"mdast-util-to-hast": "13.2.1",
|
|
77
|
+
"mdast-util-to-string": "4.0.0",
|
|
78
|
+
"mermaid": "10.9.8",
|
|
79
|
+
"micromark-extension-mdxjs": "3.0.0",
|
|
80
|
+
"minisearch": "7.2.0",
|
|
81
|
+
"node-sqlite3-wasm": "0.8.60",
|
|
82
|
+
"react": "19.2.8",
|
|
83
|
+
"react-dom": "19.2.8",
|
|
84
|
+
"react-hot-toast": "2.6.0",
|
|
85
|
+
"rehype-pretty-code": "0.14.5",
|
|
86
|
+
"rehype-slug": "6.0.0",
|
|
87
|
+
"remark-gfm": "4.0.1",
|
|
88
|
+
"shiki": "4.4.2",
|
|
89
|
+
"svg-pan-zoom": "3.6.2",
|
|
90
|
+
"tailwindcss": "4.3.3",
|
|
91
|
+
"tippy.js": "6.3.7",
|
|
92
|
+
"trash": "10.1.1",
|
|
93
|
+
"vfile-message": "4.0.3",
|
|
94
|
+
"vite": "8.2.1",
|
|
95
|
+
"zod": "4.4.3",
|
|
96
|
+
"zx": "8.8.5"
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@types/lockfile": "1.0.4",
|
|
100
|
+
"@types/mdast": "4.0.4",
|
|
101
|
+
"@types/node": "26.2.0",
|
|
102
|
+
"@types/react": "19.2.18",
|
|
103
|
+
"@types/react-dom": "19.2.4",
|
|
104
|
+
"@types/svg-pan-zoom": "3.4.0",
|
|
105
|
+
"@yarnpkg/types": "4.0.1",
|
|
106
|
+
"esbuild": "0.28.2",
|
|
107
|
+
"fast-check": "4.9.0",
|
|
108
|
+
"oxlint": "1.77.0",
|
|
109
|
+
"prettier": "3.9.6",
|
|
110
|
+
"tsx": "4.23.12",
|
|
111
|
+
"typescript": "7.0.2",
|
|
112
|
+
"vitest": "4.1.10"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mdxserve
|
|
3
|
+
description: Use when writing or editing Markdown the user will read — docs, reports, plan files, notes — so the content renders as richly as possible in mdxserve while staying plain, portable Markdown.
|
|
4
|
+
allowed-tools: Bash, Read, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Writing Markdown for mdxserve
|
|
8
|
+
|
|
9
|
+
mdxserve serves a folder of `.md` / `.mdx` files as a browsable site: a file listing,
|
|
10
|
+
rendered pages with syntax highlighting, mermaid diagrams, and a small library of builtin
|
|
11
|
+
components. `.md` and `.mdx` are treated identically — both go through MDX, so the builtin
|
|
12
|
+
components work in either.
|
|
13
|
+
|
|
14
|
+
Markdown files have many readers besides mdxserve (GitHub, editors, other tools). The goal
|
|
15
|
+
is the **simplest Markdown that is still visual**: reach for richer features only when they
|
|
16
|
+
add clarity, and prefer features that degrade gracefully everywhere else.
|
|
17
|
+
|
|
18
|
+
## The ladder — prefer lower rungs
|
|
19
|
+
|
|
20
|
+
1. **Plain GitHub-flavored Markdown.** Headings, short paragraphs, lists, task lists, tables,
|
|
21
|
+
links, bold for the one thing that matters. Works everywhere. Most content should stop here.
|
|
22
|
+
2. **Fenced code with a language tag.** Always tag the language (`ts`, `bash`, `json`, …). Add
|
|
23
|
+
fence meta when it helps the reader: `title="path/to/file.ts"`, `showLineNumbers`,
|
|
24
|
+
`{3-5}` to highlight lines. mdxserve renders these richly; other tools ignore the meta.
|
|
25
|
+
3. **Mermaid diagrams** for flows, sequences, states, and architecture. mdxserve renders them as
|
|
26
|
+
pan/zoomable diagrams (with a toggle to the source); GitHub renders them too; everywhere else
|
|
27
|
+
they are still readable text. Prefer `flowchart` and `sequenceDiagram`; keep a diagram to
|
|
28
|
+
roughly 15 nodes or fewer — split larger ones. Never use mermaid's `pie`, `xychart-beta`,
|
|
29
|
+
`quadrantChart`, or `sankey-beta` — mdxserve doesn't render them, `mdxserve validate` reports an
|
|
30
|
+
error on them, and they draw data, which is `<Chart>`'s job (or a table). Mermaid is for a
|
|
31
|
+
flow or a shape, not a dataset.
|
|
32
|
+
4. **Builtin components** (`<Callout>`, `<Tabs>`, `<Badge>`, `<Tooltip>`, `<Button>`, `<Diff>`, `<Card>`,
|
|
33
|
+
`<Kbd>`, `<FileTree>`, `<Chart>` (bar, line, area, histogram), `<Sparkline>`, `<Screenshot>`) only when they make
|
|
34
|
+
the content clearer: a warning the reader must not miss, per-OS or per-language variants of the
|
|
35
|
+
same instructions, a status label, a small dataset that's clearer as a shape than a table.
|
|
36
|
+
Outside mdxserve these show as raw tags, so use them sparingly and never for decoration.
|
|
37
|
+
|
|
38
|
+
Don't: write raw HTML or inline styles; import or create custom components; use emoji as
|
|
39
|
+
icons where a `Badge` or `Callout` would do; nest components for layout; put a component in a
|
|
40
|
+
file the user will mainly read elsewhere (e.g. a README on GitHub) unless they asked.
|
|
41
|
+
|
|
42
|
+
MDX is stricter than Markdown: a bare `{`, `}` or an unclosed `<tag>` in prose is a compile
|
|
43
|
+
error, not literal text. Put such characters in backticks or escape them (`\{`).
|
|
44
|
+
|
|
45
|
+
## Quick reference
|
|
46
|
+
|
|
47
|
+
A table beats a list of "X: Y" lines:
|
|
48
|
+
|
|
49
|
+
```md
|
|
50
|
+
| Option | Default | Effect |
|
|
51
|
+
| -------- | ------- | ------------------------- |
|
|
52
|
+
| `--port` | `4040` | Port to listen on |
|
|
53
|
+
| `--host` | `127.0.0.1` | Interface to bind (`0.0.0.0` for LAN) |
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Code with a title, line numbers, and highlighted lines:
|
|
57
|
+
|
|
58
|
+
````md
|
|
59
|
+
```ts title="src/server.ts" showLineNumbers {3-4}
|
|
60
|
+
const server = http.createServer(handler);
|
|
61
|
+
server.listen(port);
|
|
62
|
+
// highlighted:
|
|
63
|
+
console.log(`http://localhost:${port}`);
|
|
64
|
+
```
|
|
65
|
+
````
|
|
66
|
+
|
|
67
|
+
A flow and a sequence:
|
|
68
|
+
|
|
69
|
+
````md
|
|
70
|
+
```mermaid
|
|
71
|
+
flowchart LR
|
|
72
|
+
Browser -->|GET /docs/intro.md| Server
|
|
73
|
+
Server -->|compile via Vite| Page[Rendered page]
|
|
74
|
+
```
|
|
75
|
+
````
|
|
76
|
+
|
|
77
|
+
````md
|
|
78
|
+
```mermaid
|
|
79
|
+
sequenceDiagram
|
|
80
|
+
participant U as User
|
|
81
|
+
participant S as Server
|
|
82
|
+
U->>S: click file
|
|
83
|
+
S-->>U: rendered page
|
|
84
|
+
```
|
|
85
|
+
````
|
|
86
|
+
|
|
87
|
+
Task lists for progress; keep them flat:
|
|
88
|
+
|
|
89
|
+
```md
|
|
90
|
+
- [x] Read the existing router
|
|
91
|
+
- [ ] Add the listing endpoint
|
|
92
|
+
- [ ] Verify in the browser
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Builtin components
|
|
96
|
+
|
|
97
|
+
Available in any `.md` or `.mdx` with no import. The registry — not this file — is the
|
|
98
|
+
authoritative list of components and props. Before using a component for the first time in a
|
|
99
|
+
session, check it:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
mdxserve components search # list every builtin with a one-line description
|
|
103
|
+
mdxserve components search tab # search by name, description, or prop name
|
|
104
|
+
mdxserve components show Callout # props table (types, defaults) + when to use
|
|
105
|
+
mdxserve components show Callout --json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If `mdxserve` is not on your PATH, install it with `npm install -g @karimsa/mdxserve`.
|
|
109
|
+
|
|
110
|
+
Minimal usage:
|
|
111
|
+
|
|
112
|
+
```mdx
|
|
113
|
+
<Callout tone="warn" title="Before you deploy">
|
|
114
|
+
Rotate the key first; the old one stops working immediately.
|
|
115
|
+
</Callout>
|
|
116
|
+
|
|
117
|
+
<Tabs>
|
|
118
|
+
<Tab label="macOS">`brew install foo`</Tab>
|
|
119
|
+
<Tab label="Linux">`apt install foo`</Tab>
|
|
120
|
+
</Tabs>
|
|
121
|
+
|
|
122
|
+
Status: <Badge tone="ok" dot>Online</Badge>
|
|
123
|
+
|
|
124
|
+
The <Tooltip content="Mean time to recovery">MTTR</Tooltip> improved.
|
|
125
|
+
|
|
126
|
+
<Button href="./setup.md">Continue to setup</Button>
|
|
127
|
+
|
|
128
|
+
<Diff before={`port: 3000`} after={`port: 4000`} />
|
|
129
|
+
|
|
130
|
+
Press <Kbd>⌘</Kbd><Kbd>K</Kbd> to open search.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Components contain ordinary Markdown: a `Tab` can hold lists, paragraphs, and code fences.
|
|
134
|
+
Leave a blank line between a component tag and a Markdown block inside it so the block is
|
|
135
|
+
parsed as Markdown.
|
|
136
|
+
|
|
137
|
+
## Plan files
|
|
138
|
+
|
|
139
|
+
Plans are read in mdxserve and in plain text. Use headings for phases, a task list per phase,
|
|
140
|
+
a table for files-to-change, and at most one mermaid diagram (the architecture or the main
|
|
141
|
+
flow, never a chart). Skip components in plans unless the user views plans only in mdxserve.
|
|
142
|
+
|
|
143
|
+
## After writing
|
|
144
|
+
|
|
145
|
+
After saving any `.md`/`.mdx` file, run `mdxserve validate <absolute path>`. It works even when
|
|
146
|
+
no `mdxserve serve` is running. Read the first line and every diagnostic under it: it is
|
|
147
|
+
`OK: <path>`, `OK with N warnings: <path>`, or a list of problems. Fix every `error` (MDX
|
|
148
|
+
compile errors, unknown components, `render-error`) and any `unknown-prop` warning where a real
|
|
149
|
+
prop was intended, then re-run until the first line is `OK` with only intended warnings. The
|
|
150
|
+
exit code is 1 when any error was reported. Compile errors and unknown components blank the
|
|
151
|
+
page or throw at render time — invisible until a human opens it — so this is not optional.
|
|
152
|
+
|
|
153
|
+
`validate` also renders the doc server-side and reports any throw as a `render-error` — this is
|
|
154
|
+
what catches a component that compiles fine but blanks the page (e.g. a stray identifier that
|
|
155
|
+
only breaks at render time). Read the line after the diagnostics: `Rendered OK`, or
|
|
156
|
+
`Not rendered (…)` when no `mdxserve serve` is reachable, meaning only the static checks
|
|
157
|
+
(compile, unknown component/prop) ran. Treat that as a weaker pass and mention it to the user
|
|
158
|
+
rather than treating `OK` alone as a full clean bill of health. Even with `Rendered OK`, errors
|
|
159
|
+
thrown inside a `useEffect`/`useLayoutEffect` and hydration mismatches are never caught — those
|
|
160
|
+
stay browser-only. `hint:` lines are advisory and never affect the result. When scripting, use
|
|
161
|
+
`--json` and check the `rendered` field.
|
|
162
|
+
|
|
163
|
+
If `validate` says the file is outside every served directory, or `mdxserve search` /
|
|
164
|
+
`mdxserve docs` report that no folders are served, run `mdxserve roots list`, then
|
|
165
|
+
`mdxserve roots add <absolute dir>` with the doc's folder.
|
|
166
|
+
|
|
167
|
+
If `mdxserve` is not installed, tell the user the file was not validated; don't skip this
|
|
168
|
+
silently.
|
|
169
|
+
|
|
170
|
+
## Before saving
|
|
171
|
+
|
|
172
|
+
- Every code fence has a language tag; titles and highlights only where they help.
|
|
173
|
+
- Any diagram is a mermaid fence, small enough to read at a glance, and none of them draws a
|
|
174
|
+
chart (no `pie`, `xychart-beta`, `quadrantChart`, `sankey-beta` — use `<Chart>` or a table).
|
|
175
|
+
- No raw HTML, styles, imports, or custom components.
|
|
176
|
+
- Any builtin component used was checked with `components show` and genuinely clarifies.
|
|
177
|
+
- The file still reads well as plain text.
|
|
178
|
+
- `mdxserve validate` printed `OK`, ideally `Rendered OK`.
|