@hugobatist/smartcode 0.1.0

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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +292 -0
  3. package/dist/cli.js +4324 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/index.d.ts +374 -0
  6. package/dist/index.js +1167 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/static/annotations-panel.js +133 -0
  9. package/dist/static/annotations-svg.js +108 -0
  10. package/dist/static/annotations.css +367 -0
  11. package/dist/static/annotations.js +367 -0
  12. package/dist/static/app-init.js +497 -0
  13. package/dist/static/breakpoints.css +69 -0
  14. package/dist/static/breakpoints.js +197 -0
  15. package/dist/static/clipboard.js +94 -0
  16. package/dist/static/collapse-ui.js +325 -0
  17. package/dist/static/command-history.js +89 -0
  18. package/dist/static/context-menu.js +334 -0
  19. package/dist/static/custom-renderer.js +201 -0
  20. package/dist/static/dagre-layout.js +291 -0
  21. package/dist/static/diagram-dom.js +241 -0
  22. package/dist/static/diagram-editor.js +368 -0
  23. package/dist/static/editor-panel.js +107 -0
  24. package/dist/static/editor-popovers.js +187 -0
  25. package/dist/static/event-bus.js +57 -0
  26. package/dist/static/export.js +181 -0
  27. package/dist/static/file-tree.js +470 -0
  28. package/dist/static/ghost-paths.js +397 -0
  29. package/dist/static/heatmap.css +116 -0
  30. package/dist/static/heatmap.js +308 -0
  31. package/dist/static/icons.js +66 -0
  32. package/dist/static/inline-edit.js +294 -0
  33. package/dist/static/interaction-state.js +155 -0
  34. package/dist/static/interaction-tracker.js +93 -0
  35. package/dist/static/live.html +239 -0
  36. package/dist/static/main-layout.css +220 -0
  37. package/dist/static/main.css +334 -0
  38. package/dist/static/mcp-sessions.js +202 -0
  39. package/dist/static/modal.css +109 -0
  40. package/dist/static/modal.js +171 -0
  41. package/dist/static/node-drag.js +293 -0
  42. package/dist/static/pan-zoom.js +199 -0
  43. package/dist/static/renderer.js +280 -0
  44. package/dist/static/search.css +103 -0
  45. package/dist/static/search.js +304 -0
  46. package/dist/static/selection.js +353 -0
  47. package/dist/static/session-player.css +137 -0
  48. package/dist/static/session-player.js +411 -0
  49. package/dist/static/sidebar.css +248 -0
  50. package/dist/static/svg-renderer.js +313 -0
  51. package/dist/static/svg-shapes.js +218 -0
  52. package/dist/static/tokens.css +76 -0
  53. package/dist/static/vendor/dagre-bundle.js +43 -0
  54. package/dist/static/vendor/dagre.min.js +3 -0
  55. package/dist/static/vendor/graphlib.min.js +2 -0
  56. package/dist/static/viewport-transform.js +107 -0
  57. package/dist/static/workspace-switcher.js +202 -0
  58. package/dist/static/ws-client.js +71 -0
  59. package/dist/static/ws-handler.js +125 -0
  60. package/package.json +74 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * SmartCode SVG Renderer -- assembles complete SVG DOM from a LayoutResult.
