lildocs 0.1.16 → 0.1.17
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/dist/cli.mjs +53 -18
- package/dist/render/styles.css +49 -6
- package/dist/render/table-viewer.ts +75 -12
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
12
12
|
import markedShiki from "marked-shiki";
|
|
13
13
|
import { bundledThemes, codeToHtml } from "shiki";
|
|
14
14
|
import { decodeHTML } from "entities";
|
|
15
|
-
import { renderMermaidSVG } from "beautiful-mermaid";
|
|
15
|
+
import { fromShikiTheme, renderMermaidSVG } from "beautiful-mermaid";
|
|
16
16
|
import os from "node:os";
|
|
17
17
|
import { generateMarkdownForModule } from "exports-md";
|
|
18
18
|
import { clampGamut, converter, formatHex, parse, wcagContrast } from "culori";
|
|
@@ -914,10 +914,15 @@ function escapeHtml$1(value) {
|
|
|
914
914
|
//#endregion
|
|
915
915
|
//#region src/core/mermaid.ts
|
|
916
916
|
async function createMermaidRenderer(options) {
|
|
917
|
+
const lightColors = await loadShikiColors(options.themeConfig.light);
|
|
918
|
+
const darkColors = options.themeConfig.dark ? await loadShikiColors(options.themeConfig.dark) : void 0;
|
|
919
|
+
const colorKeys = sharedColorKeys(lightColors, darkColors);
|
|
920
|
+
const renderOptions = toRenderOptions(colorKeys, options.themeConfig.fontFamily);
|
|
917
921
|
return {
|
|
922
|
+
css: toThemeCss(lightColors, darkColors, colorKeys),
|
|
918
923
|
async render(source, idHint) {
|
|
919
924
|
try {
|
|
920
|
-
const svg = addImageRole(renderMermaidSVG(source,
|
|
925
|
+
const svg = addImageRole(renderMermaidSVG(source, renderOptions));
|
|
921
926
|
return `<figure class="mermaidDiagram" id="${escapeHtml(idHint)}">${svg}</figure>`;
|
|
922
927
|
} catch (error) {
|
|
923
928
|
throw new LildocsError(`Failed to render Mermaid diagram ${idHint}: ${errorMessage$1(error)}`);
|
|
@@ -926,17 +931,51 @@ async function createMermaidRenderer(options) {
|
|
|
926
931
|
async close() {}
|
|
927
932
|
};
|
|
928
933
|
}
|
|
929
|
-
|
|
934
|
+
const optionalColorKeys = [
|
|
935
|
+
"line",
|
|
936
|
+
"accent",
|
|
937
|
+
"muted",
|
|
938
|
+
"surface",
|
|
939
|
+
"border"
|
|
940
|
+
];
|
|
941
|
+
async function loadShikiColors(themeName) {
|
|
942
|
+
const themeLoader = bundledThemes[themeName];
|
|
943
|
+
if (!themeLoader) throw new LildocsError(`Unknown bundled Shiki theme: ${themeName}`);
|
|
944
|
+
const themeModule = await themeLoader();
|
|
945
|
+
return fromShikiTheme("default" in themeModule ? themeModule.default : themeModule);
|
|
946
|
+
}
|
|
947
|
+
function sharedColorKeys(light, dark) {
|
|
948
|
+
return optionalColorKeys.filter((key) => light[key] !== void 0 && (!dark || dark[key] !== void 0));
|
|
949
|
+
}
|
|
950
|
+
function toRenderOptions(colorKeys, fontFamily) {
|
|
930
951
|
return {
|
|
931
|
-
bg:
|
|
932
|
-
fg:
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
surface: themeConfig.surface,
|
|
936
|
-
border: themeConfig.border,
|
|
937
|
-
font: themeConfig.fontFamily
|
|
952
|
+
bg: "var(--ld-mermaid-bg)",
|
|
953
|
+
fg: "var(--ld-mermaid-fg)",
|
|
954
|
+
...Object.fromEntries(colorKeys.map((key) => [key, `var(--ld-mermaid-${key})`])),
|
|
955
|
+
font: fontFamily
|
|
938
956
|
};
|
|
939
957
|
}
|
|
958
|
+
function toThemeCss(light, dark, colorKeys) {
|
|
959
|
+
const lightVariables = toCssVariables(light, colorKeys, " ");
|
|
960
|
+
const darkVariables = dark ? toCssVariables(dark, colorKeys, " ") : void 0;
|
|
961
|
+
return `.mermaidDiagram {
|
|
962
|
+
${lightVariables}
|
|
963
|
+
}${darkVariables ? `
|
|
964
|
+
|
|
965
|
+
@media (prefers-color-scheme: dark) {
|
|
966
|
+
.mermaidDiagram {
|
|
967
|
+
${darkVariables}
|
|
968
|
+
}
|
|
969
|
+
}` : ""}
|
|
970
|
+
`;
|
|
971
|
+
}
|
|
972
|
+
function toCssVariables(colors, colorKeys, indent) {
|
|
973
|
+
return [
|
|
974
|
+
`${indent}--ld-mermaid-bg: ${colors.bg};`,
|
|
975
|
+
`${indent}--ld-mermaid-fg: ${colors.fg};`,
|
|
976
|
+
...colorKeys.map((key) => `${indent}--ld-mermaid-${key}: ${colors[key]};`)
|
|
977
|
+
].join("\n");
|
|
978
|
+
}
|
|
940
979
|
function addImageRole(svg) {
|
|
941
980
|
return svg.replace("<svg", "<svg role=\"img\"");
|
|
942
981
|
}
|
|
@@ -1336,12 +1375,8 @@ function resolveBackgroundOptions(options) {
|
|
|
1336
1375
|
function themeToMermaidConfig(theme, fontOverrides = {}) {
|
|
1337
1376
|
const fonts = resolveThemeFonts(theme.light, fontOverrides);
|
|
1338
1377
|
return {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
accent: theme.light.color.link,
|
|
1342
|
-
muted: theme.light.color.mutedText,
|
|
1343
|
-
surface: theme.light.color.codeBackground,
|
|
1344
|
-
border: theme.light.color.border,
|
|
1378
|
+
light: theme.light.shiki?.theme ?? "github-light",
|
|
1379
|
+
dark: theme.dark?.shiki?.theme,
|
|
1345
1380
|
fontFamily: fonts.body
|
|
1346
1381
|
};
|
|
1347
1382
|
}
|
|
@@ -1668,13 +1703,13 @@ async function buildSite(options) {
|
|
|
1668
1703
|
defaultText: packageName,
|
|
1669
1704
|
favicon: configOptions.favicon
|
|
1670
1705
|
});
|
|
1671
|
-
const
|
|
1706
|
+
const mermaid = await createMermaidRenderer({ themeConfig: themeToMermaidConfig(theme, fontResolution.themeFonts) });
|
|
1707
|
+
const css = `${resolveThemeFontImports(theme, configOptions.fonts)}${fontResolution.css}${themeToCssVariables(theme, fontResolution.themeFonts, configOptions.link, configOptions.navigation)}\n${mermaid.css}${backgroundResolution.css}${logoResolution.css}${baseCss}`;
|
|
1672
1708
|
const assets = [
|
|
1673
1709
|
...fontResolution.assets,
|
|
1674
1710
|
...backgroundResolution.assets,
|
|
1675
1711
|
...logoResolution.assets
|
|
1676
1712
|
];
|
|
1677
|
-
const mermaid = await createMermaidRenderer({ themeConfig: themeToMermaidConfig(theme, fontResolution.themeFonts) });
|
|
1678
1713
|
let frontendRenderer;
|
|
1679
1714
|
try {
|
|
1680
1715
|
await rm(outDir, {
|
package/dist/render/styles.css
CHANGED
|
@@ -271,6 +271,10 @@ html.is-animating .transition-scale {
|
|
|
271
271
|
margin-block: 1em;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
+
.content article > div > ul {
|
|
275
|
+
margin-bottom: 2em;
|
|
276
|
+
}
|
|
277
|
+
|
|
274
278
|
.content :first-child {
|
|
275
279
|
margin-top: 0;
|
|
276
280
|
}
|
|
@@ -524,17 +528,20 @@ html.is-animating .transition-scale {
|
|
|
524
528
|
border-collapse: collapse;
|
|
525
529
|
}
|
|
526
530
|
|
|
527
|
-
.tableFrame
|
|
531
|
+
.tableFrame,
|
|
532
|
+
.mermaidFrame {
|
|
528
533
|
margin-block: 1em;
|
|
529
534
|
}
|
|
530
535
|
|
|
531
|
-
.tableToolbar
|
|
536
|
+
.tableToolbar,
|
|
537
|
+
.mermaidToolbar {
|
|
532
538
|
display: flex;
|
|
533
539
|
justify-content: flex-end;
|
|
534
540
|
margin-top: 8px;
|
|
535
541
|
}
|
|
536
542
|
|
|
537
|
-
.tableViewport
|
|
543
|
+
.tableViewport,
|
|
544
|
+
.mermaidViewport {
|
|
538
545
|
max-width: 100%;
|
|
539
546
|
overflow-x: auto;
|
|
540
547
|
}
|
|
@@ -544,7 +551,12 @@ html.is-animating .transition-scale {
|
|
|
544
551
|
margin: 0;
|
|
545
552
|
}
|
|
546
553
|
|
|
554
|
+
.content .mermaidViewport .mermaidDiagram {
|
|
555
|
+
margin: 0;
|
|
556
|
+
}
|
|
557
|
+
|
|
547
558
|
.tableExpandButton,
|
|
559
|
+
.mermaidExpandButton,
|
|
548
560
|
.tableFullscreenClose {
|
|
549
561
|
display: inline-flex;
|
|
550
562
|
align-items: center;
|
|
@@ -562,19 +574,23 @@ html.is-animating .transition-scale {
|
|
|
562
574
|
}
|
|
563
575
|
|
|
564
576
|
.tableExpandButton .ti,
|
|
577
|
+
.mermaidExpandButton .ti,
|
|
565
578
|
.tableFullscreenClose .ti {
|
|
566
579
|
font-size: 18px;
|
|
567
580
|
}
|
|
568
581
|
|
|
569
582
|
.tableExpandButton:hover,
|
|
570
583
|
.tableExpandButton:focus-visible,
|
|
584
|
+
.mermaidExpandButton:hover,
|
|
585
|
+
.mermaidExpandButton:focus-visible,
|
|
571
586
|
.tableFullscreenClose:hover,
|
|
572
587
|
.tableFullscreenClose:focus-visible {
|
|
573
588
|
border-color: var(--ld-color-link);
|
|
574
589
|
color: var(--ld-color-link);
|
|
575
590
|
}
|
|
576
591
|
|
|
577
|
-
.tableFullscreenDialog
|
|
592
|
+
.tableFullscreenDialog,
|
|
593
|
+
.mermaidFullscreenDialog {
|
|
578
594
|
width: 100vw;
|
|
579
595
|
max-width: none;
|
|
580
596
|
height: 100vh;
|
|
@@ -587,7 +603,8 @@ html.is-animating .transition-scale {
|
|
|
587
603
|
font-family: var(--ld-font-body);
|
|
588
604
|
}
|
|
589
605
|
|
|
590
|
-
.tableFullscreenDialog::backdrop
|
|
606
|
+
.tableFullscreenDialog::backdrop,
|
|
607
|
+
.mermaidFullscreenDialog::backdrop {
|
|
591
608
|
background: color-mix(in srgb, black 35%, transparent);
|
|
592
609
|
}
|
|
593
610
|
|
|
@@ -613,6 +630,31 @@ html.is-animating .transition-scale {
|
|
|
613
630
|
font-size: 105%;
|
|
614
631
|
}
|
|
615
632
|
|
|
633
|
+
.mermaidFullscreenViewport {
|
|
634
|
+
display: grid;
|
|
635
|
+
min-width: 0;
|
|
636
|
+
min-height: 0;
|
|
637
|
+
overflow: auto;
|
|
638
|
+
padding: 20px;
|
|
639
|
+
place-items: center;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.mermaidFullscreenViewport .mermaidDiagram {
|
|
643
|
+
display: flex;
|
|
644
|
+
width: 100%;
|
|
645
|
+
height: 100%;
|
|
646
|
+
margin: 0;
|
|
647
|
+
align-items: center;
|
|
648
|
+
justify-content: center;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.mermaidFullscreenViewport .mermaidDiagram svg {
|
|
652
|
+
width: 100%;
|
|
653
|
+
height: 100%;
|
|
654
|
+
max-width: 100%;
|
|
655
|
+
max-height: 100%;
|
|
656
|
+
}
|
|
657
|
+
|
|
616
658
|
.tableFullscreenViewport table {
|
|
617
659
|
display: table;
|
|
618
660
|
width: max-content;
|
|
@@ -621,7 +663,8 @@ html.is-animating .transition-scale {
|
|
|
621
663
|
border-collapse: collapse;
|
|
622
664
|
}
|
|
623
665
|
|
|
624
|
-
html.tableFullscreenOpen
|
|
666
|
+
html.tableFullscreenOpen,
|
|
667
|
+
html.mermaidFullscreenOpen {
|
|
625
668
|
overflow: hidden;
|
|
626
669
|
}
|
|
627
670
|
|
|
@@ -2,9 +2,11 @@ let activeDialog: HTMLDialogElement | undefined;
|
|
|
2
2
|
|
|
3
3
|
export function initTableViewer() {
|
|
4
4
|
enhanceTables();
|
|
5
|
+
enhanceMermaidDiagrams();
|
|
5
6
|
document.addEventListener("lildocs:page-view", () => {
|
|
6
7
|
activeDialog?.close();
|
|
7
8
|
enhanceTables();
|
|
9
|
+
enhanceMermaidDiagrams();
|
|
8
10
|
});
|
|
9
11
|
}
|
|
10
12
|
|
|
@@ -31,7 +33,16 @@ function enhanceTables() {
|
|
|
31
33
|
const viewport = document.createElement("div");
|
|
32
34
|
viewport.className = "tableViewport";
|
|
33
35
|
|
|
34
|
-
button.addEventListener("click", () =>
|
|
36
|
+
button.addEventListener("click", () =>
|
|
37
|
+
openFullscreenDialog(table, button, {
|
|
38
|
+
dialogClass: "tableFullscreenDialog",
|
|
39
|
+
dialogLabel: "Full screen table",
|
|
40
|
+
title: table.querySelector("caption")?.textContent?.trim() || "Table",
|
|
41
|
+
closeLabel: "Minimize table",
|
|
42
|
+
viewportClass: "tableFullscreenViewport content",
|
|
43
|
+
openClass: "tableFullscreenOpen",
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
35
46
|
table.before(frame);
|
|
36
47
|
toolbar.append(button);
|
|
37
48
|
viewport.append(table);
|
|
@@ -39,29 +50,81 @@ function enhanceTables() {
|
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
function
|
|
53
|
+
function enhanceMermaidDiagrams() {
|
|
54
|
+
const diagrams = document.querySelectorAll<HTMLElement>(
|
|
55
|
+
".content article .mermaidDiagram",
|
|
56
|
+
);
|
|
57
|
+
for (const diagram of Array.from(diagrams)) {
|
|
58
|
+
if (diagram.closest(".mermaidFrame")) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const frame = document.createElement("div");
|
|
63
|
+
frame.className = "mermaidFrame";
|
|
64
|
+
const toolbar = document.createElement("div");
|
|
65
|
+
toolbar.className = "mermaidToolbar";
|
|
66
|
+
const button = document.createElement("button");
|
|
67
|
+
button.type = "button";
|
|
68
|
+
button.className = "mermaidExpandButton";
|
|
69
|
+
button.title = "Expand diagram";
|
|
70
|
+
button.setAttribute("aria-label", "View diagram in full screen");
|
|
71
|
+
button.innerHTML =
|
|
72
|
+
'<span class="ti ti-arrows-maximize" aria-hidden="true"></span>';
|
|
73
|
+
const viewport = document.createElement("div");
|
|
74
|
+
viewport.className = "mermaidViewport";
|
|
75
|
+
|
|
76
|
+
button.addEventListener("click", () =>
|
|
77
|
+
openFullscreenDialog(diagram, button, {
|
|
78
|
+
dialogClass: "mermaidFullscreenDialog",
|
|
79
|
+
dialogLabel: "Full screen diagram",
|
|
80
|
+
title: "Diagram",
|
|
81
|
+
closeLabel: "Minimize diagram",
|
|
82
|
+
viewportClass: "mermaidFullscreenViewport content",
|
|
83
|
+
openClass: "mermaidFullscreenOpen",
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
diagram.before(frame);
|
|
87
|
+
toolbar.append(button);
|
|
88
|
+
viewport.append(diagram);
|
|
89
|
+
frame.append(viewport, toolbar);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
type FullscreenDialogOptions = {
|
|
94
|
+
dialogClass: string;
|
|
95
|
+
dialogLabel: string;
|
|
96
|
+
title: string;
|
|
97
|
+
closeLabel: string;
|
|
98
|
+
viewportClass: string;
|
|
99
|
+
openClass: string;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
function openFullscreenDialog(
|
|
103
|
+
source: HTMLElement,
|
|
104
|
+
opener: HTMLButtonElement,
|
|
105
|
+
options: FullscreenDialogOptions,
|
|
106
|
+
) {
|
|
43
107
|
activeDialog?.close();
|
|
44
108
|
|
|
45
109
|
const dialog = document.createElement("dialog");
|
|
46
|
-
dialog.className =
|
|
47
|
-
dialog.setAttribute("aria-label",
|
|
110
|
+
dialog.className = options.dialogClass;
|
|
111
|
+
dialog.setAttribute("aria-label", options.dialogLabel);
|
|
48
112
|
const content = document.createElement("div");
|
|
49
113
|
content.className = "tableFullscreenContent";
|
|
50
114
|
const header = document.createElement("header");
|
|
51
115
|
header.className = "tableFullscreenHeader";
|
|
52
116
|
const title = document.createElement("strong");
|
|
53
|
-
title.textContent =
|
|
54
|
-
table.querySelector("caption")?.textContent?.trim() || "Table";
|
|
117
|
+
title.textContent = options.title;
|
|
55
118
|
const closeButton = document.createElement("button");
|
|
56
119
|
closeButton.type = "button";
|
|
57
120
|
closeButton.className = "tableFullscreenClose";
|
|
58
|
-
closeButton.title =
|
|
59
|
-
closeButton.setAttribute("aria-label",
|
|
121
|
+
closeButton.title = options.closeLabel;
|
|
122
|
+
closeButton.setAttribute("aria-label", options.closeLabel);
|
|
60
123
|
closeButton.innerHTML =
|
|
61
124
|
'<span class="ti ti-arrows-minimize" aria-hidden="true"></span>';
|
|
62
125
|
const viewport = document.createElement("div");
|
|
63
|
-
viewport.className =
|
|
64
|
-
viewport.append(
|
|
126
|
+
viewport.className = options.viewportClass;
|
|
127
|
+
viewport.append(source.cloneNode(true));
|
|
65
128
|
|
|
66
129
|
closeButton.addEventListener("click", () => dialog.close());
|
|
67
130
|
dialog.addEventListener("cancel", (event) => {
|
|
@@ -76,7 +139,7 @@ function openTableDialog(table: HTMLTableElement, opener: HTMLButtonElement) {
|
|
|
76
139
|
dialog.addEventListener(
|
|
77
140
|
"close",
|
|
78
141
|
() => {
|
|
79
|
-
document.documentElement.classList.remove(
|
|
142
|
+
document.documentElement.classList.remove(options.openClass);
|
|
80
143
|
dialog.remove();
|
|
81
144
|
if (activeDialog === dialog) {
|
|
82
145
|
activeDialog = undefined;
|
|
@@ -92,7 +155,7 @@ function openTableDialog(table: HTMLTableElement, opener: HTMLButtonElement) {
|
|
|
92
155
|
content.append(header, viewport);
|
|
93
156
|
dialog.append(content);
|
|
94
157
|
document.body.append(dialog);
|
|
95
|
-
document.documentElement.classList.add(
|
|
158
|
+
document.documentElement.classList.add(options.openClass);
|
|
96
159
|
activeDialog = dialog;
|
|
97
160
|
dialog.showModal();
|
|
98
161
|
}
|
package/package.json
CHANGED