@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.
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Architecture template - CSS Grid card layout for text-heavy system overviews
3
+ * Based on nicobailon/visual-explainer architecture.html
4
+ */
5
+ import { FONT_PAIRINGS, PALETTES, SHARED_CSS, escapeHtml, generateCSSVariables, generateHtmlShell, } from "./shared.js";
6
+ export function generateArchitectureTemplate(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 bodyContent = generateBody(title, content, palette);
11
+ return generateHtmlShell(title, bodyContent, aesthetic, cssVars, getExtraCSS());
12
+ }
13
+ function generateBody(title, content, palette) {
14
+ let html = `
15
+ <div class="diagram">
16
+ <h1>${escapeHtml(title)}</h1>
17
+ <p class="subtitle">Architecture Overview</p>
18
+ `;
19
+ let index = 0;
20
+ // Render sections with flow arrows
21
+ for (const section of content.sections) {
22
+ const colorClass = section.labelColor ? `section--${section.labelColor}` : "";
23
+ const depthClass = section.isHero
24
+ ? "section--hero"
25
+ : section.isRecessed
26
+ ? "section--recessed"
27
+ : "";
28
+ const dotColor = section.labelColor ? `var(--${section.labelColor})` : "var(--text-dim)";
29
+ html += `
30
+ <div class="section ${colorClass} ${depthClass}" style="--i:${index++}">
31
+ <div class="section-label"><span class="dot" style="background:${dotColor}"></span> ${escapeHtml(section.label)}</div>
32
+ ${section.content}
33
+ </div>
34
+ `;
35
+ // Add flow arrow if specified
36
+ const arrow = content.flowArrows?.[index - 1];
37
+ if (arrow) {
38
+ html += `
39
+ <div class="flow-arrow" style="--i:${index++}">
40
+ <svg viewBox="0 0 20 20"><path d="M10 4 L10 16 M6 12 L10 16 L14 12"/></svg>
41
+ ${escapeHtml(arrow.label)}
42
+ </div>
43
+ `;
44
+ }
45
+ }
46
+ // Three column row if specified
47
+ if (content.threeColumn && content.threeColumn.length > 0) {
48
+ html += ` <div class="three-col">\n`;
49
+ for (const col of content.threeColumn) {
50
+ const colorClass = col.labelColor ? `section--${col.labelColor}` : "";
51
+ const dotColor = col.labelColor ? `var(--${col.labelColor})` : "var(--text-dim)";
52
+ html += `
53
+ <div class="section ${colorClass}" style="--i:${index++}">
54
+ <div class="section-label"><span class="dot" style="background:${dotColor}"></span> ${escapeHtml(col.label)}</div>
55
+ ${col.content}
56
+ </div>
57
+ `;
58
+ }
59
+ html += " </div>\n";
60
+ }
61
+ html += "</div>";
62
+ return html;
63
+ }
64
+ function getExtraCSS() {
65
+ return `
66
+ ${SHARED_CSS}
67
+
68
+ body {
69
+ background: var(--bg);
70
+ background-image:
71
+ radial-gradient(ellipse at 20% 0%, var(--accent-dim) 0%, transparent 50%),
72
+ radial-gradient(ellipse at 80% 100%, var(--green-dim) 0%, transparent 40%);
73
+ color: var(--text);
74
+ font-family: var(--font-body);
75
+ padding: 40px;
76
+ }
77
+
78
+ h1 {
79
+ font-size: 38px;
80
+ font-weight: 700;
81
+ letter-spacing: -1px;
82
+ margin-bottom: 6px;
83
+ text-wrap: balance;
84
+ }
85
+
86
+ .subtitle {
87
+ color: var(--text-dim);
88
+ font-size: 14px;
89
+ margin-bottom: 40px;
90
+ font-family: var(--font-mono);
91
+ }
92
+
93
+ .diagram {
94
+ display: grid;
95
+ grid-template-columns: 1fr;
96
+ gap: 24px;
97
+ max-width: 1100px;
98
+ margin: 0 auto;
99
+ }
100
+
101
+ /* Color variants */
102
+ .section--accent { border-color: var(--accent-dim); }
103
+ .section--accent .section-label { color: var(--accent); }
104
+ .section--accent .section-label .dot { background: var(--accent) !important; }
105
+
106
+ .section--green { border-color: var(--green-dim); }
107
+ .section--green .section-label { color: var(--green); }
108
+ .section--green .section-label .dot { background: var(--green) !important; }
109
+
110
+ .section--orange { border-color: var(--orange-dim); }
111
+ .section--orange .section-label { color: var(--orange); }
112
+ .section--orange .section-label .dot { background: var(--orange) !important; }
113
+
114
+ .section--teal { border-color: var(--teal-dim); }
115
+ .section--teal .section-label { color: var(--teal); }
116
+ .section--teal .section-label .dot { background: var(--teal) !important; }
117
+
118
+ .section--plum { border-color: var(--plum-dim); }
119
+ .section--plum .section-label { color: var(--plum); }
120
+ .section--plum .section-label .dot { background: var(--plum) !important; }
121
+
122
+ /* Inner grid for sub-cards */
123
+ .inner-grid {
124
+ display: grid;
125
+ grid-template-columns: 1fr 1fr;
126
+ gap: 12px;
127
+ }
128
+
129
+ .inner-card {
130
+ background: var(--surface2);
131
+ border: 1px solid var(--border);
132
+ border-radius: 8px;
133
+ padding: 12px 16px;
134
+ }
135
+
136
+ .inner-card .title {
137
+ font-weight: 600;
138
+ font-size: 13px;
139
+ margin-bottom: 4px;
140
+ }
141
+
142
+ .inner-card .desc {
143
+ color: var(--text-dim);
144
+ font-size: 12px;
145
+ line-height: 1.5;
146
+ }
147
+
148
+ /* Three column layout */
149
+ .three-col {
150
+ display: grid;
151
+ grid-template-columns: 1fr 1fr 1fr;
152
+ gap: 16px;
153
+ }
154
+
155
+ /* Node lists */
156
+ .node-list {
157
+ list-style: none;
158
+ font-size: 12px;
159
+ line-height: 1.8;
160
+ }
161
+
162
+ .node-list li {
163
+ padding-left: 14px;
164
+ position: relative;
165
+ }
166
+
167
+ .node-list li::before {
168
+ content: '›';
169
+ color: var(--text-dim);
170
+ font-weight: 600;
171
+ position: absolute;
172
+ left: 0;
173
+ }
174
+
175
+ /* Pipeline */
176
+ .pipeline {
177
+ display: flex;
178
+ gap: 0;
179
+ align-items: stretch;
180
+ overflow-x: auto;
181
+ padding-bottom: 4px;
182
+ }
183
+
184
+ .pipeline-step {
185
+ background: var(--surface);
186
+ border: 1px solid var(--border);
187
+ border-radius: 8px;
188
+ padding: 10px 12px;
189
+ min-width: 120px;
190
+ flex-shrink: 0;
191
+ text-align: center;
192
+ }
193
+
194
+ .pipeline-step .step-num {
195
+ font-family: var(--font-mono);
196
+ font-size: 10px;
197
+ font-weight: 600;
198
+ margin-bottom: 4px;
199
+ }
200
+
201
+ .pipeline-step .step-name {
202
+ font-size: 12px;
203
+ font-weight: 600;
204
+ margin-bottom: 3px;
205
+ }
206
+
207
+ .pipeline-step .step-detail {
208
+ font-size: 10px;
209
+ color: var(--text-dim);
210
+ line-height: 1.4;
211
+ }
212
+
213
+ .pipeline-arrow {
214
+ display: flex;
215
+ align-items: center;
216
+ padding: 0 2px;
217
+ color: var(--border-bright);
218
+ font-size: 16px;
219
+ flex-shrink: 0;
220
+ }
221
+
222
+ /* Legend */
223
+ .legend {
224
+ display: flex;
225
+ gap: 20px;
226
+ flex-wrap: wrap;
227
+ margin-bottom: 14px;
228
+ }
229
+
230
+ .legend-item {
231
+ display: flex;
232
+ align-items: center;
233
+ gap: 6px;
234
+ font-size: 11px;
235
+ color: var(--text-dim);
236
+ font-family: var(--font-mono);
237
+ }
238
+
239
+ .legend-swatch {
240
+ width: 12px;
241
+ height: 12px;
242
+ border-radius: 3px;
243
+ }
244
+
245
+ /* Sources */
246
+ .sources {
247
+ display: flex;
248
+ gap: 12px;
249
+ flex-wrap: wrap;
250
+ justify-content: center;
251
+ }
252
+
253
+ .source {
254
+ background: var(--surface2);
255
+ border: 1px solid var(--border);
256
+ border-radius: 8px;
257
+ padding: 10px 18px;
258
+ font-family: var(--font-mono);
259
+ font-size: 13px;
260
+ font-weight: 500;
261
+ display: flex;
262
+ align-items: center;
263
+ gap: 8px;
264
+ transition: border-color 0.2s;
265
+ }
266
+
267
+ .source:hover { border-color: var(--border-bright); }
268
+
269
+ /* Callout */
270
+ .callout {
271
+ background: var(--surface2);
272
+ border: 1px solid var(--border);
273
+ border-left: 3px solid var(--accent);
274
+ border-radius: 0 8px 8px 0;
275
+ padding: 14px 18px;
276
+ font-size: 13px;
277
+ line-height: 1.6;
278
+ color: var(--text-dim);
279
+ }
280
+
281
+ .callout strong { color: var(--text); font-weight: 600; }
282
+
283
+ /* Responsive */
284
+ @media (max-width: 768px) {
285
+ body { padding: 20px; }
286
+ .inner-grid { grid-template-columns: 1fr; }
287
+ .three-col { grid-template-columns: 1fr; }
288
+ .pipeline { flex-wrap: wrap; gap: 6px; }
289
+ .pipeline-arrow { display: none; }
290
+ }
291
+ `;
292
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Data table template for structured data display
3
+ * Based on nicobailon/visual-explainer data-table.html
4
+ */
5
+ import type { Aesthetic } from "../types.js";
6
+ export interface TableColumn {
7
+ key: string;
8
+ header: string;
9
+ width?: string;
10
+ align?: "left" | "center" | "right";
11
+ }
12
+ export interface TableRow {
13
+ [key: string]: string | {
14
+ value: string;
15
+ status?: "success" | "warning" | "error" | "neutral";
16
+ };
17
+ }
18
+ export interface TableContent {
19
+ columns: TableColumn[];
20
+ rows: TableRow[];
21
+ caption?: string;
22
+ stickyHeader?: boolean;
23
+ }
24
+ export declare function generateTableTemplate(title: string, content: TableContent, aesthetic: Aesthetic, isDark: boolean): string;
25
+ //# sourceMappingURL=data-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/templates/data-table.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,MAAM,WAAW,WAAW;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,QAAQ;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;KAAE,CAAC;CAChG;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,OAAO,GACb,MAAM,CAQR"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Data table template for structured data display
3
+ * Based on nicobailon/visual-explainer data-table.html
4
+ */
5
+ import { FONT_PAIRINGS, PALETTES, escapeHtml, generateCSSVariables, generateHtmlShell, } from "./shared.js";
6
+ export function generateTableTemplate(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 bodyContent = generateBody(title, content);
11
+ return generateHtmlShell(title, bodyContent, aesthetic, cssVars, getExtraCSS());
12
+ }
13
+ function generateBody(title, content) {
14
+ const colgroup = content.columns
15
+ .map((col) => `<col${col.width ? ` style="width:${col.width}"` : ""}>`)
16
+ .join("");
17
+ const thead = content.columns
18
+ .map((col) => {
19
+ const align = col.align ? ` align="${col.align}"` : "";
20
+ return `<th${align}>${escapeHtml(col.header)}</th>`;
21
+ })
22
+ .join("");
23
+ const tbody = content.rows
24
+ .map((row, i) => {
25
+ const cells = content.columns
26
+ .map((col) => {
27
+ const cellData = row[col.key];
28
+ let value;
29
+ let statusClass = "";
30
+ if (typeof cellData === "object" && cellData !== null) {
31
+ value = cellData.value;
32
+ if (cellData.status) {
33
+ statusClass = ` status-${cellData.status}`;
34
+ }
35
+ }
36
+ else {
37
+ value = String(cellData ?? "");
38
+ }
39
+ const align = col.align ? ` align="${col.align}"` : "";
40
+ return `<td class="cell${statusClass}"${align}>${formatCellValue(value)}</td>`;
41
+ })
42
+ .join("");
43
+ return `<tr style="--i:${i}">${cells}</tr>`;
44
+ })
45
+ .join("");
46
+ const captionHtml = content.caption
47
+ ? `<p class="caption">${escapeHtml(content.caption)}</p>`
48
+ : "";
49
+ return `
50
+ <div class="container">
51
+ <h1>${escapeHtml(title)}</h1>
52
+ <div class="table-wrap" style="--i:0">
53
+ <table${content.stickyHeader ? ' class="sticky-header"' : ""}>
54
+ <colgroup>${colgroup}</colgroup>
55
+ <thead>
56
+ <tr>${thead}</tr>
57
+ </thead>
58
+ <tbody>
59
+ ${tbody}
60
+ </tbody>
61
+ </table>
62
+ </div>
63
+ ${captionHtml}
64
+ </div>
65
+ `;
66
+ }
67
+ function formatCellValue(value) {
68
+ // Check if value contains code-like content (backticks)
69
+ if (value.includes("`")) {
70
+ return value.replace(/`([^`]+)`/g, "<code>$1</code>");
71
+ }
72
+ return escapeHtml(value);
73
+ }
74
+ function getExtraCSS() {
75
+ return `
76
+ body {
77
+ background: var(--bg);
78
+ color: var(--text);
79
+ font-family: var(--font-body);
80
+ padding: 40px;
81
+ min-height: 100vh;
82
+ }
83
+
84
+ .container {
85
+ max-width: 1200px;
86
+ margin: 0 auto;
87
+ }
88
+
89
+ h1 {
90
+ font-size: 32px;
91
+ font-weight: 700;
92
+ letter-spacing: -0.5px;
93
+ margin-bottom: 24px;
94
+ text-wrap: balance;
95
+ }
96
+
97
+ .caption {
98
+ color: var(--text-dim);
99
+ font-size: 14px;
100
+ margin-top: 16px;
101
+ text-align: center;
102
+ }
103
+
104
+ .table-wrap {
105
+ background: var(--surface);
106
+ border: 1px solid var(--border);
107
+ border-radius: 12px;
108
+ overflow-x: auto;
109
+ animation: fadeUp 0.4s ease-out both;
110
+ }
111
+
112
+ table {
113
+ width: 100%;
114
+ border-collapse: collapse;
115
+ font-size: 14px;
116
+ }
117
+
118
+ /* Header */
119
+ thead {
120
+ background: var(--surface2);
121
+ }
122
+
123
+ th {
124
+ padding: 14px 16px;
125
+ text-align: left;
126
+ font-weight: 600;
127
+ font-size: 12px;
128
+ text-transform: uppercase;
129
+ letter-spacing: 0.5px;
130
+ color: var(--text-dim);
131
+ border-bottom: 1px solid var(--border);
132
+ white-space: nowrap;
133
+ }
134
+
135
+ th[align="center"] { text-align: center; }
136
+ th[align="right"] { text-align: right; font-variant-numeric: tabular-nums; }
137
+
138
+ /* Body */
139
+ tbody tr {
140
+ animation: fadeUp 0.4s ease-out both;
141
+ animation-delay: calc(var(--i, 0) * 0.04s);
142
+ }
143
+
144
+ tbody tr:nth-child(even) {
145
+ background: var(--surface2);
146
+ }
147
+
148
+ tbody tr:hover {
149
+ background: var(--surface-elevated);
150
+ }
151
+
152
+ td {
153
+ padding: 12px 16px;
154
+ border-bottom: 1px solid var(--border);
155
+ vertical-align: top;
156
+ }
157
+
158
+ td[align="center"] { text-align: center; }
159
+ td[align="right"] { text-align: right; font-variant-numeric: tabular-nums; }
160
+
161
+ /* Cell content */
162
+ .cell {
163
+ line-height: 1.5;
164
+ }
165
+
166
+ .cell code {
167
+ font-family: var(--font-mono);
168
+ font-size: 12px;
169
+ background: var(--accent-dim);
170
+ color: var(--accent);
171
+ padding: 2px 6px;
172
+ border-radius: 4px;
173
+ white-space: nowrap;
174
+ }
175
+
176
+ /* Status indicators */
177
+ .status-success {
178
+ color: var(--green);
179
+ font-weight: 500;
180
+ }
181
+
182
+ .status-success::before {
183
+ content: '';
184
+ display: inline-block;
185
+ width: 8px;
186
+ height: 8px;
187
+ border-radius: 50%;
188
+ background: var(--green);
189
+ margin-right: 6px;
190
+ }
191
+
192
+ .status-warning {
193
+ color: var(--orange);
194
+ font-weight: 500;
195
+ }
196
+
197
+ .status-warning::before {
198
+ content: '';
199
+ display: inline-block;
200
+ width: 8px;
201
+ height: 8px;
202
+ border-radius: 50%;
203
+ background: var(--orange);
204
+ margin-right: 6px;
205
+ }
206
+
207
+ .status-error {
208
+ color: var(--plum);
209
+ font-weight: 500;
210
+ }
211
+
212
+ .status-error::before {
213
+ content: '';
214
+ display: inline-block;
215
+ width: 8px;
216
+ height: 8px;
217
+ border-radius: 50%;
218
+ background: var(--plum);
219
+ margin-right: 6px;
220
+ }
221
+
222
+ .status-neutral {
223
+ color: var(--text-dim);
224
+ }
225
+
226
+ /* Sticky header */
227
+ table.sticky-header thead {
228
+ position: sticky;
229
+ top: 0;
230
+ z-index: 10;
231
+ }
232
+
233
+ /* Animation */
234
+ @keyframes fadeUp {
235
+ from { opacity: 0; transform: translateY(8px); }
236
+ to { opacity: 1; transform: translateY(0); }
237
+ }
238
+
239
+ /* Reduced motion */
240
+ @media (prefers-reduced-motion: reduce) {
241
+ *, *::before, *::after {
242
+ animation-duration: 0.01ms !important;
243
+ animation-delay: 0ms !important;
244
+ transition-duration: 0.01ms !important;
245
+ }
246
+ }
247
+
248
+ /* Responsive */
249
+ @media (max-width: 768px) {
250
+ body { padding: 20px; }
251
+ h1 { font-size: 24px; }
252
+ th, td { padding: 10px 12px; font-size: 13px; }
253
+ }
254
+ `;
255
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Mermaid template for flowcharts, sequence diagrams, ER diagrams, etc.
3
+ * Based on nicobailon/visual-explainer mermaid-flowchart.html
4
+ */
5
+ import type { Aesthetic } from "../types.js";
6
+ export interface MermaidContent {
7
+ mermaidSyntax: string;
8
+ caption?: string;
9
+ }
10
+ export declare function generateMermaidTemplate(title: string, content: MermaidContent, aesthetic: Aesthetic, isDark: boolean): string;
11
+ //# sourceMappingURL=mermaid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../src/templates/mermaid.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAW7C,MAAM,WAAW,cAAc;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,OAAO,GACb,MAAM,CAgBR"}