@wrikka/create-docs 0.1.0 → 0.2.1
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/docs/config.md +1 -1
- package/docs/data-sources.md +1 -1
- package/docs/deploy.md +1 -1
- package/docs/features.md +1 -1
- package/docs/markdown.md +1 -1
- package/docs/theming.md +1 -1
- package/docs/translate.md +46 -0
- package/package.json +7 -5
- package/scripts/generate-docs-index.ts +3 -3
- package/scripts/translate.ts +127 -0
- package/src/adapters/github/github-pull.ts +23 -0
- package/src/runtime/components/ApiReference.tsx +332 -0
- package/src/runtime/components/ContextMenu.tsx +88 -0
- package/src/runtime/components/MobileBottomNav.tsx +3 -3
- package/src/runtime/components/SidebarNav.tsx +190 -3
- package/src/runtime/components/TopNav.tsx +163 -49
- package/src/runtime/config.ts +24 -1
- package/src/runtime/content.ts +17 -15
- package/src/runtime/index.ts +6 -0
- package/src/runtime/pages/ApiEndpointPage.tsx +54 -141
- package/src/runtime/pages/DocPage.tsx +10 -1
- package/src/runtime/pages/PluginsPage.tsx +38 -13
- package/src/runtime/pages/SearchPage.tsx +374 -0
- package/src/runtime/pages/ShowcasePage.tsx +143 -15
- package/src/runtime/pages/TranslatePage.tsx +338 -0
- package/src/runtime/plugins-catalog.ts +170 -0
- package/src/runtime/router.tsx +23 -0
package/src/runtime/content.ts
CHANGED
|
@@ -259,21 +259,23 @@ export function createStaticDataSource(
|
|
|
259
259
|
async collections(): Promise<CollectionMeta[]> {
|
|
260
260
|
return options.collections.map((c) => {
|
|
261
261
|
const dirs = dirMeta.get(c.meta.id);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
262
|
+
const fromDirs = [...(dirs?.entries() ?? [])].map(([dirKey, m]) => ({
|
|
263
|
+
id: dirKey.split("/").pop() ?? dirKey,
|
|
264
|
+
label: m.title ?? dirKey.split("/").pop() ?? dirKey,
|
|
265
|
+
icon: m.icon,
|
|
266
|
+
order: m.order,
|
|
267
|
+
collapsed: m.collapsed,
|
|
268
|
+
}));
|
|
269
|
+
const dirIds = new Set(fromDirs.map((s) => s.id));
|
|
270
|
+
const fromMeta = (c.meta.sections ?? []).filter(
|
|
271
|
+
(s) => !dirIds.has(s.id) && !dirIds.has(s.label),
|
|
272
|
+
);
|
|
273
|
+
const sections = [...fromDirs, ...fromMeta].sort(
|
|
274
|
+
(a, b) =>
|
|
275
|
+
(a.order ?? Number.MAX_SAFE_INTEGER) -
|
|
276
|
+
(b.order ?? Number.MAX_SAFE_INTEGER),
|
|
277
|
+
);
|
|
278
|
+
return sections.length ? { ...c.meta, sections } : c.meta;
|
|
277
279
|
});
|
|
278
280
|
},
|
|
279
281
|
|
package/src/runtime/index.ts
CHANGED
|
@@ -15,10 +15,12 @@ export { createDocsApp, mountDocsApp } from "./app";
|
|
|
15
15
|
// Components (for custom pages/layouts)
|
|
16
16
|
export { AccentPicker } from "./components/AccentPicker";
|
|
17
17
|
export { ApiPlayground } from "./components/ApiPlayground";
|
|
18
|
+
export { ApiReference } from "./components/ApiReference";
|
|
18
19
|
export { AskAiDialog } from "./components/AskAiDialog";
|
|
19
20
|
export { BackToTop } from "./components/BackToTop";
|
|
20
21
|
export { Breadcrumbs } from "./components/Breadcrumbs";
|
|
21
22
|
export { CollectionDropdown } from "./components/CollectionDropdown";
|
|
23
|
+
export { ContextMenu, type ContextMenuItem } from "./components/ContextMenu";
|
|
22
24
|
export { DocMarkdown } from "./components/DocMarkdown";
|
|
23
25
|
export { DocPrevNext } from "./components/DocPrevNext";
|
|
24
26
|
export { DocsDropdown } from "./components/DocsDropdown";
|
|
@@ -63,6 +65,7 @@ export type {
|
|
|
63
65
|
MarkdownConfig,
|
|
64
66
|
PluginInfo,
|
|
65
67
|
ShowcaseInfo,
|
|
68
|
+
TranslateConfig,
|
|
66
69
|
VersionsConfig,
|
|
67
70
|
} from "./config";
|
|
68
71
|
export type { DirMeta, StaticSourceOptions } from "./content";
|
|
@@ -114,7 +117,10 @@ export { HomePage } from "./pages/HomePage";
|
|
|
114
117
|
export { IssuesPage } from "./pages/IssuesPage";
|
|
115
118
|
export { OAuthCallbackPage } from "./pages/OAuthCallbackPage";
|
|
116
119
|
export { PluginsPage } from "./pages/PluginsPage";
|
|
120
|
+
export { SearchPage } from "./pages/SearchPage";
|
|
117
121
|
export { ShowcasePage } from "./pages/ShowcasePage";
|
|
122
|
+
export { TranslatePage } from "./pages/TranslatePage";
|
|
123
|
+
export { officialPlugins } from "./plugins-catalog";
|
|
118
124
|
export { setupPwa } from "./pwa";
|
|
119
125
|
export { createDocsRouter } from "./router";
|
|
120
126
|
export type { SeoInput } from "./seo";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useParams } from "@tanstack/solid-router";
|
|
2
|
-
import { createMemo, Show } from "solid-js";
|
|
2
|
+
import { createMemo, createSignal, Show } from "solid-js";
|
|
3
3
|
import { ApiPlayground } from "../components/ApiPlayground";
|
|
4
|
-
import {
|
|
4
|
+
import { ApiReference } from "../components/ApiReference";
|
|
5
5
|
import { DocPrevNext } from "../components/DocPrevNext";
|
|
6
6
|
import { findApiCollection, useDocs } from "../context";
|
|
7
|
-
import type {
|
|
7
|
+
import type { DocEntry } from "../types";
|
|
8
8
|
|
|
9
9
|
const METHOD_BADGE: Record<string, string> = {
|
|
10
10
|
GET: "bg-accent/15 text-accent border-accent/30",
|
|
@@ -21,123 +21,25 @@ const STYLE_ICON: Record<string, string> = {
|
|
|
21
21
|
rpc: "i-mdi:api",
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"| Name | Required | Description |",
|
|
44
|
-
"| --- | --- | --- |",
|
|
45
|
-
);
|
|
46
|
-
for (const a of ep.cli.args) {
|
|
47
|
-
lines.push(
|
|
48
|
-
`| \`${a.name}\` | ${a.required ? "yes" : "no"} | ${a.description ?? ""} |`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
lines.push("");
|
|
52
|
-
}
|
|
53
|
-
if (ep.requestBody?.example != null) {
|
|
54
|
-
lines.push("## Options", "");
|
|
55
|
-
lines.push(
|
|
56
|
-
"```json",
|
|
57
|
-
JSON.stringify(ep.requestBody.example, null, 2),
|
|
58
|
-
"```",
|
|
59
|
-
"",
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
} else if (style === "graphql") {
|
|
63
|
-
if (ep.description) lines.push(ep.description, "");
|
|
64
|
-
if (ep.graphql?.query) {
|
|
65
|
-
lines.push("## Query", "", "```graphql", ep.graphql.query, "```", "");
|
|
66
|
-
}
|
|
67
|
-
if (ep.graphql?.variables != null) {
|
|
68
|
-
lines.push("## Variables", "");
|
|
69
|
-
lines.push(
|
|
70
|
-
"```json",
|
|
71
|
-
JSON.stringify(ep.graphql.variables, null, 2),
|
|
72
|
-
"```",
|
|
73
|
-
"",
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
if (ep.description) lines.push(ep.description, "");
|
|
78
|
-
if (ep.parameters.length > 0) {
|
|
79
|
-
lines.push(
|
|
80
|
-
"## Parameters",
|
|
81
|
-
"",
|
|
82
|
-
"| Name | In | Required | Description |",
|
|
83
|
-
"| --- | --- | --- | --- |",
|
|
84
|
-
);
|
|
85
|
-
for (const p of ep.parameters) {
|
|
86
|
-
lines.push(
|
|
87
|
-
`| \`${p.name}\` | ${p.in} | ${p.required ? "yes" : "no"} | ${p.description ?? ""} |`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
lines.push("");
|
|
91
|
-
}
|
|
92
|
-
if (ep.requestBody) {
|
|
93
|
-
lines.push("## Request Body", "");
|
|
94
|
-
if (ep.requestBody.description)
|
|
95
|
-
lines.push(ep.requestBody.description, "");
|
|
96
|
-
if (ep.requestBody.example != null) {
|
|
97
|
-
lines.push(
|
|
98
|
-
"```json",
|
|
99
|
-
JSON.stringify(ep.requestBody.example, null, 2),
|
|
100
|
-
"```",
|
|
101
|
-
"",
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const codes = Object.keys(ep.responses);
|
|
108
|
-
if (codes.length > 0) {
|
|
109
|
-
lines.push(style === "cli" ? "## Exit codes" : "## Responses", "");
|
|
110
|
-
for (const code of codes) {
|
|
111
|
-
const r = ep.responses[code]!;
|
|
112
|
-
lines.push(`### ${code} — ${r.description}`);
|
|
113
|
-
if (r.example != null) {
|
|
114
|
-
lines.push(
|
|
115
|
-
"",
|
|
116
|
-
"```json",
|
|
117
|
-
JSON.stringify(r.example, null, 2),
|
|
118
|
-
"```",
|
|
119
|
-
"",
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return lines.join("\n");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function endpointHeader(ep: ApiEndpoint, style: string) {
|
|
128
|
-
if (style === "cli") {
|
|
129
|
-
const cmd = ep.cli
|
|
130
|
-
? [ep.cli.command, ep.cli.subcommand].filter(Boolean).join(" ")
|
|
131
|
-
: `${ep.method} ${ep.path}`;
|
|
132
|
-
return { label: cmd, icon: "i-mdi:console-line" };
|
|
133
|
-
}
|
|
134
|
-
if (style === "graphql") {
|
|
135
|
-
return {
|
|
136
|
-
label: ep.graphql?.operation ?? ep.summary ?? "GraphQL",
|
|
137
|
-
icon: "i-mdi:graphql",
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
return { label: `${ep.method} ${ep.path}`, icon: "" };
|
|
24
|
+
function CopyInline(props: { text: () => string }) {
|
|
25
|
+
const [copied, setCopied] = createSignal(false);
|
|
26
|
+
return (
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
aria-label="Copy"
|
|
30
|
+
onClick={() => {
|
|
31
|
+
navigator.clipboard.writeText(props.text()).catch(() => {});
|
|
32
|
+
setCopied(true);
|
|
33
|
+
setTimeout(() => setCopied(false), 1500);
|
|
34
|
+
}}
|
|
35
|
+
class="w-7 h-7 inline-flex items-center justify-center rounded-md border border-border text-muted hover:text-foreground hover:bg-surface transition-colors cursor-pointer"
|
|
36
|
+
>
|
|
37
|
+
<span
|
|
38
|
+
class={copied() ? "i-mdi:check text-success" : "i-mdi:content-copy"}
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
/>
|
|
41
|
+
</button>
|
|
42
|
+
);
|
|
141
43
|
}
|
|
142
44
|
|
|
143
45
|
export function ApiEndpointPage() {
|
|
@@ -165,10 +67,15 @@ export function ApiEndpointPage() {
|
|
|
165
67
|
})),
|
|
166
68
|
);
|
|
167
69
|
|
|
168
|
-
const
|
|
70
|
+
const cliLabel = () => {
|
|
169
71
|
const ep = endpoint();
|
|
170
|
-
if (!ep) return
|
|
171
|
-
|
|
72
|
+
if (!ep) return "";
|
|
73
|
+
if (style() === "cli") {
|
|
74
|
+
return ep.cli
|
|
75
|
+
? [ep.cli.command, ep.cli.subcommand].filter(Boolean).join(" ")
|
|
76
|
+
: `${ep.method} ${ep.path}`;
|
|
77
|
+
}
|
|
78
|
+
return ep.graphql?.operation ?? ep.summary ?? "GraphQL";
|
|
172
79
|
};
|
|
173
80
|
|
|
174
81
|
return (
|
|
@@ -180,50 +87,56 @@ export function ApiEndpointPage() {
|
|
|
180
87
|
>
|
|
181
88
|
{(ep) => (
|
|
182
89
|
<>
|
|
183
|
-
<
|
|
90
|
+
<Show when={ep().tag}>
|
|
91
|
+
<div class="text-[11px] uppercase tracking-wide text-muted mb-2">
|
|
92
|
+
{ep().tag}
|
|
93
|
+
</div>
|
|
94
|
+
</Show>
|
|
95
|
+
<Show when={ep().summary}>
|
|
96
|
+
<h1 class="text-2xl font-bold text-foreground mt-0 mb-3">
|
|
97
|
+
{ep().summary}
|
|
98
|
+
</h1>
|
|
99
|
+
</Show>
|
|
100
|
+
|
|
101
|
+
<div class="flex flex-wrap items-center gap-2 p-3 mb-6 rounded-xl border border-border bg-surface/50">
|
|
184
102
|
<Show when={style() === "rest" || style() === "rpc"}>
|
|
185
103
|
<span
|
|
186
104
|
class={`inline-flex items-center px-2.5 py-1 rounded-md border text-xs font-bold ${METHOD_BADGE[ep().method] ?? ""}`}
|
|
187
105
|
>
|
|
188
106
|
{ep().method}
|
|
189
107
|
</span>
|
|
190
|
-
<code class="text-sm font-mono text-foreground">
|
|
108
|
+
<code class="text-sm font-mono text-foreground break-all">
|
|
109
|
+
{ep().server ? `${ep().server}` : ""}
|
|
191
110
|
{ep().path}
|
|
192
111
|
</code>
|
|
112
|
+
<CopyInline text={() => `${ep().server ?? ""}${ep().path}`} />
|
|
193
113
|
</Show>
|
|
194
114
|
|
|
195
115
|
<Show when={style() === "graphql" || style() === "cli"}>
|
|
196
|
-
<span class="inline-flex items-center gap-1.5 text-sm font-mono text-foreground">
|
|
116
|
+
<span class="inline-flex items-center gap-1.5 text-sm font-mono text-foreground min-w-0">
|
|
197
117
|
<span
|
|
198
|
-
class={`${
|
|
118
|
+
class={`${style() === "cli" ? "i-mdi:console-line" : "i-mdi:graphql"} text-primary shrink-0`}
|
|
199
119
|
aria-hidden="true"
|
|
200
120
|
/>
|
|
201
|
-
{
|
|
121
|
+
<span class="truncate">{cliLabel()}</span>
|
|
202
122
|
</span>
|
|
123
|
+
<CopyInline text={cliLabel} />
|
|
203
124
|
</Show>
|
|
204
125
|
|
|
205
|
-
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-border bg-
|
|
126
|
+
<span class="ml-auto inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-border bg-background text-[10px] uppercase tracking-wide font-semibold text-muted shrink-0">
|
|
206
127
|
<span
|
|
207
128
|
class={`${STYLE_ICON[style()] ?? "i-mdi:api"} text-xs`}
|
|
208
129
|
aria-hidden="true"
|
|
209
130
|
/>
|
|
210
131
|
{style()}
|
|
211
132
|
</span>
|
|
212
|
-
|
|
213
|
-
<Show when={ep().tag}>
|
|
214
|
-
<span class="ml-auto text-[11px] uppercase tracking-wide text-muted">
|
|
215
|
-
{ep().tag}
|
|
216
|
-
</span>
|
|
217
|
-
</Show>
|
|
218
133
|
</div>
|
|
219
134
|
|
|
220
|
-
<
|
|
221
|
-
<h1 class="text-2xl font-bold text-foreground mt-0 mb-4">
|
|
222
|
-
{ep().summary}
|
|
223
|
-
</h1>
|
|
224
|
-
</Show>
|
|
135
|
+
<ApiReference endpoint={ep()} style={style()} />
|
|
225
136
|
|
|
226
|
-
<
|
|
137
|
+
<div class="lg:hidden">
|
|
138
|
+
<ApiPlayground endpoint={ep()} style={style()} />
|
|
139
|
+
</div>
|
|
227
140
|
</>
|
|
228
141
|
)}
|
|
229
142
|
</Show>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useParams } from "@tanstack/solid-router";
|
|
1
|
+
import { Link, useParams } from "@tanstack/solid-router";
|
|
2
2
|
import { dump as dumpYaml } from "js-yaml";
|
|
3
3
|
import { createResource, createSignal, Show } from "solid-js";
|
|
4
4
|
import { AskAiDialog } from "../components/AskAiDialog";
|
|
@@ -108,6 +108,15 @@ export function DocPage() {
|
|
|
108
108
|
<span class="i-mdi:robot-happy-outline" aria-hidden="true" />
|
|
109
109
|
Ask AI
|
|
110
110
|
</button>
|
|
111
|
+
<Show when={config.features?.translate || config.translate}>
|
|
112
|
+
<Link
|
|
113
|
+
to="/translate"
|
|
114
|
+
class="inline-flex items-center gap-1.5 px-2.5 h-8 rounded-md border border-border text-xs text-muted hover:text-foreground hover:bg-surface transition-colors no-underline"
|
|
115
|
+
>
|
|
116
|
+
<span class="i-mdi:translate" aria-hidden="true" />
|
|
117
|
+
Translate
|
|
118
|
+
</Link>
|
|
119
|
+
</Show>
|
|
111
120
|
<Show when={showFrontmatterToggle()}>
|
|
112
121
|
<button
|
|
113
122
|
type="button"
|
|
@@ -93,23 +93,32 @@ export function PluginsPage() {
|
|
|
93
93
|
const list = plugins() ?? [];
|
|
94
94
|
const groups = new Map<string, typeof list>();
|
|
95
95
|
for (const p of list) {
|
|
96
|
-
const cat =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
? "
|
|
100
|
-
: p.name.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
const cat =
|
|
97
|
+
p.category ??
|
|
98
|
+
(p.name.startsWith("@")
|
|
99
|
+
? "Packages"
|
|
100
|
+
: p.name.includes("adapter")
|
|
101
|
+
? "Adapters"
|
|
102
|
+
: p.name.startsWith("MCP") ||
|
|
103
|
+
p.name.includes("LLM") ||
|
|
104
|
+
p.name.includes("OAuth") ||
|
|
105
|
+
p.name.includes("PWA") ||
|
|
106
|
+
p.name.includes("SEO") ||
|
|
107
|
+
p.name.includes("Search")
|
|
108
|
+
? "Integrations"
|
|
109
|
+
: "Core");
|
|
108
110
|
const g = groups.get(cat) ?? [];
|
|
109
111
|
g.push(p);
|
|
110
112
|
groups.set(cat, g);
|
|
111
113
|
}
|
|
112
|
-
const order = [
|
|
114
|
+
const order = [
|
|
115
|
+
"Core",
|
|
116
|
+
"Adapters",
|
|
117
|
+
"AI",
|
|
118
|
+
"Integrations",
|
|
119
|
+
"Content",
|
|
120
|
+
"Packages",
|
|
121
|
+
];
|
|
113
122
|
return [...groups.entries()].sort(([a], [b]) => {
|
|
114
123
|
const ia = order.indexOf(a);
|
|
115
124
|
const ib = order.indexOf(b);
|
|
@@ -120,6 +129,15 @@ export function PluginsPage() {
|
|
|
120
129
|
});
|
|
121
130
|
};
|
|
122
131
|
|
|
132
|
+
const statusBadge = (status?: string) => {
|
|
133
|
+
if (!status || status === "built-in")
|
|
134
|
+
return "bg-success/10 text-success border-success/30";
|
|
135
|
+
if (status === "beta")
|
|
136
|
+
return "bg-warning/10 text-warning border-warning/30";
|
|
137
|
+
if (status === "planned") return "bg-surface text-muted border-border";
|
|
138
|
+
return "bg-primary/10 text-primary border-primary/30";
|
|
139
|
+
};
|
|
140
|
+
|
|
123
141
|
return (
|
|
124
142
|
<div class="max-w-5xl mx-auto px-6 py-10 pb-24">
|
|
125
143
|
<div class="flex items-start gap-3 mb-2">
|
|
@@ -203,6 +221,13 @@ export function PluginsPage() {
|
|
|
203
221
|
</span>
|
|
204
222
|
</Show>
|
|
205
223
|
</div>
|
|
224
|
+
<Show when={p.status}>
|
|
225
|
+
<span
|
|
226
|
+
class={`text-[10px] px-1.5 py-0.5 rounded border shrink-0 ${statusBadge(p.status)}`}
|
|
227
|
+
>
|
|
228
|
+
{p.status}
|
|
229
|
+
</span>
|
|
230
|
+
</Show>
|
|
206
231
|
<Show when={p.url}>
|
|
207
232
|
<a
|
|
208
233
|
href={p.url}
|