3
+ * Renders nodes (with shapes), edges (with arrows), and subgraphs.
4
+ *
5
+ * Dependencies: svg-shapes.js (SmartCodeSvgShapes)
6
+ * Dependents: (future) custom-renderer-bridge.js
7
+ *
8
+ * Usage:
9
+ * var svgEl = SmartCodeSvgRenderer.createSVG(layout);
10
+ * container.appendChild(svgEl);
11
+ */
12
+ (function() {
13
+ 'use strict';
14
+
15
+ var NS = 'http://www.w3.org/2000/svg';
16
+
17
+ // ── Theme constants (matching renderer.js MERMAID_CONFIG themeVariables) ──
18
+ var THEME = {
19
+ nodeFill: '#eff6ff',
20
+ nodeStroke: '#2563eb',
21
+ nodeStrokeWidth: '2',
22
+ nodeTextColor: '#18181b',
23
+ nodeFontSize: '15',
24
+ nodeFontWeight: '600',
25
+ nodeFontFamily: "'Inter', sans-serif",
26
+ edgeStroke: '#52525b',
27
+ edgeStrokeWidth: '1.5',
28
+ edgeLabelBg: '#ffffff',
29
+ edgeLabelColor: '#52525b',
30
+ edgeLabelFontSize: '13',
31
+ subgraphFill: '#f4f4f5',
32
+ subgraphStroke: '#a1a1aa',
33
+ subgraphStrokeWidth: '1',
34
+ subgraphLabelColor: '#18181b',
35
+ subgraphLabelFontSize: '14',
36
+ subgraphLabelFontWeight: '700'
37
+ };
38
+
39
+ function el(tag) { return document.createElementNS(NS, tag); }
40
+
41
+ function attrs(element, map) {
42
+ for (var key in map) {
43
+ if (map.hasOwnProperty(key)) element.setAttribute(key, String(map[key]));
44
+ }
45
+ return element;
46
+ }
47
+
48
+ // ── Arrow Markers ──
49
+ function createArrowMarkers(defs) {
50
+ var sizes = { 'arrow-normal': 8, 'arrow-thick': 10, 'arrow-dotted': 8 };
51
+ for (var id in sizes) {
52
+ if (!sizes.hasOwnProperty(id)) continue;
53
+ var marker = attrs(el('marker'), {
54
+ id: id, viewBox: '0 0 10 10', refX: 10, refY: 5,
55
+ markerWidth: sizes[id], markerHeight: sizes[id],
56
+ orient: 'auto-start-reverse'
57
+ });
58
+ var arrow = el('polygon');
59
+ arrow.setAttribute('points', '0 0, 10 5, 0 10');
60
+ arrow.setAttribute('fill', THEME.edgeStroke);
61
+ marker.appendChild(arrow);
62
+ defs.appendChild(marker);
63
+ }
64
+ }
65
+
66
+ // ── Edge path construction ──
67
+ function edgePointsToPath(points) {
68
+ if (!points || points.length === 0) return '';
69
+ // Filter out points with NaN coordinates (defensive against dagre bugs)
70
+ var valid = [];
71
+ for (var vi = 0; vi < points.length; vi++) {
72
+ if (isFinite(points[vi].x) && isFinite(points[vi].y)) {
73
+ valid.push(points[vi]);
74
+ }
75
+ }
76
+ if (valid.length === 0) return '';
77
+ var d = 'M ' + valid[0].x + ' ' + valid[0].y;
78
+ if (valid.length === 2) {
79
+ d += ' L ' + valid[1].x + ' ' + valid[1].y;
80
+ } else if (valid.length >= 3) {
81
+ var idx = 1;
82
+ while (idx + 2 < valid.length) {
83
+ d += ' C ' + valid[idx].x + ' ' + valid[idx].y
84
+ + ', ' + valid[idx + 1].x + ' ' + valid[idx + 1].y
85
+ + ', ' + valid[idx + 2].x + ' ' + valid[idx + 2].y;
86
+ idx += 3;
87
+ }
88
+ while (idx < valid.length) {
89
+ d += ' L ' + valid[idx].x + ' ' + valid[idx].y;
90
+ idx++;
91
+ }
92
+ }
93
+ return d;
94
+ }
95
+
96
+ // ── Helper: clamp endpoint to rectangle boundary ──
97
+ function clampToRect(from, cx, cy, hw, hh) {
98
+ var dx = cx - from.x;
99
+ var dy = cy - from.y;
100
+ if (dx === 0 && dy === 0) return { x: cx, y: cy - hh };
101
+ var absDx = Math.abs(dx);
102
+ var absDy = Math.abs(dy);
103
+ var t = (absDx * hh > absDy * hw) ? hw / absDx : hh / absDy;
104
+ return { x: cx - dx * t, y: cy - dy * t };
105
+ }
106
+
107
+ // ── Shorten path to node boundary ──
108
+ function shortenPathToNodeBoundary(points, targetNode) {
109
+ if (!points || points.length < 2 || !targetNode) return points;
110
+ var result = [];
111
+ for (var i = 0; i < points.length; i++) {
112
+ result.push({ x: points[i].x, y: points[i].y });
113
+ }
114
+ var prev = result[result.length - 2];
115
+ var dx = result[result.length - 1].x - prev.x;
116
+ var dy = result[result.length - 1].y - prev.y;
117
+ var dist = Math.sqrt(dx * dx + dy * dy);
118
+ if (dist === 0) return result;
119
+
120
+ var nx = targetNode.x, ny = targetNode.y;
121
+ var nw = targetNode.width / 2, nh = targetNode.height / 2;
122
+ var shape = targetNode.shape || 'rect';
123
+
124
+ if (shape === 'circle') {
125
+ var r = Math.max(targetNode.width, targetNode.height) / 2;
126
+ result[result.length - 1] = { x: nx - (dx / dist) * r, y: ny - (dy / dist) * r };
127
+ } else if (shape === 'diamond') {
128
+ result[result.length - 1] = clampToRect(prev, nx, ny, nw * 0.7, nh * 0.7);
129
+ } else {
130
+ result[result.length - 1] = clampToRect(prev, nx, ny, nw, nh);
131
+ }
132
+ return result;
133
+ }
134
+
135
+ // ── Render a single node ──
136
+ function renderNode(node) {
137
+ var g = el('g');
138
+ g.setAttribute('data-node-id', node.id);
139
+ g.setAttribute('class', 'smartcode-node');
140
+ var nx = isFinite(node.x) ? node.x : 0;
141
+ var ny = isFinite(node.y) ? node.y : 0;
142
+ g.setAttribute('transform', 'translate(' + nx + ',' + ny + ')');
143
+
144
+ var shapeEl = window.SmartCodeSvgShapes.render(node.shape, node.width, node.height);
145
+ attrs(shapeEl, { fill: THEME.nodeFill, stroke: THEME.nodeStroke, 'stroke-width': THEME.nodeStrokeWidth });
146
+
147
+ // For subroutine <g>, apply styles to child elements individually
148
+ if (node.shape === 'subroutine' && shapeEl.tagName === 'g') {
149
+ var children = shapeEl.childNodes;
150
+ for (var c = 0; c < children.length; c++) {
151
+ if (children[c].nodeType === 1) {
152
+ attrs(children[c], {
153
+ fill: children[c].tagName === 'rect' ? THEME.nodeFill : 'none',
154
+ stroke: THEME.nodeStroke, 'stroke-width': THEME.nodeStrokeWidth
155
+ });
156
+ }
157
+ }
158
+ }
159
+ g.appendChild(shapeEl);
160
+
161
+ var text = el('text');
162
+ attrs(text, {
163
+ 'text-anchor': 'middle',
164
+ fill: THEME.nodeTextColor, 'font-family': THEME.nodeFontFamily,
165
+ 'font-size': THEME.nodeFontSize, 'font-weight': THEME.nodeFontWeight
166
+ });
167
+ // Handle multiline labels: split on \n and use <tspan> per line
168
+ var labelStr = (node.label || '').replace(/\\n/g, '\n');
169
+ var lines = labelStr.split('\n');
170
+ var lineHeight = parseFloat(THEME.nodeFontSize) * 1.3;
171
+ var totalHeight = lines.length * lineHeight;
172
+ var startY = -(totalHeight - lineHeight) / 2;
173
+ for (var li = 0; li < lines.length; li++) {
174
+ var tspan = el('tspan');
175
+ tspan.setAttribute('x', '0');
176
+ tspan.setAttribute('dy', li === 0 ? String(startY) : String(lineHeight));
177
+ tspan.setAttribute('dominant-baseline', 'central');
178
+ tspan.textContent = lines[li];
179
+ text.appendChild(tspan);
180
+ }
181
+ g.appendChild(text);
182
+ return g;
183
+ }
184
+
185
+ // ── Edge type styling ──
186
+ function applyEdgeStyle(path, type) {
187
+ var base = { stroke: THEME.edgeStroke, fill: 'none' };
188
+ if (type === 'thick') {
189
+ attrs(path, { stroke: base.stroke, 'stroke-width': '3', 'marker-end': 'url(#arrow-thick)', fill: 'none' });
190
+ } else if (type === 'dotted') {
191
+ attrs(path, { stroke: base.stroke, 'stroke-width': THEME.edgeStrokeWidth, 'stroke-dasharray': '5,5', 'marker-end': 'url(#arrow-normal)', fill: 'none' });
192
+ } else if (type === 'open') {
193
+ attrs(path, { stroke: base.stroke, 'stroke-width': THEME.edgeStrokeWidth, fill: 'none' });
194
+ } else if (type === 'invisible') {
195
+ attrs(path, { stroke: 'none', fill: 'none' });
196
+ } else {
197
+ // Default: arrow
198
+ attrs(path, { stroke: base.stroke, 'stroke-width': THEME.edgeStrokeWidth, 'marker-end': 'url(#arrow-normal)', fill: 'none' });
199
+ }
200
+ }
201
+
202
+ // ── Render a single edge ──
203
+ function renderEdge(edge, nodesMap) {
204
+ var g = el('g');
205
+ g.setAttribute('data-edge-id', edge.id);
206
+ g.setAttribute('class', 'smartcode-edge');
207
+
208
+ var targetNode = nodesMap[edge.to];
209
+ var points = targetNode ? shortenPathToNodeBoundary(edge.points, targetNode) : edge.points;
210
+
211
+ var path = el('path');
212
+ path.setAttribute('d', edgePointsToPath(points));
213
+ applyEdgeStyle(path, edge.type);
214
+ g.appendChild(path);
215
+
216
+ // Optional label at midpoint
217
+ if (edge.label) {
218
+ var midPt = points[Math.floor(points.length / 2)] || points[0];
219
+ var labelGroup = el('g');
220
+ labelGroup.setAttribute('transform', 'translate(' + midPt.x + ',' + midPt.y + ')');
221
+
222
+ var textLen = edge.label.length * 7 + 12;
223
+ labelGroup.appendChild(attrs(el('rect'), {
224
+ x: -textLen / 2, y: -10, width: textLen, height: 20,
225
+ rx: 4, fill: THEME.edgeLabelBg, stroke: 'none'
226
+ }));
227
+
228
+ var labelText = el('text');
229
+ attrs(labelText, {
230
+ 'text-anchor': 'middle', 'dominant-baseline': 'central',
231
+ fill: THEME.edgeLabelColor, 'font-family': THEME.nodeFontFamily,
232
+ 'font-size': THEME.edgeLabelFontSize
233
+ });
234
+ labelText.textContent = edge.label;
235
+ labelGroup.appendChild(labelText);
236
+ g.appendChild(labelGroup);
237
+ }
238
+ return g;
239
+ }
240
+
241
+ // ── Render a subgraph ──
242
+ function renderSubgraph(sg) {
243
+ var g = el('g');
244
+ g.setAttribute('data-subgraph-id', sg.id);
245
+ g.setAttribute('class', 'smartcode-subgraph');
246
+
247
+ // Guard against NaN/undefined positions from dagre compound layout
248
+ var sx = isFinite(sg.x) ? sg.x : 0;
249
+ var sy = isFinite(sg.y) ? sg.y : 0;
250
+ var sw = sg.width > 0 ? sg.width : 100;
251
+ var sh = sg.height > 0 ? sg.height : 60;
252
+
253
+ g.appendChild(attrs(el('rect'), {
254
+ x: sx - sw / 2, y: sy - sh / 2,
255
+ width: sw, height: sh, rx: 8,
256
+ fill: THEME.subgraphFill, stroke: THEME.subgraphStroke,
257
+ 'stroke-width': THEME.subgraphStrokeWidth
258
+ }));
259
+
260
+ var text = el('text');
261
+ attrs(text, {
262
+ x: sx, y: sy - sh / 2 + 20,
263
+ 'text-anchor': 'middle', 'dominant-baseline': 'central',
264
+ fill: THEME.subgraphLabelColor, 'font-family': THEME.nodeFontFamily,
265
+ 'font-size': THEME.subgraphLabelFontSize, 'font-weight': THEME.subgraphLabelFontWeight
266
+ });
267
+ text.textContent = sg.label;
268
+ g.appendChild(text);
269
+ return g;
270
+ }
271
+
272
+ // ── Main: create complete SVG from LayoutResult ──
273
+ function createSVG(layout) {
274
+ var svg = attrs(el('svg'), {
275
+ xmlns: NS,
276
+ width: '100%',
277
+ height: '100%',
278
+ viewBox: '0 0 ' + layout.width + ' ' + layout.height
279
+ });
280
+
281
+ var defs = el('defs');
282
+ createArrowMarkers(defs);
283
+ svg.appendChild(defs);
284
+
285
+ var root = el('g');
286
+ root.setAttribute('class', 'smartcode-diagram');
287
+
288
+ // Build nodes map for edge boundary calculations
289
+ var nodesMap = {};
290
+ for (var n = 0; n < layout.nodes.length; n++) {
291
+ nodesMap[layout.nodes[n].id] = layout.nodes[n];
292
+ }
293
+
294
+ // 1. Subgraphs first (behind everything)
295
+ for (var s = 0; s < layout.subgraphs.length; s++) {
296
+ root.appendChild(renderSubgraph(layout.subgraphs[s]));
297
+ }
298
+ // 2. Edges next (middle layer)
299
+ for (var e = 0; e < layout.edges.length; e++) {
300
+ root.appendChild(renderEdge(layout.edges[e], nodesMap));
301
+ }
302
+ // 3. Nodes last (on top)
303
+ for (var i = 0; i < layout.nodes.length; i++) {
304
+ root.appendChild(renderNode(layout.nodes[i]));
305
+ }
306
+
307
+ svg.appendChild(root);
308
+ return svg;
309
+ }
310
+
311
+ // ── Public API ──
312
+ window.SmartCodeSvgRenderer = { createSVG: createSVG };
313
+ })();
@@ -0,0 +1,218 @@
1
+ /**
2
+ * SmartCode SVG Shapes -- SVG element factories for all 13 Mermaid node shapes.
3
+ * Each shape function takes (w, h) and returns an SVG element centered at (0, 0).
4
+ *
5
+ * Dependencies: none (standalone)
6
+ * Dependents: svg-renderer.js (calls SmartCodeSvgShapes.render)
7
+ *
8
+ * Usage:
9
+ * var el = SmartCodeSvgShapes.render('diamond', 120, 60);
10
+ * // Returns an SVG element ready for translate(x,y) positioning
11
+ */
12
+ (function() {
13
+ 'use strict';
14
+
15
+ var NS = 'http://www.w3.org/2000/svg';
16
+
17
+ // ── Helper: create SVG element ──
18
+ function el(tag) {
19
+ return document.createElementNS(NS, tag);
20
+ }
21
+
22
+ // ── Helper: set multiple attributes ──
23
+ function attrs(element, map) {
24
+ for (var key in map) {
25
+ if (map.hasOwnProperty(key)) {
26
+ element.setAttribute(key, String(map[key]));
27
+ }
28
+ }
29
+ return element;
30
+ }
31
+
32
+ // ── Helper: polygon from points array ──
33
+ function polygon(points) {
34
+ var poly = el('polygon');
35
+ var str = '';
36
+ for (var i = 0; i < points.length; i++) {
37
+ if (i > 0) str += ' ';
38
+ str += points[i][0] + ',' + points[i][1];
39
+ }
40
+ poly.setAttribute('points', str);
41
+ return poly;
42
+ }
43
+
44
+ // ── Shape: rect ──
45
+ function rect(w, h) {
46
+ return attrs(el('rect'), {
47
+ x: -w / 2, y: -h / 2, width: w, height: h, rx: 0
48
+ });
49
+ }
50
+
51
+ // ── Shape: rounded ──
52
+ function rounded(w, h) {
53
+ return attrs(el('rect'), {
54
+ x: -w / 2, y: -h / 2, width: w, height: h, rx: 8
55
+ });
56
+ }
57
+
58
+ // ── Shape: stadium ──
59
+ function stadium(w, h) {
60
+ return attrs(el('rect'), {
61
+ x: -w / 2, y: -h / 2, width: w, height: h, rx: h / 2
62
+ });
63
+ }
64
+
65
+ // ── Shape: diamond ──
66
+ function diamond(w, h) {
67
+ return polygon([
68
+ [0, -h / 2],
69
+ [w / 2, 0],
70
+ [0, h / 2],
71
+ [-w / 2, 0]
72
+ ]);
73
+ }
74
+
75
+ // ── Shape: circle ──
76
+ function circle(w, h) {
77
+ var r = Math.max(w, h) / 2;
78
+ return attrs(el('circle'), { cx: 0, cy: 0, r: r });
79
+ }
80
+
81
+ // ── Shape: hexagon ──
82
+ function hexagon(w, h) {
83
+ var dx = h / 4;
84
+ return polygon([
85
+ [-w / 2 + dx, -h / 2],
86
+ [w / 2 - dx, -h / 2],
87
+ [w / 2, 0],
88
+ [w / 2 - dx, h / 2],
89
+ [-w / 2 + dx, h / 2],
90
+ [-w / 2, 0]
91
+ ]);
92
+ }
93
+
94
+ // ── Shape: subroutine ──
95
+ function subroutine(w, h) {
96
+ var g = el('g');
97
+ var mainRect = attrs(el('rect'), {
98
+ x: -w / 2, y: -h / 2, width: w, height: h, rx: 0
99
+ });
100
+ g.appendChild(mainRect);
101
+
102
+ // Left inner vertical line
103
+ var lineLeft = attrs(el('line'), {
104
+ x1: -w / 2 + 8, y1: -h / 2,
105
+ x2: -w / 2 + 8, y2: h / 2
106
+ });
107
+ g.appendChild(lineLeft);
108
+
109
+ // Right inner vertical line
110
+ var lineRight = attrs(el('line'), {
111
+ x1: w / 2 - 8, y1: -h / 2,
112
+ x2: w / 2 - 8, y2: h / 2
113
+ });
114
+ g.appendChild(lineRight);
115
+
116
+ return g;
117
+ }
118
+
119
+ // ── Shape: cylinder ──
120
+ function cylinder(w, h) {
121
+ var rx = w / 2;
122
+ var ry = 8; // ellipse vertical radius for cap
123
+ var bodyTop = -h / 2 + ry;
124
+ var bodyBottom = h / 2 - ry;
125
+
126
+ // Path: top ellipse, right side, bottom ellipse, left side, close with top back-arc
127
+ var d = 'M ' + (-rx) + ' ' + bodyTop
128
+ + ' A ' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + bodyTop
129
+ + ' L ' + rx + ' ' + bodyBottom
130
+ + ' A ' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' ' + bodyBottom
131
+ + ' L ' + (-rx) + ' ' + bodyTop
132
+ + ' A ' + rx + ' ' + ry + ' 0 0 0 ' + rx + ' ' + bodyTop;
133
+
134
+ return attrs(el('path'), { d: d });
135
+ }
136
+
137
+ // ── Shape: asymmetric (flag/pennant) ──
138
+ function asymmetric(w, h) {
139
+ var notch = h / 4;
140
+ return polygon([
141
+ [-w / 2, -h / 2],
142
+ [w / 2, -h / 2],
143
+ [w / 2 - notch, 0],
144
+ [w / 2, h / 2],
145
+ [-w / 2, h / 2]
146
+ ]);
147
+ }
148
+
149
+ // ── Shape: parallelogram (slanting right) ──
150
+ function parallelogram(w, h) {
151
+ var skew = h * 0.3;
152
+ return polygon([
153
+ [-w / 2 + skew, -h / 2],
154
+ [w / 2, -h / 2],
155
+ [w / 2 - skew, h / 2],
156
+ [-w / 2, h / 2]
157
+ ]);
158
+ }
159
+
160
+ // ── Shape: parallelogram-alt (slanting left, mirror) ──
161
+ function parallelogramAlt(w, h) {
162
+ var skew = h * 0.3;
163
+ return polygon([
164
+ [-w / 2, -h / 2],
165
+ [w / 2 - skew, -h / 2],
166
+ [w / 2, h / 2],
167
+ [-w / 2 + skew, h / 2]
168
+ ]);
169
+ }
170
+
171
+ // ── Shape: trapezoid (wider at bottom) ──
172
+ function trapezoid(w, h) {
173
+ var dx = w * 0.15;
174
+ return polygon([
175
+ [-w / 2 + dx, -h / 2],
176
+ [w / 2 - dx, -h / 2],
177
+ [w / 2, h / 2],
178
+ [-w / 2, h / 2]
179
+ ]);
180
+ }
181
+
182
+ // ── Shape: trapezoid-alt (wider at top) ──
183
+ function trapezoidAlt(w, h) {
184
+ var dx = w * 0.15;
185
+ return polygon([
186
+ [-w / 2, -h / 2],
187
+ [w / 2, -h / 2],
188
+ [w / 2 - dx, h / 2],
189
+ [-w / 2 + dx, h / 2]
190
+ ]);
191
+ }
192
+
193
+ // ── Shape Registry ──
194
+ var SHAPE_RENDERERS = {
195
+ 'rect': rect,
196
+ 'rounded': rounded,
197
+ 'stadium': stadium,
198
+ 'diamond': diamond,
199
+ 'circle': circle,
200
+ 'hexagon': hexagon,
201
+ 'subroutine': subroutine,
202
+ 'cylinder': cylinder,
203
+ 'asymmetric': asymmetric,
204
+ 'parallelogram': parallelogram,
205
+ 'parallelogram-alt': parallelogramAlt,
206
+ 'trapezoid': trapezoid,
207
+ 'trapezoid-alt': trapezoidAlt
208
+ };
209
+
210
+ // ── Render function ──
211
+ function render(shape, w, h) {
212
+ var fn = SHAPE_RENDERERS[shape] || SHAPE_RENDERERS['rect'];
213
+ return fn(w, h);
214
+ }
215
+
216
+ // ── Public API ──
217
+ window.SmartCodeSvgShapes = { render: render };
218
+ })();
@@ -0,0 +1,76 @@
1
+ /* SmartCode — Carbon Design Tokens */
2
+ /* Single source of truth for all colors, spacing, and radius */
3
+
4
+ :root {
5
+ /* Surface colors (dark chrome) */
6
+ --surface-0: #111113;
7
+ --surface-1: #18181b;
8
+ --surface-2: #1f1f23;
9
+ --surface-3: #27272b;
10
+ --surface-4: #303036;
11
+
12
+ /* Preview canvas (light, for Mermaid readability) */
13
+ --preview-bg: #fafafa;
14
+
15
+ /* Borders */
16
+ --border-subtle: #27272b;
17
+ --border-default: #303036;
18
+ --border-focus: #3b82f6;
19
+
20
+ /* Text */
21
+ --text-primary: #e4e4e7;
22
+ --text-secondary: #a1a1aa;
23
+ --text-tertiary: #71717a;
24
+ --text-on-accent: #ffffff;
25
+
26
+ /* Accent (blue) */
27
+ --accent: #3b82f6;
28
+ --accent-hover: #2563eb;
29
+ --accent-muted: rgba(59, 130, 246, 0.15);
30
+
31
+ /* Status — semantically identical colors */
32
+ --status-ok: #22c55e;
33
+ --status-ok-stroke: #16a34a;
34
+ --status-problem: #ef4444;
35
+ --status-problem-stroke: #dc2626;
36
+ --status-warning: #eab308;
37
+ --status-warning-stroke: #ca8a04;
38
+ --status-neutral: #71717a;
39
+ --status-neutral-stroke: #52525b;
40
+
41
+ /* Utility */
42
+ --ghost-path: #8b5cf6;
43
+ --search-match: #f59e0b;
44
+ --breakpoint: #ef4444;
45
+ --diff-added: #22c55e;
46
+ --diff-removed: #ef4444;
47
+ --diff-modified: #eab308;
48
+
49
+ /* Mermaid theme (light canvas) */
50
+ --mermaid-primary: #3b82f6;
51
+ --mermaid-primary-text: #18181b;
52
+ --mermaid-primary-border: #2563eb;
53
+ --mermaid-secondary: #dbeafe;
54
+ --mermaid-tertiary: #f0fdf4;
55
+ --mermaid-line: #52525b;
56
+ --mermaid-main-bg: #eff6ff;
57
+ --mermaid-node-border: #2563eb;
58
+ --mermaid-cluster-bg: #f4f4f5;
59
+ --mermaid-cluster-border: #a1a1aa;
60
+ --mermaid-title: #18181b;
61
+ --mermaid-edge-label-bg: #ffffff;
62
+
63
+ /* Spacing scale */
64
+ --space-1: 4px;
65
+ --space-2: 8px;
66
+ --space-3: 12px;
67
+ --space-4: 16px;
68
+ --space-6: 24px;
69
+ --space-8: 32px;
70
+
71
+ /* Radius scale */
72
+ --radius-sm: 2px;
73
+ --radius-md: 4px;
74
+ --radius-lg: 6px;
75
+ --radius-xl: 8px;
76
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * dagre-bundle.js — loads graphlib then dagre for browser use.
3
+ *
4
+ * @dagrejs/dagre@2 internally calls require("@dagrejs/graphlib") which
5
+ * breaks in the browser. We load graphlib first (it self-registers as
6
+ * window.graphlib) and then monkey-patch the bundler's require so dagre
7
+ * can find it.
8
+ */
9
+ (function () {
10
+ 'use strict';
11
+
12
+ /* ── 1. Inject graphlib ──────────────────────────────────────────── */
13
+ var s1 = document.createElement('script');
14
+ s1.src = 'vendor/graphlib.min.js';
15
+ s1.async = false; // keep execution order
16
+ document.head.appendChild(s1);
17
+
18
+ /* ── 2. Once graphlib is ready, patch require and inject dagre ──── */
19
+ s1.onload = function () {
20
+ // The dagre CJS bundle calls __require("@dagrejs/graphlib").
21
+ // We intercept that by shimming a global require that resolves it.
22
+ var _origRequire = window.require; // may be undefined — that's fine
23
+ window.require = function (id) {
24
+ if (id === '@dagrejs/graphlib') return window.graphlib;
25
+ if (typeof _origRequire === 'function') return _origRequire(id);
26
+ throw new Error('Cannot find module "' + id + '"');
27
+ };
28
+
29
+ var s2 = document.createElement('script');
30
+ s2.src = 'vendor/dagre.min.js';
31
+ s2.async = false;
32
+ document.head.appendChild(s2);
33
+
34
+ s2.onload = function () {
35
+ // Restore original require (or remove shim)
36
+ if (_origRequire) {
37
+ window.require = _origRequire;
38
+ } else {
39
+ delete window.require;
40
+ }
41
+ };
42
+ };
43
+ })();