@cedros/data-react 0.1.6 → 0.1.8
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/README.md +7 -0
- package/dist/docsContract.d.ts +56 -0
- package/dist/docsContract.js +136 -0
- package/dist/react/contentCollections.d.ts +4 -0
- package/dist/react/contentCollections.js +48 -0
- package/dist/react/docs.d.ts +14 -0
- package/dist/react/docs.js +207 -0
- package/dist/react/entries.js +6 -7
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +1 -0
- package/dist/react/server.d.ts +2 -1
- package/dist/react/server.js +1 -0
- package/dist/react/sitemap.js +7 -20
- package/dist/react/slugs.js +7 -20
- package/dist/react/types.d.ts +17 -0
- package/dist/site-templates/BlogTemplates.js +16 -12
- package/dist/site-templates/DocsSidebar.d.ts +1 -1
- package/dist/site-templates/DocsSidebar.js +2 -2
- package/dist/site-templates/DocsTemplates.d.ts +9 -8
- package/dist/site-templates/DocsTemplates.js +32 -18
- package/dist/site-templates/SiteFooter.js +1 -1
- package/dist/site-templates/SiteLayout.js +1 -1
- package/dist/site-templates/TopNav.js +1 -1
- package/dist/site-templates/blog-styles.css +259 -0
- package/dist/site-templates/blogControls.js +2 -2
- package/dist/site-templates/blogTemplateUi.d.ts +10 -0
- package/dist/site-templates/blogTemplateUi.js +4 -0
- package/dist/site-templates/content-styles.css +127 -309
- package/dist/site-templates/contentIndex.d.ts +4 -7
- package/dist/site-templates/contentIndex.js +25 -1
- package/dist/site-templates/contentUi.js +4 -3
- package/dist/site-templates/dashboard-styles.css +109 -0
- package/dist/site-templates/docs-layout.css +372 -0
- package/dist/site-templates/docs-styles.css +288 -96
- package/dist/site-templates/docsNavigation.d.ts +50 -1
- package/dist/site-templates/docsNavigation.js +242 -8
- package/dist/site-templates/docsTemplateShell.d.ts +8 -0
- package/dist/site-templates/docsTemplateShell.js +14 -0
- package/dist/site-templates/index.d.ts +2 -1
- package/dist/site-templates/index.js +2 -1
- package/dist/site-templates/styles.css +283 -201
- package/package.json +1 -1
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import { normalizeDocsSlug, sortDocsEntries, } from "../docsContract.js";
|
|
1
2
|
import { isRouteActive, normalizeRoutePath } from "./routing.js";
|
|
2
3
|
export function buildDocsSidebarSections(docs, basePath = "/docs") {
|
|
3
4
|
const grouped = new Map();
|
|
4
5
|
docs.forEach((doc) => {
|
|
5
6
|
const sectionLabel = doc.category ?? "Overview";
|
|
6
|
-
const sectionKey =
|
|
7
|
+
const sectionKey = normalizeFragment(doc.sectionKey ?? sectionLabel) || "overview";
|
|
7
8
|
const current = grouped.get(sectionKey) ?? { label: sectionLabel, items: [] };
|
|
8
9
|
current.items.push({
|
|
9
10
|
key: doc.slug,
|
|
10
|
-
label: doc.title,
|
|
11
|
-
href:
|
|
11
|
+
label: doc.navLabel ?? doc.title,
|
|
12
|
+
href: buildDocHref(basePath, doc.slug),
|
|
13
|
+
badge: doc.badge,
|
|
12
14
|
});
|
|
13
15
|
grouped.set(sectionKey, current);
|
|
14
16
|
});
|
|
@@ -16,18 +18,77 @@ export function buildDocsSidebarSections(docs, basePath = "/docs") {
|
|
|
16
18
|
.map(([key, value]) => ({
|
|
17
19
|
key,
|
|
18
20
|
label: value.label,
|
|
19
|
-
items: [...value.items].sort((left, right) => left.label.localeCompare(right.label))
|
|
21
|
+
items: [...value.items].sort((left, right) => left.label.localeCompare(right.label)),
|
|
20
22
|
}))
|
|
21
23
|
.sort((left, right) => left.label.localeCompare(right.label));
|
|
22
24
|
}
|
|
25
|
+
export function fetchDocEntry(docs, slugOrPath, options = {}) {
|
|
26
|
+
const normalizedLookup = normalizeDocsSlug(slugOrPath, options);
|
|
27
|
+
return docs.find((doc) => docLookupCandidates(doc, options).some((candidate) => matchesDocLookup(candidate, normalizedLookup)));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds sidebar-ready docs navigation from a normalized docs collection.
|
|
31
|
+
*
|
|
32
|
+
* Groups by product automatically when multiple products exist and preserves explicit ordering fields when present.
|
|
33
|
+
*/
|
|
34
|
+
export function buildDocsNavigation(docs, options = {}) {
|
|
35
|
+
const sections = buildDocsTreeSections(docs, options)
|
|
36
|
+
.map((section) => ({
|
|
37
|
+
key: section.key,
|
|
38
|
+
label: section.label,
|
|
39
|
+
items: flattenDocsTreeNodes(section.nodes),
|
|
40
|
+
}))
|
|
41
|
+
.filter((section) => section.items.length > 0);
|
|
42
|
+
const activeSections = withActiveDocsSidebar(sections, options.currentPath);
|
|
43
|
+
if (!options.collapsible || !options.currentPath) {
|
|
44
|
+
return activeSections;
|
|
45
|
+
}
|
|
46
|
+
return activeSections.map((section) => ({
|
|
47
|
+
...section,
|
|
48
|
+
collapsed: !section.items.some((item) => item.isActive),
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
export function buildDocsTree(docs, basePath = "/docs") {
|
|
52
|
+
return buildDocsTreeSections(docs, { basePath });
|
|
53
|
+
}
|
|
54
|
+
export function buildHierarchicalDocsSidebarSections(docs, basePath = "/docs") {
|
|
55
|
+
return buildDocsNavigation(docs, { basePath });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds previous/next links from the same ordered docs collection used for navigation.
|
|
59
|
+
*
|
|
60
|
+
* When the current doc belongs to a product, pager links stay inside that product by default.
|
|
61
|
+
*/
|
|
62
|
+
export function buildDocsArticlePager(docs, currentSlugOrPath, options = {}) {
|
|
63
|
+
const current = fetchDocEntry(docs, currentSlugOrPath, options);
|
|
64
|
+
if (!current) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
const scopedProduct = options.productSlug ?? current.productSlug;
|
|
68
|
+
const orderedDocs = resolveOrderedDocs(docs, {
|
|
69
|
+
...options,
|
|
70
|
+
productSlug: scopedProduct,
|
|
71
|
+
});
|
|
72
|
+
const currentIndex = orderedDocs.findIndex((doc) => normalizeDocsSlug(doc.slug, options) === normalizeDocsSlug(current.slug, options));
|
|
73
|
+
if (currentIndex === -1) {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
previousDoc: buildDocsPagerLink(orderedDocs[currentIndex - 1], options.basePath),
|
|
78
|
+
nextDoc: buildDocsPagerLink(orderedDocs[currentIndex + 1], options.basePath),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function buildDocsPrevNext(docs, currentSlugOrPath, options = {}) {
|
|
82
|
+
return buildDocsArticlePager(docs, currentSlugOrPath, options);
|
|
83
|
+
}
|
|
23
84
|
export function withActiveDocsSidebar(sections, currentPath) {
|
|
24
85
|
if (!currentPath) {
|
|
25
86
|
return sections.map((section) => ({
|
|
26
87
|
...section,
|
|
27
88
|
items: section.items.map((item) => ({
|
|
28
89
|
...item,
|
|
29
|
-
isActive: item.isActive ?? false
|
|
30
|
-
}))
|
|
90
|
+
isActive: item.isActive ?? false,
|
|
91
|
+
})),
|
|
31
92
|
}));
|
|
32
93
|
}
|
|
33
94
|
const candidateLengths = sections
|
|
@@ -43,8 +104,181 @@ export function withActiveDocsSidebar(sections, currentPath) {
|
|
|
43
104
|
isRouteActive(item.href, currentPath);
|
|
44
105
|
return {
|
|
45
106
|
...item,
|
|
46
|
-
isActive: item.isActive ?? inferredActive
|
|
107
|
+
isActive: item.isActive ?? inferredActive,
|
|
47
108
|
};
|
|
48
|
-
})
|
|
109
|
+
}),
|
|
49
110
|
}));
|
|
50
111
|
}
|
|
112
|
+
function buildDocsTreeSections(docs, options) {
|
|
113
|
+
const orderedDocs = resolveOrderedDocs(docs, options);
|
|
114
|
+
const groupByProduct = shouldGroupByProduct(orderedDocs, options.groupByProduct);
|
|
115
|
+
const sections = [];
|
|
116
|
+
const sectionMap = new Map();
|
|
117
|
+
orderedDocs.forEach((doc) => {
|
|
118
|
+
const identity = sectionIdentity(doc, groupByProduct);
|
|
119
|
+
let section = sectionMap.get(identity.key);
|
|
120
|
+
if (!section) {
|
|
121
|
+
section = { key: identity.key, label: identity.label, nodes: [] };
|
|
122
|
+
sectionMap.set(identity.key, section);
|
|
123
|
+
sections.push(section);
|
|
124
|
+
}
|
|
125
|
+
insertDocTreeNode(section.nodes, doc, options.basePath ?? "/docs", groupByProduct, options);
|
|
126
|
+
});
|
|
127
|
+
return sections;
|
|
128
|
+
}
|
|
129
|
+
function resolveOrderedDocs(docs, options) {
|
|
130
|
+
return sortDocsEntries(docs.filter((doc) => matchesNavigationScope(doc, options)), { preserveSourceOrder: options.preserveOrder !== false });
|
|
131
|
+
}
|
|
132
|
+
function matchesNavigationScope(doc, options) {
|
|
133
|
+
if (options.productSlug) {
|
|
134
|
+
const productSlug = normalizeDocsSlug(doc.productSlug ?? "", options);
|
|
135
|
+
if (!productSlug || productSlug !== normalizeDocsSlug(options.productSlug, options)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (options.sectionKey) {
|
|
140
|
+
const sectionKey = normalizeFragment(doc.sectionKey);
|
|
141
|
+
if (!sectionKey || sectionKey !== normalizeFragment(options.sectionKey)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
function shouldGroupByProduct(docs, explicit) {
|
|
148
|
+
if (explicit !== undefined) {
|
|
149
|
+
return explicit;
|
|
150
|
+
}
|
|
151
|
+
return new Set(docs.map((doc) => normalizeFragment(doc.productSlug)).filter(Boolean)).size > 1;
|
|
152
|
+
}
|
|
153
|
+
function sectionIdentity(doc, groupByProduct) {
|
|
154
|
+
if (groupByProduct) {
|
|
155
|
+
const productSlug = normalizeDocsSlug(doc.productSlug ?? doc.slug.split("/")[0] ?? "");
|
|
156
|
+
return {
|
|
157
|
+
key: productSlug || "docs",
|
|
158
|
+
label: doc.productLabel ?? humanizeDocSegment(productSlug || "docs"),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const label = doc.sectionLabel ?? doc.category ?? "Overview";
|
|
162
|
+
return {
|
|
163
|
+
key: normalizeFragment(doc.sectionKey ?? label) || "overview",
|
|
164
|
+
label,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function insertDocTreeNode(nodes, doc, basePath, groupByProduct, options) {
|
|
168
|
+
const fullSegments = normalizedDocSegments(doc.slug, options);
|
|
169
|
+
const visibleSegments = visibleDocSegments(doc, groupByProduct, options);
|
|
170
|
+
if (visibleSegments.length === 0) {
|
|
171
|
+
nodes.push({
|
|
172
|
+
key: doc.slug,
|
|
173
|
+
slug: normalizeDocsSlug(doc.slug, options),
|
|
174
|
+
label: doc.navLabel ?? doc.title,
|
|
175
|
+
href: buildDocHref(basePath, doc.slug),
|
|
176
|
+
entry: doc,
|
|
177
|
+
children: [],
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
let cursor = nodes;
|
|
182
|
+
const hiddenCount = fullSegments.length - visibleSegments.length;
|
|
183
|
+
visibleSegments.forEach((segment, index) => {
|
|
184
|
+
const fullSlug = fullSegments.slice(0, hiddenCount + index + 1).join("/");
|
|
185
|
+
let node = cursor.find((candidate) => candidate.slug === fullSlug);
|
|
186
|
+
if (!node) {
|
|
187
|
+
node = {
|
|
188
|
+
key: fullSlug || "index",
|
|
189
|
+
slug: fullSlug,
|
|
190
|
+
label: humanizeDocSegment(segment),
|
|
191
|
+
children: [],
|
|
192
|
+
};
|
|
193
|
+
cursor.push(node);
|
|
194
|
+
}
|
|
195
|
+
if (index === visibleSegments.length - 1) {
|
|
196
|
+
node.entry = doc;
|
|
197
|
+
node.href = buildDocHref(basePath, doc.slug);
|
|
198
|
+
node.label = doc.navLabel ?? doc.title;
|
|
199
|
+
}
|
|
200
|
+
cursor = node.children;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function visibleDocSegments(doc, groupByProduct, options) {
|
|
204
|
+
const segments = normalizedDocSegments(doc.slug, options);
|
|
205
|
+
if (groupByProduct) {
|
|
206
|
+
const productSlug = normalizeDocsSlug(doc.productSlug ?? "", options);
|
|
207
|
+
if (productSlug && segments[0] === productSlug) {
|
|
208
|
+
return segments.slice(1);
|
|
209
|
+
}
|
|
210
|
+
return segments;
|
|
211
|
+
}
|
|
212
|
+
const withoutProduct = doc.productSlug && segments[0] === normalizeDocsSlug(doc.productSlug, options)
|
|
213
|
+
? segments.slice(1)
|
|
214
|
+
: segments;
|
|
215
|
+
const sectionKey = normalizeFragment(doc.sectionKey);
|
|
216
|
+
if (sectionKey && withoutProduct[0] === sectionKey) {
|
|
217
|
+
return withoutProduct.slice(1);
|
|
218
|
+
}
|
|
219
|
+
return withoutProduct;
|
|
220
|
+
}
|
|
221
|
+
function normalizedDocSegments(slug, options) {
|
|
222
|
+
const normalized = normalizeDocsSlug(slug, options);
|
|
223
|
+
return normalized ? normalized.split("/").filter(Boolean) : ["index"];
|
|
224
|
+
}
|
|
225
|
+
function flattenDocsTreeNodes(nodes, depth = 0) {
|
|
226
|
+
return nodes.flatMap((node) => {
|
|
227
|
+
const items = [];
|
|
228
|
+
if (node.entry && node.href) {
|
|
229
|
+
items.push({
|
|
230
|
+
key: node.key,
|
|
231
|
+
label: node.label,
|
|
232
|
+
href: node.href,
|
|
233
|
+
depth: Math.min(depth, 2),
|
|
234
|
+
badge: node.entry.badge,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
items.push(...flattenDocsTreeNodes(node.children, depth + 1));
|
|
238
|
+
return items;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function buildDocsPagerLink(doc, basePath = "/docs") {
|
|
242
|
+
if (!doc) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
title: doc.title,
|
|
247
|
+
href: buildDocHref(basePath, doc.slug),
|
|
248
|
+
entry: doc,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function buildDocHref(basePath, slug) {
|
|
252
|
+
const normalizedBasePath = normalizeRoutePath(basePath);
|
|
253
|
+
const normalizedSlug = normalizeDocsSlug(slug, { basePath });
|
|
254
|
+
if (!normalizedSlug || normalizedSlug === "index") {
|
|
255
|
+
return normalizedBasePath;
|
|
256
|
+
}
|
|
257
|
+
if (normalizedBasePath === "/") {
|
|
258
|
+
return `/${normalizedSlug}`;
|
|
259
|
+
}
|
|
260
|
+
return `${normalizedBasePath}/${normalizedSlug}`;
|
|
261
|
+
}
|
|
262
|
+
function docLookupCandidates(doc, options) {
|
|
263
|
+
const candidates = [normalizeDocsSlug(doc.slug, options)];
|
|
264
|
+
doc.aliases?.forEach((alias) => {
|
|
265
|
+
const normalized = normalizeDocsSlug(alias, options);
|
|
266
|
+
if (normalized) {
|
|
267
|
+
candidates.push(normalized);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return [...new Set(candidates.filter(Boolean))];
|
|
271
|
+
}
|
|
272
|
+
function matchesDocLookup(candidate, lookup) {
|
|
273
|
+
return candidate === lookup || (!lookup && (candidate === "" || candidate === "index"));
|
|
274
|
+
}
|
|
275
|
+
function normalizeFragment(value) {
|
|
276
|
+
return (value ?? "")
|
|
277
|
+
.trim()
|
|
278
|
+
.toLowerCase()
|
|
279
|
+
.replace(/[^a-z0-9]+/gu, "-")
|
|
280
|
+
.replace(/^-+|-+$/gu, "");
|
|
281
|
+
}
|
|
282
|
+
function humanizeDocSegment(segment) {
|
|
283
|
+
return segment.replace(/[-_]+/gu, " ").replace(/\b\w/gu, (char) => char.toUpperCase());
|
|
284
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type SiteNavigationItem } from "./SiteLayout.js";
|
|
2
|
+
export interface DocsTemplateShellOptions {
|
|
3
|
+
siteTitle?: string;
|
|
4
|
+
navigation?: SiteNavigationItem[];
|
|
5
|
+
headless?: boolean;
|
|
6
|
+
renderLayout?: (content: React.JSX.Element) => React.JSX.Element;
|
|
7
|
+
}
|
|
8
|
+
export declare function renderDocsTemplateShell(content: React.JSX.Element, options: DocsTemplateShellOptions): React.JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SiteLayout } from "./SiteLayout.js";
|
|
3
|
+
export function renderDocsTemplateShell(content, options) {
|
|
4
|
+
if (options.renderLayout) {
|
|
5
|
+
return options.renderLayout(content);
|
|
6
|
+
}
|
|
7
|
+
if (options.headless) {
|
|
8
|
+
return content;
|
|
9
|
+
}
|
|
10
|
+
if (options.siteTitle === undefined || options.navigation === undefined) {
|
|
11
|
+
throw new Error("Docs templates require `siteTitle` and `navigation` unless `headless` or `renderLayout` is provided.");
|
|
12
|
+
}
|
|
13
|
+
return (_jsx(SiteLayout, { siteTitle: options.siteTitle, navigation: options.navigation, children: content }));
|
|
14
|
+
}
|
|
@@ -5,7 +5,8 @@ export { DashboardShell, type DashboardShellProps, type DashboardNavItem } from
|
|
|
5
5
|
export { DashboardOverviewTemplate, type DashboardOverviewTemplateProps, type DashboardPanel, type DashboardStat } from "./DashboardOverviewTemplate.js";
|
|
6
6
|
export { isRouteActive, normalizeRoutePath, withActiveRouteState, type RouteAwareItem, type RouteMatcherOptions } from "./routing.js";
|
|
7
7
|
export { buildContentListHref, collectFilterValues, collectDimensionValues, matchesFilterDimensions, prepareBlogIndex, prepareDocsIndex, type BlogIndexEntry, type BlogIndexQuery, type DocsIndexEntry, type DocsIndexQuery, type FilterDimension, type FilterDimensionValues, type PaginationResult } from "./contentIndex.js";
|
|
8
|
-
export { buildDocsSidebarSections, withActiveDocsSidebar, type DocsSidebarItem, type DocsSidebarSection } from "./docsNavigation.js";
|
|
8
|
+
export { buildDocsNavigation, buildDocsArticlePager, buildDocsSidebarSections, buildDocsTree, buildHierarchicalDocsSidebarSections, buildDocsPrevNext, fetchDocEntry, withActiveDocsSidebar, type DocsTreeNode, type DocsTreeSection, type DocsPagerLink, type DocsPrevNext, type DocsNavigationOptions, type FetchDocEntryOptions, type DocsSidebarItem, type DocsSidebarSection } from "./docsNavigation.js";
|
|
9
|
+
export { normalizeDocsHref, normalizeDocsSlug, type DocsBreadcrumb, type DocsEntryRecord, type DocsNormalizationOptions, type DocsTocHeading, } from "../docsContract.js";
|
|
9
10
|
export { MarkdownContent, type MarkdownContentProps } from "./MarkdownContent.js";
|
|
10
11
|
export { extractTocFromMarkdown, type TocEntry } from "./tocExtractor.js";
|
|
11
12
|
export { DocsSidebar, type DocsSidebarProps } from "./DocsSidebar.js";
|
|
@@ -5,7 +5,8 @@ export { DashboardShell } from "./DashboardShell.js";
|
|
|
5
5
|
export { DashboardOverviewTemplate } from "./DashboardOverviewTemplate.js";
|
|
6
6
|
export { isRouteActive, normalizeRoutePath, withActiveRouteState } from "./routing.js";
|
|
7
7
|
export { buildContentListHref, collectFilterValues, collectDimensionValues, matchesFilterDimensions, prepareBlogIndex, prepareDocsIndex } from "./contentIndex.js";
|
|
8
|
-
export { buildDocsSidebarSections, withActiveDocsSidebar } from "./docsNavigation.js";
|
|
8
|
+
export { buildDocsNavigation, buildDocsArticlePager, buildDocsSidebarSections, buildDocsTree, buildHierarchicalDocsSidebarSections, buildDocsPrevNext, fetchDocEntry, withActiveDocsSidebar } from "./docsNavigation.js";
|
|
9
|
+
export { normalizeDocsHref, normalizeDocsSlug, } from "../docsContract.js";
|
|
9
10
|
export { MarkdownContent } from "./MarkdownContent.js";
|
|
10
11
|
export { extractTocFromMarkdown } from "./tocExtractor.js";
|
|
11
12
|
export { DocsSidebar } from "./DocsSidebar.js";
|