@riebeckite/plugin-docs 0.0.24 → 0.0.26
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.
|
@@ -4,5 +4,5 @@ export type DocsPrevNextProps = {
|
|
|
4
4
|
readonly next?: DocsNavigationLink;
|
|
5
5
|
readonly language?: string;
|
|
6
6
|
};
|
|
7
|
-
declare const DocsPrevNext: (
|
|
7
|
+
declare const DocsPrevNext: (props: Readonly<DocsPrevNextProps>) => Promise<import("hono/utils/html").HtmlEscapedString>;
|
|
8
8
|
export default DocsPrevNext;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DocsNavigationItem } from "../src/types.js";
|
|
2
2
|
export type DocsSidebarProps = {
|
|
3
|
-
readonly items
|
|
3
|
+
readonly items?: readonly DocsNavigationItem[];
|
|
4
4
|
readonly currentPermalink?: string;
|
|
5
5
|
readonly label?: string;
|
|
6
6
|
};
|
|
7
|
-
declare const DocsSidebar: (
|
|
7
|
+
declare const DocsSidebar: (props: Readonly<DocsSidebarProps>) => Promise<import("hono/utils/html").HtmlEscapedString>;
|
|
8
8
|
export default DocsSidebar;
|
|
@@ -1,11 +1,187 @@
|
|
|
1
|
+
// components/docs-sidebar.tsx
|
|
2
|
+
import { useArticleContext, useSiteContext } from "@riebeckite/ui";
|
|
3
|
+
import { html } from "hono/html";
|
|
4
|
+
|
|
5
|
+
// index.ts
|
|
6
|
+
import {
|
|
7
|
+
createClientEntry,
|
|
8
|
+
createStyleAsset,
|
|
9
|
+
definePlugin
|
|
10
|
+
} from "@riebeckite/core";
|
|
11
|
+
|
|
12
|
+
// src/navigation.ts
|
|
13
|
+
var ROOT_SEGMENT = "";
|
|
14
|
+
function resolveDocsOptions(options) {
|
|
15
|
+
return {
|
|
16
|
+
root: normalizeRoot(options.root),
|
|
17
|
+
sidebar: {
|
|
18
|
+
auto: options.sidebar?.auto ?? true,
|
|
19
|
+
label: options.sidebar?.label ?? "Docs navigation"
|
|
20
|
+
},
|
|
21
|
+
prevNext: options.prevNext ?? true
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function buildDocsNavigation(entries, options) {
|
|
25
|
+
if (!options.sidebar.auto) return [];
|
|
26
|
+
const docsEntries = entries.map((entry) => toNavigationEntry(entry, options.root)).filter((entry) => Boolean(entry)).filter((entry) => !entry.hidden);
|
|
27
|
+
const root = createTreeNode(ROOT_SEGMENT);
|
|
28
|
+
for (const entry of docsEntries) addEntry(root, entry);
|
|
29
|
+
const rootIndex = root.index;
|
|
30
|
+
const items = buildItems(root, []);
|
|
31
|
+
if (!rootIndex) return items;
|
|
32
|
+
return [toItem(rootIndex, []), ...items];
|
|
33
|
+
}
|
|
34
|
+
function normalizeRoot(root) {
|
|
35
|
+
return root.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
36
|
+
}
|
|
37
|
+
function toNavigationEntry(entry, root) {
|
|
38
|
+
const relativePath = resolveRelativeDocsPath(entry, root);
|
|
39
|
+
if (!relativePath) return null;
|
|
40
|
+
const segments = relativePath.split("/").filter(Boolean);
|
|
41
|
+
const isIndex = ["index", "README"].includes(segments.at(-1) ?? "");
|
|
42
|
+
const sidebar = readSidebarFrontmatter(
|
|
43
|
+
"frontmatter" in entry ? entry.frontmatter.sidebar : void 0
|
|
44
|
+
);
|
|
45
|
+
return {
|
|
46
|
+
entry,
|
|
47
|
+
relativePath,
|
|
48
|
+
segments,
|
|
49
|
+
isIndex,
|
|
50
|
+
title: resolveTitle(entry, sidebar),
|
|
51
|
+
order: sidebar.order,
|
|
52
|
+
hidden: sidebar.hidden ?? false,
|
|
53
|
+
collapsed: sidebar.collapsed
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function resolveRelativeDocsPath(entry, root) {
|
|
57
|
+
if (entry.slug === root) return "index";
|
|
58
|
+
if (!entry.slug.startsWith(`${root}/`)) return null;
|
|
59
|
+
return stripFilenameLanguage(
|
|
60
|
+
entry.slug.slice(root.length + 1),
|
|
61
|
+
entry.publicLocation.language
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function stripFilenameLanguage(path, language) {
|
|
65
|
+
if (!language) return path;
|
|
66
|
+
const segments = path.split("/");
|
|
67
|
+
const last = segments.at(-1);
|
|
68
|
+
if (last === void 0) return path;
|
|
69
|
+
segments[segments.length - 1] = last.replace(
|
|
70
|
+
new RegExp(`[._-]${escapeRegExp(language)}$`, "i"),
|
|
71
|
+
""
|
|
72
|
+
);
|
|
73
|
+
return segments.join("/");
|
|
74
|
+
}
|
|
75
|
+
function escapeRegExp(value) {
|
|
76
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
77
|
+
}
|
|
78
|
+
function readSidebarFrontmatter(value) {
|
|
79
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
80
|
+
const record = value;
|
|
81
|
+
return {
|
|
82
|
+
...typeof record.label === "string" && record.label.trim() ? { label: record.label.trim() } : {},
|
|
83
|
+
...typeof record.order === "number" && Number.isFinite(record.order) ? { order: record.order } : {},
|
|
84
|
+
...typeof record.hidden === "boolean" ? { hidden: record.hidden } : {},
|
|
85
|
+
...typeof record.collapsed === "boolean" ? { collapsed: record.collapsed } : {}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function resolveTitle(entry, sidebar) {
|
|
89
|
+
if (sidebar.label) return sidebar.label;
|
|
90
|
+
if (entry.title.trim()) return entry.title.trim();
|
|
91
|
+
return titleFromSegment(entry.slug.split("/").at(-1) ?? entry.slug);
|
|
92
|
+
}
|
|
93
|
+
function addEntry(root, entry) {
|
|
94
|
+
const path = entry.isIndex ? entry.segments.slice(0, -1) : entry.segments;
|
|
95
|
+
let node = root;
|
|
96
|
+
for (const segment of path) {
|
|
97
|
+
const child = node.children.get(segment) ?? createTreeNode(segment);
|
|
98
|
+
node.children.set(segment, child);
|
|
99
|
+
node = child;
|
|
100
|
+
}
|
|
101
|
+
if (entry.isIndex) node.index = entry;
|
|
102
|
+
else node.page = entry;
|
|
103
|
+
}
|
|
104
|
+
function buildItems(node, path) {
|
|
105
|
+
return [...node.children.values()].toSorted(compareNodes).map((child) => nodeToItem(child, [...path, child.segment]));
|
|
106
|
+
}
|
|
107
|
+
function nodeToItem(node, path) {
|
|
108
|
+
const primary = node.index ?? node.page;
|
|
109
|
+
const children = [
|
|
110
|
+
...node.index && node.page ? [toItem(node.page, [])] : [],
|
|
111
|
+
...buildItems(node, path)
|
|
112
|
+
];
|
|
113
|
+
if (primary) return toItem(primary, children);
|
|
114
|
+
return {
|
|
115
|
+
title: titleFromSegment(node.segment),
|
|
116
|
+
children
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function toItem(entry, children) {
|
|
120
|
+
return {
|
|
121
|
+
title: entry.title,
|
|
122
|
+
href: entry.entry.permalink,
|
|
123
|
+
slug: entry.entry.slug,
|
|
124
|
+
...entry.order === void 0 ? {} : { order: entry.order },
|
|
125
|
+
...entry.collapsed === void 0 ? {} : { collapsed: entry.collapsed },
|
|
126
|
+
children
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function compareNodes(a, b) {
|
|
130
|
+
const left = a.index ?? a.page;
|
|
131
|
+
const right = b.index ?? b.page;
|
|
132
|
+
return compareNavigationKeys(
|
|
133
|
+
left?.order,
|
|
134
|
+
left?.title ?? titleFromSegment(a.segment),
|
|
135
|
+
a.segment,
|
|
136
|
+
right?.order,
|
|
137
|
+
right?.title ?? titleFromSegment(b.segment),
|
|
138
|
+
b.segment
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
function compareNavigationKeys(leftOrder, leftTitle, leftPath, rightOrder, rightTitle, rightPath) {
|
|
142
|
+
if (leftOrder !== void 0 || rightOrder !== void 0) {
|
|
143
|
+
if (leftOrder === void 0) return 1;
|
|
144
|
+
if (rightOrder === void 0) return -1;
|
|
145
|
+
const order = leftOrder - rightOrder;
|
|
146
|
+
if (order !== 0) return order;
|
|
147
|
+
}
|
|
148
|
+
const title = leftTitle.localeCompare(rightTitle, "en", {
|
|
149
|
+
sensitivity: "base"
|
|
150
|
+
});
|
|
151
|
+
if (title !== 0) return title;
|
|
152
|
+
return leftPath.localeCompare(rightPath, "en", { sensitivity: "base" });
|
|
153
|
+
}
|
|
154
|
+
function createTreeNode(segment) {
|
|
155
|
+
return { segment, children: /* @__PURE__ */ new Map() };
|
|
156
|
+
}
|
|
157
|
+
function titleFromSegment(segment) {
|
|
158
|
+
return segment.replace(/[-_]+/g, " ").replace(/\b\p{L}/gu, (letter) => letter.toLocaleUpperCase("en"));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// index.ts
|
|
162
|
+
var getDocsNavigation = ({ view, entrySlug, options }) => {
|
|
163
|
+
const entry = view.findRoutableBySlug(entrySlug);
|
|
164
|
+
if (!entry) return [];
|
|
165
|
+
const localized = view.discoverableEntries.filter(
|
|
166
|
+
(candidate) => candidate.publicLocation.language === entry.publicLocation.language
|
|
167
|
+
);
|
|
168
|
+
return buildDocsNavigation(localized, resolveDocsOptions(options));
|
|
169
|
+
};
|
|
170
|
+
|
|
1
171
|
// components/docs-sidebar.tsx
|
|
2
172
|
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
3
|
-
var DocsSidebar = (({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
173
|
+
var DocsSidebar = (async (props) => {
|
|
174
|
+
const site = useSiteContext();
|
|
175
|
+
const article = useArticleContext();
|
|
176
|
+
const options = findDocsOptions(site?.config.plugins);
|
|
177
|
+
const items = props.items ?? (site && article?.entry && options ? await getDocsNavigation({
|
|
178
|
+
view: site.view,
|
|
179
|
+
entrySlug: article.entry.slug,
|
|
180
|
+
options
|
|
181
|
+
}) : []);
|
|
182
|
+
const currentPermalink = props.currentPermalink ?? article?.entry?.permalink;
|
|
183
|
+
const label = props.label ?? options?.sidebar?.label ?? "Docs navigation";
|
|
184
|
+
if (items.length === 0) return html``;
|
|
9
185
|
const permalink = currentPermalink ?? "";
|
|
10
186
|
return /* @__PURE__ */ jsxs("details", { class: "rb-docs-sidebar-details", "data-docs-sidebar-details": true, open: true, children: [
|
|
11
187
|
/* @__PURE__ */ jsx("summary", { class: "rb-docs-sidebar-summary", children: label }),
|
|
@@ -84,6 +260,9 @@ function containsPermalink(item, currentPermalink) {
|
|
|
84
260
|
return item.href === currentPermalink || item.children.some((child) => containsPermalink(child, currentPermalink));
|
|
85
261
|
}
|
|
86
262
|
var docs_sidebar_default = DocsSidebar;
|
|
263
|
+
function findDocsOptions(plugins) {
|
|
264
|
+
return plugins?.find((plugin) => plugin.name.startsWith("docs:"))?.options;
|
|
265
|
+
}
|
|
87
266
|
export {
|
|
88
267
|
docs_sidebar_default as default
|
|
89
268
|
};
|
package/dist/index.js
CHANGED
|
@@ -161,13 +161,23 @@ function titleFromSegment(segment) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// components/docs-prev-next.tsx
|
|
164
|
+
import { useArticleContext, useSiteContext } from "@riebeckite/ui";
|
|
165
|
+
import { html } from "hono/html";
|
|
164
166
|
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
165
|
-
var DocsPrevNext = (({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
var DocsPrevNext = (async (props) => {
|
|
168
|
+
const site = useSiteContext();
|
|
169
|
+
const article = useArticleContext();
|
|
170
|
+
const options = findDocsOptions(site?.config.plugins);
|
|
171
|
+
const navigation = site && article?.entry && options ? await getDocsNavigation({
|
|
172
|
+
view: site.view,
|
|
173
|
+
entrySlug: article.entry.slug,
|
|
174
|
+
options
|
|
175
|
+
}) : [];
|
|
176
|
+
const resolved = article?.entry ? await getDocsPrevNext({ items: navigation, slug: article.entry.slug }) : {};
|
|
177
|
+
const previous = props.previous ?? resolved.previous;
|
|
178
|
+
const next = props.next ?? resolved.next;
|
|
179
|
+
const language = props.language ?? article?.entry?.publicLocation.language;
|
|
180
|
+
if (!previous && !next) return html``;
|
|
171
181
|
const labels = language === "ja" ? { nav: "前後のドキュメント", previous: "前へ", next: "次へ" } : {
|
|
172
182
|
nav: "Previous and next docs pages",
|
|
173
183
|
previous: "Previous",
|
|
@@ -209,15 +219,26 @@ var DocsPrevNext = (({
|
|
|
209
219
|
] });
|
|
210
220
|
});
|
|
211
221
|
var docs_prev_next_default = DocsPrevNext;
|
|
222
|
+
function findDocsOptions(plugins) {
|
|
223
|
+
return plugins?.find((plugin) => plugin.name.startsWith("docs:"))?.options;
|
|
224
|
+
}
|
|
212
225
|
|
|
213
226
|
// components/docs-sidebar.tsx
|
|
227
|
+
import { useArticleContext as useArticleContext2, useSiteContext as useSiteContext2 } from "@riebeckite/ui";
|
|
228
|
+
import { html as html2 } from "hono/html";
|
|
214
229
|
import { jsx as jsx2, jsxs as jsxs2 } from "hono/jsx/jsx-runtime";
|
|
215
|
-
var DocsSidebar = (({
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
var DocsSidebar = (async (props) => {
|
|
231
|
+
const site = useSiteContext2();
|
|
232
|
+
const article = useArticleContext2();
|
|
233
|
+
const options = findDocsOptions2(site?.config.plugins);
|
|
234
|
+
const items = props.items ?? (site && article?.entry && options ? await getDocsNavigation({
|
|
235
|
+
view: site.view,
|
|
236
|
+
entrySlug: article.entry.slug,
|
|
237
|
+
options
|
|
238
|
+
}) : []);
|
|
239
|
+
const currentPermalink = props.currentPermalink ?? article?.entry?.permalink;
|
|
240
|
+
const label = props.label ?? options?.sidebar?.label ?? "Docs navigation";
|
|
241
|
+
if (items.length === 0) return html2``;
|
|
221
242
|
const permalink = currentPermalink ?? "";
|
|
222
243
|
return /* @__PURE__ */ jsxs2("details", { class: "rb-docs-sidebar-details", "data-docs-sidebar-details": true, open: true, children: [
|
|
223
244
|
/* @__PURE__ */ jsx2("summary", { class: "rb-docs-sidebar-summary", children: label }),
|
|
@@ -296,6 +317,9 @@ function containsPermalink(item, currentPermalink) {
|
|
|
296
317
|
return item.href === currentPermalink || item.children.some((child) => containsPermalink(child, currentPermalink));
|
|
297
318
|
}
|
|
298
319
|
var docs_sidebar_default = DocsSidebar;
|
|
320
|
+
function findDocsOptions2(plugins) {
|
|
321
|
+
return plugins?.find((plugin) => plugin.name.startsWith("docs:"))?.options;
|
|
322
|
+
}
|
|
299
323
|
|
|
300
324
|
// src/docs-sidebar.client.ts
|
|
301
325
|
var COLLAPSIBLE_PROPERTY = "--rb-docs-sidebar-collapsible";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-docs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"hono": "^4.12.25",
|
|
31
|
-
"@riebeckite/core": "0.0.
|
|
31
|
+
"@riebeckite/core": "0.0.26",
|
|
32
|
+
"@riebeckite/ui": "0.0.26"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"tsx": "^4.22.4",
|
|
35
|
-
"@riebeckite/test": "0.0.
|
|
36
|
+
"@riebeckite/test": "0.0.26"
|
|
36
37
|
},
|
|
37
38
|
"publishConfig": {
|
|
38
39
|
"access": "public"
|