@the-forge-flow/visual-explainer-pi 0.1.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/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +238 -0
- package/dist/templates/architecture.d.ts +33 -0
- package/dist/templates/architecture.d.ts.map +1 -0
- package/dist/templates/architecture.js +292 -0
- package/dist/templates/data-table.d.ts +25 -0
- package/dist/templates/data-table.d.ts.map +1 -0
- package/dist/templates/data-table.js +255 -0
- package/dist/templates/mermaid.d.ts +11 -0
- package/dist/templates/mermaid.d.ts.map +1 -0
- package/dist/templates/mermaid.js +149 -0
- package/dist/templates/shared.d.ts +17 -0
- package/dist/templates/shared.d.ts.map +1 -0
- package/dist/templates/shared.js +663 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/utils/browser-open.d.ts +6 -0
- package/dist/utils/browser-open.d.ts.map +1 -0
- package/dist/utils/browser-open.js +33 -0
- package/dist/utils/file-writer.d.ts +8 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +40 -0
- package/dist/utils/validators.d.ts +11 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +93 -0
- package/package.json +73 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mermaid template for flowcharts, sequence diagrams, ER diagrams, etc.
|
|
3
|
+
* Based on nicobailon/visual-explainer mermaid-flowchart.html
|
|
4
|
+
*/
|
|
5
|
+
import { FONT_PAIRINGS, MERMAID_SHELL_CSS, MERMAID_SHELL_JS, PALETTES, escapeHtml, generateCSSVariables, generateHtmlShell, } from "./shared.js";
|
|
6
|
+
export function generateMermaidTemplate(title, content, aesthetic, isDark) {
|
|
7
|
+
const palette = isDark ? PALETTES[aesthetic].dark : PALETTES[aesthetic].light;
|
|
8
|
+
const fonts = FONT_PAIRINGS[aesthetic];
|
|
9
|
+
const cssVars = generateCSSVariables(palette, fonts, isDark);
|
|
10
|
+
const mermaidTheme = generateMermaidThemeVariables(palette);
|
|
11
|
+
const bodyContent = generateBody(title, content);
|
|
12
|
+
return generateHtmlShell(title, bodyContent, aesthetic, cssVars, `${MERMAID_SHELL_CSS}${getExtraCSS()}`, getMermaidScript(mermaidTheme, content.mermaidSyntax));
|
|
13
|
+
}
|
|
14
|
+
function generateMermaidThemeVariables(palette) {
|
|
15
|
+
// Convert palette to Mermaid themeVariables format
|
|
16
|
+
return `
|
|
17
|
+
theme: 'base',
|
|
18
|
+
themeVariables: {
|
|
19
|
+
primaryColor: '${palette.surface}',
|
|
20
|
+
primaryTextColor: '${palette.text}',
|
|
21
|
+
primaryBorderColor: '${palette.accent}',
|
|
22
|
+
lineColor: '${palette.textDim}',
|
|
23
|
+
secondaryColor: '${palette.surface2}',
|
|
24
|
+
tertiaryColor: '${palette.surfaceElevated}',
|
|
25
|
+
fontFamily: 'var(--font-mono)',
|
|
26
|
+
fontSize: '14px'
|
|
27
|
+
},
|
|
28
|
+
flowchart: {
|
|
29
|
+
useMaxWidth: true,
|
|
30
|
+
htmlLabels: true,
|
|
31
|
+
curve: 'basis'
|
|
32
|
+
},
|
|
33
|
+
sequence: {
|
|
34
|
+
useMaxWidth: true,
|
|
35
|
+
diagramMarginX: 50,
|
|
36
|
+
diagramMarginY: 10
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
function generateBody(title, content) {
|
|
41
|
+
const captionHtml = content.caption
|
|
42
|
+
? `<p class="caption">${escapeHtml(content.caption)}</p>`
|
|
43
|
+
: "";
|
|
44
|
+
return `
|
|
45
|
+
<div class="container">
|
|
46
|
+
<h1>${escapeHtml(title)}</h1>
|
|
47
|
+
<div class="diagram-shell" style="--i:0">
|
|
48
|
+
<div class="mermaid-wrap">
|
|
49
|
+
<div class="zoom-controls">
|
|
50
|
+
<button class="zoom-btn" data-zoom="in" title="Zoom in">+</button>
|
|
51
|
+
<button class="zoom-btn" data-zoom="out" title="Zoom out">−</button>
|
|
52
|
+
<button class="zoom-btn" data-zoom="reset" title="Reset">⟲</button>
|
|
53
|
+
<button class="zoom-btn" data-zoom="expand" title="Open in new tab">⛶</button>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="mermaid-viewport">
|
|
56
|
+
<div class="mermaid-canvas">
|
|
57
|
+
<pre class="mermaid">${content.mermaidSyntax}</pre>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
${captionHtml}
|
|
63
|
+
</div>
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
function getExtraCSS() {
|
|
67
|
+
return `
|
|
68
|
+
body {
|
|
69
|
+
background: var(--bg);
|
|
70
|
+
color: var(--text);
|
|
71
|
+
font-family: var(--font-body);
|
|
72
|
+
padding: 40px;
|
|
73
|
+
min-height: 100vh;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.container {
|
|
77
|
+
max-width: 1200px;
|
|
78
|
+
margin: 0 auto;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
h1 {
|
|
82
|
+
font-size: 32px;
|
|
83
|
+
font-weight: 700;
|
|
84
|
+
letter-spacing: -0.5px;
|
|
85
|
+
margin-bottom: 24px;
|
|
86
|
+
text-wrap: balance;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.caption {
|
|
90
|
+
color: var(--text-dim);
|
|
91
|
+
font-size: 14px;
|
|
92
|
+
margin-top: 16px;
|
|
93
|
+
text-align: center;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Mermaid overrides for theming */
|
|
97
|
+
.mermaid .node rect,
|
|
98
|
+
.mermaid .node circle,
|
|
99
|
+
.mermaid .node ellipse,
|
|
100
|
+
.mermaid .node polygon {
|
|
101
|
+
fill: var(--surface) !important;
|
|
102
|
+
stroke: var(--accent) !important;
|
|
103
|
+
stroke-width: 2px !important;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.mermaid .node .label {
|
|
107
|
+
color: var(--text) !important;
|
|
108
|
+
font-family: var(--font-mono) !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.mermaid .edgePath .path {
|
|
112
|
+
stroke: var(--text-dim) !important;
|
|
113
|
+
stroke-width: 2px !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.mermaid .edgeLabel {
|
|
117
|
+
background: var(--surface) !important;
|
|
118
|
+
color: var(--text) !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Responsive */
|
|
122
|
+
@media (max-width: 768px) {
|
|
123
|
+
body { padding: 20px; }
|
|
124
|
+
h1 { font-size: 24px; }
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
function getMermaidScript(themeConfig, mermaidSyntax) {
|
|
129
|
+
return `
|
|
130
|
+
<script type="module">
|
|
131
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
|
132
|
+
|
|
133
|
+
mermaid.initialize({
|
|
134
|
+
startOnLoad: true,
|
|
135
|
+
securityLevel: 'loose',
|
|
136
|
+
${themeConfig}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
${MERMAID_SHELL_JS}
|
|
140
|
+
|
|
141
|
+
// Initialize controls after Mermaid renders
|
|
142
|
+
setTimeout(() => {
|
|
143
|
+
document.querySelectorAll('.mermaid-wrap').forEach(wrap => {
|
|
144
|
+
initMermaidControls(wrap);
|
|
145
|
+
});
|
|
146
|
+
}, 500);
|
|
147
|
+
</script>
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CSS variables, animations, and utilities for all templates
|
|
3
|
+
* Based on nicobailon/visual-explainer design system
|
|
4
|
+
*/
|
|
5
|
+
import type { Aesthetic, FontPairing, Palette } from "../types.js";
|
|
6
|
+
export declare const FONT_PAIRINGS: Record<Aesthetic, FontPairing>;
|
|
7
|
+
export declare const PALETTES: Record<Aesthetic, {
|
|
8
|
+
light: Palette;
|
|
9
|
+
dark: Palette;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const SHARED_CSS = "\n/* Reset */\n* { margin: 0; padding: 0; box-sizing: border-box; }\n\n/* Animation keyframes */\n@keyframes fadeUp {\n from { opacity: 0; transform: translateY(12px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes fadeScale {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n animation-duration: 0.01ms !important;\n animation-delay: 0ms !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* Base styles */\nbody {\n min-height: 100vh;\n line-height: 1.6;\n}\n\n/* Section card base */\n.section {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 20px 24px;\n animation: fadeUp 0.4s ease-out both;\n animation-delay: calc(var(--i, 0) * 0.06s);\n}\n\n.section--hero {\n background: var(--surface-elevated);\n border-color: color-mix(in srgb, var(--border) 50%, var(--accent) 50%);\n box-shadow: 0 4px 20px rgba(0,0,0,0.06);\n padding: 28px 32px;\n}\n\n.section--recessed {\n background: var(--surface2);\n box-shadow: inset 0 1px 3px rgba(0,0,0,0.04);\n}\n\n/* Section labels with dot indicators */\n.section-label {\n font-family: var(--font-mono);\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 1.5px;\n margin-bottom: 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-label .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n}\n\n/* Flow arrows */\n.flow-arrow {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 8px;\n color: var(--text-dim);\n font-family: var(--font-mono);\n font-size: 12px;\n padding: 4px 0;\n animation: fadeUp 0.4s ease-out both;\n animation-delay: calc(var(--i, 0) * 0.06s);\n}\n\n.flow-arrow svg {\n width: 20px;\n height: 20px;\n fill: none;\n stroke: var(--border-bright);\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n/* Code styling */\ncode {\n font-family: var(--font-mono);\n font-size: 0.9em;\n background: var(--accent-dim);\n color: var(--accent);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n body { padding: 20px; }\n .section { padding: 16px 20px; }\n .section--hero { padding: 20px 24px; }\n}\n";
|
|
12
|
+
export declare const MERMAID_SHELL_CSS = "\n.diagram-shell {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.mermaid-wrap {\n position: relative;\n display: flex;\n justify-content: center;\n padding: 24px;\n}\n\n.mermaid-viewport {\n overflow: hidden;\n cursor: grab;\n}\n\n.mermaid-viewport:active {\n cursor: grabbing;\n}\n\n.mermaid-canvas {\n transform-origin: center center;\n transition: transform 0.1s ease-out;\n}\n\n.zoom-controls {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 6px;\n z-index: 10;\n}\n\n.zoom-btn {\n width: 32px;\n height: 32px;\n border: 1px solid var(--border);\n border-radius: 6px;\n background: var(--surface);\n color: var(--text);\n font-size: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n}\n\n.zoom-btn:hover {\n background: var(--surface2);\n border-color: var(--border-bright);\n}\n";
|
|
13
|
+
export declare const MERMAID_SHELL_JS = "\nfunction initMermaidControls(wrap) {\n const viewport = wrap.querySelector('.mermaid-viewport');\n const canvas = wrap.querySelector('.mermaid-canvas');\n let scale = 1;\n let isDragging = false;\n let startX, startY, translateX = 0, translateY = 0;\n\n function updateTransform() {\n canvas.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`;\n }\n\n wrap.querySelector('[data-zoom=\"in\"]').onclick = () => { scale *= 1.2; updateTransform(); };\n wrap.querySelector('[data-zoom=\"out\"]').onclick = () => { scale /= 1.2; updateTransform(); };\n wrap.querySelector('[data-zoom=\"reset\"]').onclick = () => { scale = 1; translateX = 0; translateY = 0; updateTransform(); };\n wrap.querySelector('[data-zoom=\"expand\"]').onclick = () => openMermaidInNewTab(wrap);\n\n viewport.addEventListener('mousedown', (e) => {\n isDragging = true;\n startX = e.clientX - translateX;\n startY = e.clientY - translateY;\n viewport.style.cursor = 'grabbing';\n });\n\n window.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n translateX = e.clientX - startX;\n translateY = e.clientY - startY;\n updateTransform();\n });\n\n window.addEventListener('mouseup', () => {\n isDragging = false;\n viewport.style.cursor = 'grab';\n });\n\n viewport.addEventListener('wheel', (e) => {\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n scale *= e.deltaY > 0 ? 0.9 : 1.1;\n updateTransform();\n }\n }, { passive: false });\n}\n\nfunction openMermaidInNewTab(wrap) {\n const svg = wrap.querySelector('svg');\n if (!svg) return;\n const blob = new Blob([svg.outerHTML], { type: 'image/svg+xml' });\n const url = URL.createObjectURL(blob);\n window.open(url, '_blank');\n}\n";
|
|
14
|
+
export declare function generateCSSVariables(palette: Palette, fonts: FontPairing, isDark: boolean): string;
|
|
15
|
+
export declare function generateHtmlShell(title: string, bodyContent: string, aesthetic: string, cssVariables: string, extraHead?: string, extraScripts?: string): string;
|
|
16
|
+
export declare function escapeHtml(str: string): string;
|
|
17
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/templates/shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGnE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,CAiCxD,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAiVzE,CAAC;AAGF,eAAO,MAAM,UAAU,63EAgHtB,CAAC;AAGF,eAAO,MAAM,iBAAiB,w9BAyD7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,0vDAoD5B,CAAC;AAGF,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,OAAO,GACb,MAAM,CA0BR;AAGD,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,SAAS,SAAK,EACd,YAAY,SAAK,GACf,MAAM,CAqBR;AAGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C"}
|