@canopy-iiif/app 0.12.1 → 0.12.2
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/lib/build/mdx.js +16 -0
- package/lib/build/pages.js +20 -4
- package/lib/components/navigation.js +18 -0
- package/package.json +1 -1
- package/ui/dist/server.mjs +40 -27
- package/ui/dist/server.mjs.map +2 -2
- package/ui/styles/base/_heading.scss +8 -2
- package/ui/styles/components/_interstitial-hero.scss +1 -1
- package/ui/styles/components/_sub-navigation.scss +28 -1
- package/ui/styles/index.css +34 -3
package/lib/build/mdx.js
CHANGED
|
@@ -81,6 +81,21 @@ function parseFrontmatter(src) {
|
|
|
81
81
|
return {data, content};
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
function isRoadmapEntry(frontmatterData) {
|
|
85
|
+
if (!frontmatterData || typeof frontmatterData !== "object") return false;
|
|
86
|
+
if (!Object.prototype.hasOwnProperty.call(frontmatterData, "roadmap")) return false;
|
|
87
|
+
const raw = frontmatterData.roadmap;
|
|
88
|
+
if (typeof raw === "boolean") return raw;
|
|
89
|
+
if (typeof raw === "number") return raw !== 0;
|
|
90
|
+
if (typeof raw === "string") {
|
|
91
|
+
const normalized = raw.trim().toLowerCase();
|
|
92
|
+
if (!normalized) return false;
|
|
93
|
+
if (["false", "0", "no", "off", "none"].includes(normalized)) return false;
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return !!raw;
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
// ESM-only in v3; load dynamically from CJS
|
|
85
100
|
let MDXProviderCached = null;
|
|
86
101
|
async function getMdxProvider() {
|
|
@@ -1159,6 +1174,7 @@ module.exports = {
|
|
|
1159
1174
|
extractMarkdownSummary,
|
|
1160
1175
|
isReservedFile,
|
|
1161
1176
|
parseFrontmatter,
|
|
1177
|
+
isRoadmapEntry,
|
|
1162
1178
|
compileMdxFile,
|
|
1163
1179
|
compileMdxToComponent,
|
|
1164
1180
|
loadCustomLayout,
|
package/lib/build/pages.js
CHANGED
|
@@ -77,8 +77,9 @@ function mapContentPathToOutput(filePath) {
|
|
|
77
77
|
return path.join(OUT_DIR, outRel);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
async function renderContentMdxToHtml(filePath, outPath, extraProps = {}) {
|
|
81
|
-
const
|
|
80
|
+
async function renderContentMdxToHtml(filePath, outPath, extraProps = {}, sourceOverride = null) {
|
|
81
|
+
const sourceRaw = sourceOverride != null ? sourceOverride : await fsp.readFile(filePath, 'utf8');
|
|
82
|
+
const source = typeof sourceRaw === 'string' ? sourceRaw : String(sourceRaw || '');
|
|
82
83
|
const title = mdx.extractTitle(source);
|
|
83
84
|
const relContentPath = path.relative(CONTENT_DIR, filePath);
|
|
84
85
|
const normalizedRel = navigation.normalizeRelativePath(relContentPath);
|
|
@@ -259,12 +260,27 @@ async function processContentEntry(absPath, pagesMetadata = []) {
|
|
|
259
260
|
if (/\.mdx$/i.test(absPath)) {
|
|
260
261
|
if (mdx.isReservedFile(absPath)) return;
|
|
261
262
|
const outPath = mapContentPathToOutput(absPath);
|
|
262
|
-
ensureDirSync(path.dirname(outPath));
|
|
263
263
|
try {
|
|
264
|
+
const source = await fsp.readFile(absPath, 'utf8');
|
|
265
|
+
const frontmatter = typeof mdx.parseFrontmatter === 'function'
|
|
266
|
+
? mdx.parseFrontmatter(source)
|
|
267
|
+
: { data: null };
|
|
268
|
+
const frontmatterData = frontmatter && isPlainObject(frontmatter.data) ? frontmatter.data : null;
|
|
269
|
+
const isRoadmap = frontmatterData && typeof mdx.isRoadmapEntry === 'function'
|
|
270
|
+
? mdx.isRoadmapEntry(frontmatterData)
|
|
271
|
+
: false;
|
|
272
|
+
if (isRoadmap) {
|
|
273
|
+
try { await fsp.rm(outPath, { force: true }); } catch (_) {}
|
|
274
|
+
try {
|
|
275
|
+
log(`• Skipped roadmap page ${path.relative(process.cwd(), absPath)}\n`, 'yellow', { dim: true });
|
|
276
|
+
} catch (_) {}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
ensureDirSync(path.dirname(outPath));
|
|
264
280
|
try { log(`• Processing MDX ${absPath}\n`, 'blue'); } catch (_) {}
|
|
265
281
|
const base = path.basename(absPath);
|
|
266
282
|
const extra = base.toLowerCase() === 'sitemap.mdx' ? { pages: pagesMetadata } : {};
|
|
267
|
-
const html = await renderContentMdxToHtml(absPath, outPath, extra);
|
|
283
|
+
const html = await renderContentMdxToHtml(absPath, outPath, extra, source);
|
|
268
284
|
await fsp.writeFile(outPath, html || '', 'utf8');
|
|
269
285
|
try { log(`✓ Built ${path.relative(process.cwd(), outPath)}\n`, 'green'); } catch (_) {}
|
|
270
286
|
} catch (err) {
|
|
@@ -88,6 +88,20 @@ function collectPagesSync() {
|
|
|
88
88
|
} catch (_) {
|
|
89
89
|
raw = "";
|
|
90
90
|
}
|
|
91
|
+
let frontmatterData = null;
|
|
92
|
+
if (raw && typeof mdx.parseFrontmatter === "function") {
|
|
93
|
+
try {
|
|
94
|
+
const parsed = mdx.parseFrontmatter(raw);
|
|
95
|
+
if (parsed && parsed.data && typeof parsed.data === "object") {
|
|
96
|
+
frontmatterData = parsed.data;
|
|
97
|
+
}
|
|
98
|
+
} catch (_) {
|
|
99
|
+
frontmatterData = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const isRoadmap = frontmatterData && typeof mdx.isRoadmapEntry === "function"
|
|
103
|
+
? mdx.isRoadmapEntry(frontmatterData)
|
|
104
|
+
: false;
|
|
91
105
|
const {
|
|
92
106
|
slug,
|
|
93
107
|
segments: slugSegments,
|
|
@@ -114,6 +128,7 @@ function collectPagesSync() {
|
|
|
114
128
|
fallbackTitle,
|
|
115
129
|
sortKey: pageSortKey(normalizedRel),
|
|
116
130
|
topSegment: slugSegments[0] || firstSegment || "",
|
|
131
|
+
isRoadmap,
|
|
117
132
|
};
|
|
118
133
|
pages.push(page);
|
|
119
134
|
}
|
|
@@ -138,6 +153,7 @@ function createNode(slug) {
|
|
|
138
153
|
sortKey: slug || name,
|
|
139
154
|
sourcePage: null,
|
|
140
155
|
children: [],
|
|
156
|
+
isRoadmap: false,
|
|
141
157
|
};
|
|
142
158
|
}
|
|
143
159
|
|
|
@@ -173,6 +189,7 @@ function getNavigationCache() {
|
|
|
173
189
|
node.relativePath = page.relativePath;
|
|
174
190
|
node.sortKey = page.sortKey || node.sortKey;
|
|
175
191
|
node.hasContent = true;
|
|
192
|
+
node.isRoadmap = !!page.isRoadmap;
|
|
176
193
|
}
|
|
177
194
|
}
|
|
178
195
|
|
|
@@ -240,6 +257,7 @@ function cloneNode(node, currentSlug) {
|
|
|
240
257
|
hasContent: node.hasContent,
|
|
241
258
|
relativePath: node.relativePath,
|
|
242
259
|
children,
|
|
260
|
+
isRoadmap: !!node.isRoadmap,
|
|
243
261
|
};
|
|
244
262
|
}
|
|
245
263
|
|
package/package.json
CHANGED
package/ui/dist/server.mjs
CHANGED
|
@@ -717,7 +717,8 @@ function Hero({
|
|
|
717
717
|
import React10 from "react";
|
|
718
718
|
import navigationHelpers from "@canopy-iiif/app/lib/components/navigation.js";
|
|
719
719
|
function resolveRelativeCandidate(page, current) {
|
|
720
|
-
if (page && typeof page.relativePath === "string" && page.relativePath)
|
|
720
|
+
if (page && typeof page.relativePath === "string" && page.relativePath)
|
|
721
|
+
return page.relativePath;
|
|
721
722
|
if (page && typeof page.slug === "string" && page.slug) return page.slug;
|
|
722
723
|
if (typeof current === "string" && current) return current;
|
|
723
724
|
return "";
|
|
@@ -731,32 +732,33 @@ function renderNodes(nodes, parentKey = "node") {
|
|
|
731
732
|
const showChildren = hasChildren && (node.isExpanded || node.depth === 0);
|
|
732
733
|
const depth = typeof node.depth === "number" ? Math.max(0, node.depth) : 0;
|
|
733
734
|
const depthClass = `depth-${Math.min(depth, 5)}`;
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (
|
|
735
|
+
const isRoadmap = !!node.isRoadmap;
|
|
736
|
+
const isInteractive = !!(node.href && !isRoadmap);
|
|
737
|
+
const classes = ["canopy-sub-navigation__link", depthClass];
|
|
738
|
+
if (!node.href && !isRoadmap) classes.push("is-label");
|
|
739
|
+
if (isRoadmap) classes.push("is-disabled");
|
|
739
740
|
if (node.isActive) classes.push("is-active");
|
|
740
741
|
const linkClass = classes.join(" ");
|
|
741
|
-
const Tag =
|
|
742
|
-
|
|
743
|
-
|
|
742
|
+
const Tag = isInteractive ? "a" : "span";
|
|
743
|
+
const badge = isRoadmap ? /* @__PURE__ */ React10.createElement("span", { className: "canopy-sub-navigation__badge" }, "Beta") : null;
|
|
744
|
+
return /* @__PURE__ */ React10.createElement("li", { key, className: "canopy-sub-navigation__item", "data-depth": depth }, /* @__PURE__ */ React10.createElement(
|
|
745
|
+
Tag,
|
|
744
746
|
{
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
"
|
|
747
|
+
className: linkClass,
|
|
748
|
+
href: isInteractive ? node.href : void 0,
|
|
749
|
+
"aria-current": node.isActive ? "page" : void 0,
|
|
750
|
+
tabIndex: isInteractive ? void 0 : -1
|
|
748
751
|
},
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
)
|
|
758
|
-
|
|
759
|
-
);
|
|
752
|
+
node.title || node.slug,
|
|
753
|
+
badge
|
|
754
|
+
), showChildren ? /* @__PURE__ */ React10.createElement(
|
|
755
|
+
"ul",
|
|
756
|
+
{
|
|
757
|
+
className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
|
|
758
|
+
role: "list"
|
|
759
|
+
},
|
|
760
|
+
renderNodes(node.children, key)
|
|
761
|
+
) : null);
|
|
760
762
|
});
|
|
761
763
|
}
|
|
762
764
|
function SubNavigation({
|
|
@@ -775,7 +777,8 @@ function SubNavigation({
|
|
|
775
777
|
const effectiveNavigation = navigationProp || contextNavigation;
|
|
776
778
|
const effectivePage = page || contextPage;
|
|
777
779
|
const resolvedNavigation = React10.useMemo(() => {
|
|
778
|
-
if (effectiveNavigation && effectiveNavigation.root)
|
|
780
|
+
if (effectiveNavigation && effectiveNavigation.root)
|
|
781
|
+
return effectiveNavigation;
|
|
779
782
|
const candidate = resolveRelativeCandidate(effectivePage, current);
|
|
780
783
|
if (!candidate) return effectiveNavigation || null;
|
|
781
784
|
const helpers2 = navigationHelpers && navigationHelpers.buildNavigationForFile ? navigationHelpers : null;
|
|
@@ -798,7 +801,16 @@ function SubNavigation({
|
|
|
798
801
|
if (!Object.prototype.hasOwnProperty.call(inlineStyle, "--sub-nav-indent")) {
|
|
799
802
|
inlineStyle["--sub-nav-indent"] = "0.85rem";
|
|
800
803
|
}
|
|
801
|
-
return /* @__PURE__ */ React10.createElement(
|
|
804
|
+
return /* @__PURE__ */ React10.createElement(
|
|
805
|
+
"nav",
|
|
806
|
+
{
|
|
807
|
+
className: combinedClassName,
|
|
808
|
+
style: inlineStyle,
|
|
809
|
+
"aria-label": navLabel
|
|
810
|
+
},
|
|
811
|
+
finalHeading ? /* @__PURE__ */ React10.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null,
|
|
812
|
+
/* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root"))
|
|
813
|
+
);
|
|
802
814
|
}
|
|
803
815
|
|
|
804
816
|
// ui/src/layout/Layout.jsx
|
|
@@ -2437,6 +2449,7 @@ function DocsCodeBlock(props = {}) {
|
|
|
2437
2449
|
display: "inline"
|
|
2438
2450
|
};
|
|
2439
2451
|
const showFilename = Boolean(filename);
|
|
2452
|
+
const showHeader = showFilename || enableCopy;
|
|
2440
2453
|
const { style: preStyleOverride, className: preClassName, ...preRest } = rest;
|
|
2441
2454
|
const mergedPreStyle = Object.assign({}, preStyle, preStyleOverride || {});
|
|
2442
2455
|
const lineElements = lines.map((line, index) => {
|
|
@@ -2453,7 +2466,7 @@ function DocsCodeBlock(props = {}) {
|
|
|
2453
2466
|
return React30.createElement(
|
|
2454
2467
|
"div",
|
|
2455
2468
|
{ style: containerStyle },
|
|
2456
|
-
React30.createElement(
|
|
2469
|
+
showHeader ? React30.createElement(
|
|
2457
2470
|
"div",
|
|
2458
2471
|
{ style: headerStyle },
|
|
2459
2472
|
React30.createElement("span", null, showFilename ? filename : null),
|
|
@@ -2475,7 +2488,7 @@ function DocsCodeBlock(props = {}) {
|
|
|
2475
2488
|
},
|
|
2476
2489
|
copied ? "Copied" : "Copy"
|
|
2477
2490
|
) : null
|
|
2478
|
-
),
|
|
2491
|
+
) : null,
|
|
2479
2492
|
React30.createElement(
|
|
2480
2493
|
"pre",
|
|
2481
2494
|
{ ...preRest, className: preClassName, style: mergedPreStyle },
|