kymostudio 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.
- package/LICENSE +201 -0
- package/README.md +53 -0
- package/icons-manifest.json +1 -0
- package/package.json +30 -0
- package/src/js/icons-builtin.js +399 -0
- package/src/js/icons-loader.js +91 -0
- package/src/js/index.js +13 -0
- package/src/js/model.js +176 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-coded SVG icon library — JS mirror of `src/icons.py`.
|
|
3
|
+
*
|
|
4
|
+
* Each entry in `ICONS` is an SVG fragment centred at (0, 0). The
|
|
5
|
+
* renderer wraps it in a `<g transform="translate(cx, cy)">`. Helper
|
|
6
|
+
* functions (`_cube`, `_box`, `_awsTile`, `_halo`, `_stepBadge`)
|
|
7
|
+
* generate consistent shells around inner glyphs, mirroring the
|
|
8
|
+
* Python originals 1:1.
|
|
9
|
+
*
|
|
10
|
+
* The file-backed icons (icons/<provider>/<name>.png) live in
|
|
11
|
+
* `icons-loader.js`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ── Numeric formatter ─────────────────────────────────────────────────
|
|
15
|
+
function r(x) {
|
|
16
|
+
const s = x.toFixed(2);
|
|
17
|
+
return s.replace(/\.?0+$/, "");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── Isometric cube (NVIDIA green) ─────────────────────────────────────
|
|
21
|
+
function _cube(innerUnit, size = 80) {
|
|
22
|
+
const s = size;
|
|
23
|
+
const h = (s / 2) | 0;
|
|
24
|
+
const a = r(s * 0.44);
|
|
25
|
+
const b = r(s * 0.21);
|
|
26
|
+
const d = r(s * 0.44);
|
|
27
|
+
const e = r(s * 0.06);
|
|
28
|
+
const f = r(s * 0.28);
|
|
29
|
+
const p = Object.fromEntries(
|
|
30
|
+
[["06", 0.06], ["28", 0.28], ["49", 0.49], ["72", 0.72], ["94", 0.94], ["50", 0.50]]
|
|
31
|
+
.map(([k, v]) => [k, r(s * v)])
|
|
32
|
+
);
|
|
33
|
+
return (
|
|
34
|
+
`<g class="icon-shadow" transform="translate(-${h},-${h})">` +
|
|
35
|
+
`<polygon points="${p["50"]},${p["06"]} ${p["94"]},${p["28"]} ${p["50"]},${p["49"]} ${p["06"]},${p["28"]}" ` +
|
|
36
|
+
`fill="url(#g-face-top)" stroke="#3d5d00" stroke-width="1"/>` +
|
|
37
|
+
`<polygon points="${p["50"]},${p["49"]} ${p["94"]},${p["28"]} ${p["94"]},${p["72"]} ${p["50"]},${p["94"]}" ` +
|
|
38
|
+
`fill="url(#g-face-side)" stroke="#3d5d00" stroke-width="1"/>` +
|
|
39
|
+
`<polygon points="${p["06"]},${p["28"]} ${p["50"]},${p["49"]} ${p["50"]},${p["94"]} ${p["06"]},${p["72"]}" ` +
|
|
40
|
+
`fill="url(#g-face-front)" stroke="#3d5d00" stroke-width="1"/>` +
|
|
41
|
+
`<g transform="matrix(${a},${b},0,${d},${e},${f})" stroke-linejoin="round">${innerUnit}</g>` +
|
|
42
|
+
`</g>`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── Inner cube glyphs (unit space) ────────────────────────────────────
|
|
47
|
+
const _NOTEBOOK_GLYPH = `
|
|
48
|
+
<g stroke="white" stroke-width="0.045" stroke-linecap="round" fill="none">
|
|
49
|
+
<line x1="0.18" y1="0.32" x2="0.82" y2="0.32"/>
|
|
50
|
+
<line x1="0.18" y1="0.52" x2="0.82" y2="0.52"/>
|
|
51
|
+
<line x1="0.18" y1="0.72" x2="0.60" y2="0.72"/>
|
|
52
|
+
</g>
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const _DOCKER_GLYPH = `
|
|
56
|
+
<g fill="white">
|
|
57
|
+
<rect x="0.10" y="0.30" width="0.34" height="0.18"/>
|
|
58
|
+
<rect x="0.56" y="0.30" width="0.34" height="0.18"/>
|
|
59
|
+
<rect x="0.10" y="0.56" width="0.34" height="0.18"/>
|
|
60
|
+
<rect x="0.56" y="0.56" width="0.34" height="0.18"/>
|
|
61
|
+
</g>
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const _NEURAL_GLYPH = `
|
|
65
|
+
<g stroke="white" stroke-width="0.032" fill="white">
|
|
66
|
+
<line x1="0.50" y1="0.50" x2="0.20" y2="0.22"/>
|
|
67
|
+
<line x1="0.50" y1="0.50" x2="0.80" y2="0.22"/>
|
|
68
|
+
<line x1="0.50" y1="0.50" x2="0.20" y2="0.78"/>
|
|
69
|
+
<line x1="0.50" y1="0.50" x2="0.80" y2="0.78"/>
|
|
70
|
+
<circle cx="0.50" cy="0.50" r="0.085"/>
|
|
71
|
+
<circle cx="0.20" cy="0.22" r="0.055"/>
|
|
72
|
+
<circle cx="0.80" cy="0.22" r="0.055"/>
|
|
73
|
+
<circle cx="0.20" cy="0.78" r="0.055"/>
|
|
74
|
+
<circle cx="0.80" cy="0.78" r="0.055"/>
|
|
75
|
+
</g>
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const _HEX_NET_GLYPH = `
|
|
79
|
+
<g stroke="white" stroke-width="0.04" fill="white">
|
|
80
|
+
<line x1="0.50" y1="0.20" x2="0.20" y2="0.50"/>
|
|
81
|
+
<line x1="0.50" y1="0.20" x2="0.80" y2="0.50"/>
|
|
82
|
+
<line x1="0.20" y1="0.50" x2="0.50" y2="0.80"/>
|
|
83
|
+
<line x1="0.80" y1="0.50" x2="0.50" y2="0.80"/>
|
|
84
|
+
<line x1="0.20" y1="0.50" x2="0.80" y2="0.50"/>
|
|
85
|
+
<line x1="0.50" y1="0.20" x2="0.50" y2="0.80"/>
|
|
86
|
+
<circle cx="0.50" cy="0.20" r="0.055"/>
|
|
87
|
+
<circle cx="0.20" cy="0.50" r="0.055"/>
|
|
88
|
+
<circle cx="0.80" cy="0.50" r="0.055"/>
|
|
89
|
+
<circle cx="0.50" cy="0.80" r="0.055"/>
|
|
90
|
+
</g>
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
// ── Flat orange box wrapper ───────────────────────────────────────────
|
|
94
|
+
function _box(inner) {
|
|
95
|
+
return (
|
|
96
|
+
`<g class="icon-shadow">` +
|
|
97
|
+
`<rect x="-35" y="-35" width="70" height="70" rx="8" ` +
|
|
98
|
+
`fill="url(#g-box-orange)" stroke="#c2410c" stroke-width="1.5"/>` +
|
|
99
|
+
`${inner}` +
|
|
100
|
+
`</g>`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const _SEND_GLYPH = `
|
|
105
|
+
<g transform="translate(-13, -13)">
|
|
106
|
+
<line x1="28" y1="2" x2="13" y2="17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
107
|
+
<polygon points="28,2 21,28 13,17 2,11 28,2" fill="white" stroke="white" stroke-width="1.2" stroke-linejoin="round"/>
|
|
108
|
+
</g>
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
const _ZAP_GLYPH = `
|
|
112
|
+
<polygon points="2,-18 -12,4 -1,4 -3,18 11,-4 0,-4 2,-18" fill="white" stroke="white" stroke-width="1.2" stroke-linejoin="round"/>
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
const _ARCHIVE_GLYPH = `
|
|
116
|
+
<g transform="translate(0,-2)">
|
|
117
|
+
<rect x="-20" y="-15" width="40" height="9" rx="2" fill="white"/>
|
|
118
|
+
<path d="M -16,-6 V 16 a 2,2 0 0 0 2,2 H 14 a 2,2 0 0 0 2,-2 V -6" fill="none" stroke="white" stroke-width="2" stroke-linejoin="round"/>
|
|
119
|
+
<line x1="-6" y1="3" x2="6" y2="3" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
120
|
+
</g>
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const _CLOUD_GLYPH = `
|
|
124
|
+
<path d="M -10,12 a 12,12 0 1 1 5,-23 a 16,16 0 0 1 22,15 a 9,9 0 0 1 -2,17 H -10 a 9,9 0 0 1 0,-9 z"
|
|
125
|
+
fill="white" stroke="white" stroke-width="1" stroke-linejoin="round"/>
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
// ── Standalone shapes ─────────────────────────────────────────────────
|
|
129
|
+
const _USER_CIRCLE = `
|
|
130
|
+
<g class="icon-shadow">
|
|
131
|
+
<circle r="38" fill="url(#g-user-blue)"/>
|
|
132
|
+
<circle cy="-9" r="10" fill="white"/>
|
|
133
|
+
<path d="M -18,20 a 18,14 0 0 1 36,0 z" fill="white"/>
|
|
134
|
+
</g>
|
|
135
|
+
`;
|
|
136
|
+
|
|
137
|
+
const _CYLINDER = `
|
|
138
|
+
<g class="icon-shadow" transform="translate(-35, -35)">
|
|
139
|
+
<ellipse cx="35" cy="12" rx="28" ry="8" fill="#fdba74" stroke="#c2410c" stroke-width="1.4"/>
|
|
140
|
+
<path d="M 7,12 V 58 a 28,8 0 0 0 56,0 V 12" fill="url(#g-cyl-orange)" stroke="#c2410c" stroke-width="1.4"/>
|
|
141
|
+
<ellipse cx="35" cy="12" rx="28" ry="8" fill="none" stroke="#c2410c" stroke-width="1.2"/>
|
|
142
|
+
<path d="M 7,28 a 28,8 0 0 0 56,0" fill="none" stroke="#c2410c" stroke-width="0.8" opacity="0.55"/>
|
|
143
|
+
<path d="M 7,42 a 28,8 0 0 0 56,0" fill="none" stroke="#c2410c" stroke-width="0.8" opacity="0.55"/>
|
|
144
|
+
</g>
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
const _KEY = `
|
|
148
|
+
<g stroke="#d97706" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
149
|
+
<circle cx="-10" cy="0" r="6" fill="#fff4e0"/>
|
|
150
|
+
<line x1="-4" y1="-2" x2="16" y2="-2"/>
|
|
151
|
+
<line x1="10" y1="-2" x2="10" y2="3"/>
|
|
152
|
+
<line x1="16" y1="-2" x2="16" y2="5"/>
|
|
153
|
+
</g>
|
|
154
|
+
`;
|
|
155
|
+
|
|
156
|
+
const _HEX_AGENT = `
|
|
157
|
+
<g class="icon-shadow">
|
|
158
|
+
<polygon points="-30,-17 0,-32 30,-17 30,17 0,32 -30,17"
|
|
159
|
+
fill="#e9f5d0" stroke="#3d5d00" stroke-width="1.6"/>
|
|
160
|
+
<circle cx="0" cy="-7" r="6.5" fill="#76b900"/>
|
|
161
|
+
<circle cx="-2.5" cy="-7" r="1" fill="#e9f5d0"/>
|
|
162
|
+
<circle cx="2.5" cy="-7" r="1" fill="#e9f5d0"/>
|
|
163
|
+
<path d="M -14,18 Q -14,4 0,4 Q 14,4 14,18 Z" fill="#76b900"/>
|
|
164
|
+
<path d="M -4,6 L 0,12 L 4,6" fill="#e9f5d0" stroke="none"/>
|
|
165
|
+
</g>
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
// ── More _box-inner glyphs ────────────────────────────────────────────
|
|
169
|
+
const _GEAR_GLYPH = `
|
|
170
|
+
<g fill="white" stroke="white" stroke-width="1.4" stroke-linejoin="round">
|
|
171
|
+
<path d="M 0,-15 L 4,-15 L 5,-11 L 9,-9 L 12,-12 L 15,-9 L 12,-6 L 14,-2 L 18,-1 L 18,3
|
|
172
|
+
L 14,4 L 12,8 L 15,11 L 12,14 L 9,11 L 5,13 L 4,17 L 0,17 L -1,13 L -5,11
|
|
173
|
+
L -8,14 L -11,11 L -8,8 L -10,4 L -14,3 L -14,-1 L -10,-2 L -8,-6 L -11,-9
|
|
174
|
+
L -8,-12 L -5,-9 L -1,-11 L 0,-15 Z"
|
|
175
|
+
transform="translate(2, -2) scale(0.85)"/>
|
|
176
|
+
<circle cx="2" cy="-2" r="4" fill="#f59e0b" stroke="#f59e0b"/>
|
|
177
|
+
</g>
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
const _FOLDER_GLYPH = `
|
|
181
|
+
<g fill="white" stroke="white" stroke-width="1.2" stroke-linejoin="round">
|
|
182
|
+
<path d="M -22,-12 L -8,-12 L -4,-7 L 22,-7 L 22,16 L -22,16 Z"/>
|
|
183
|
+
</g>
|
|
184
|
+
`;
|
|
185
|
+
|
|
186
|
+
const _FILES_STACK = `
|
|
187
|
+
<g fill="white" stroke="white" stroke-width="1.2" stroke-linejoin="round">
|
|
188
|
+
<rect x="-18" y="-18" width="20" height="26" rx="2" fill="white" opacity="0.6"/>
|
|
189
|
+
<rect x="-8" y="-8" width="22" height="28" rx="2" fill="white"/>
|
|
190
|
+
<line x1="-3" y1="-1" x2="10" y2="-1" stroke="#d97706" stroke-width="1.2"/>
|
|
191
|
+
<line x1="-3" y1="4" x2="10" y2="4" stroke="#d97706" stroke-width="1.2"/>
|
|
192
|
+
<line x1="-3" y1="9" x2="6" y2="9" stroke="#d97706" stroke-width="1.2"/>
|
|
193
|
+
</g>
|
|
194
|
+
`;
|
|
195
|
+
|
|
196
|
+
const _CHECKLIST_GLYPH = `
|
|
197
|
+
<g stroke="#94a3b8" fill="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
198
|
+
<rect x="-22" y="-22" width="44" height="44" rx="2" fill="white"/>
|
|
199
|
+
<polyline points="-15,-14 -12,-11 -8,-16" fill="none" stroke="#475569" stroke-width="2"/>
|
|
200
|
+
<line x1="-4" y1="-13" x2="14" y2="-13" stroke="#94a3b8"/>
|
|
201
|
+
<polyline points="-15,-2 -12,1 -8,-4" fill="none" stroke="#475569" stroke-width="2"/>
|
|
202
|
+
<line x1="-4" y1="-1" x2="14" y2="-1" stroke="#94a3b8"/>
|
|
203
|
+
<polyline points="-15,10 -12,13 -8,8" fill="none" stroke="#475569" stroke-width="2"/>
|
|
204
|
+
<line x1="-4" y1="11" x2="14" y2="11" stroke="#94a3b8"/>
|
|
205
|
+
</g>
|
|
206
|
+
`;
|
|
207
|
+
|
|
208
|
+
const _MAGNIFIER_GLYPH = `
|
|
209
|
+
<g fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
|
|
210
|
+
<circle cx="-3" cy="-3" r="11" fill="white" stroke="white" stroke-width="0"/>
|
|
211
|
+
<circle cx="-3" cy="-3" r="9" fill="none" stroke="#f59e0b" stroke-width="3"/>
|
|
212
|
+
<line x1="5" y1="5" x2="14" y2="14" stroke="white" stroke-width="4"/>
|
|
213
|
+
</g>
|
|
214
|
+
`;
|
|
215
|
+
|
|
216
|
+
// ── Halo wrapper ──────────────────────────────────────────────────────
|
|
217
|
+
function _halo(inner, size = 124) {
|
|
218
|
+
const s = (size / 2) | 0;
|
|
219
|
+
return `<circle r="${s}" fill="#76b900" opacity="0.10"/>` +
|
|
220
|
+
`<circle r="${s - 6}" fill="#76b900" opacity="0.08"/>` +
|
|
221
|
+
`${inner}`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ── AWS-style coloured tile ───────────────────────────────────────────
|
|
225
|
+
function _awsTile(color, dark, glyph, hero = false) {
|
|
226
|
+
const size = hero ? 80 : 64;
|
|
227
|
+
const h = (size / 2) | 0;
|
|
228
|
+
return (
|
|
229
|
+
`<g class="icon-shadow">` +
|
|
230
|
+
`<rect x="-${h}" y="-${h}" width="${size}" height="${size}" rx="10" ` +
|
|
231
|
+
`fill="${color}" stroke="${dark}" stroke-width="1.4"/>` +
|
|
232
|
+
`${glyph}` +
|
|
233
|
+
`</g>`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const _AMPLIFY_GLYPH = `
|
|
238
|
+
<g fill="white" stroke="none">
|
|
239
|
+
<path d="M -14,12 L -3,-12 L 3,-12 L 14,12 L 7,12 L 4,5 L -4,5 L -7,12 Z"/>
|
|
240
|
+
<path d="M -1,-1 L 1,-1 L 2,2 L -2,2 Z"/>
|
|
241
|
+
</g>
|
|
242
|
+
`;
|
|
243
|
+
|
|
244
|
+
const _LEX_GLYPH = `
|
|
245
|
+
<g fill="white" stroke="none">
|
|
246
|
+
<path d="M -14,-8 a 4,4 0 0 1 4,-4 H 10 a 4,4 0 0 1 4,4 V 4 a 4,4 0 0 1 -4,4 H -2 L -8,14 V 8 H -10 a 4,4 0 0 1 -4,-4 Z"/>
|
|
247
|
+
<circle cx="-6" cy="-2" r="1.6" fill="#C925D1"/>
|
|
248
|
+
<circle cx="0" cy="-2" r="1.6" fill="#C925D1"/>
|
|
249
|
+
<circle cx="6" cy="-2" r="1.6" fill="#C925D1"/>
|
|
250
|
+
</g>
|
|
251
|
+
`;
|
|
252
|
+
|
|
253
|
+
const _LAMBDA_GLYPH = `
|
|
254
|
+
<text x="0" y="11" text-anchor="middle"
|
|
255
|
+
style="font-size:38px;font-weight:700;fill:white;font-family:Georgia,serif">λ</text>
|
|
256
|
+
`;
|
|
257
|
+
|
|
258
|
+
const _CONNECT_GLYPH = `
|
|
259
|
+
<g fill="white" stroke="none">
|
|
260
|
+
<path d="M -12,-8 q 0,-4 4,-4 l 4,0 q 3,0 4,3 l 1,4 q 1,3 -2,5 l -3,2 q 3,6 9,9 l 2,-3 q 2,-3 5,-2 l 4,1 q 3,1 3,4 l 0,4 q 0,4 -4,4 q -16,0 -27,-11 q -11,-11 -11,-16 z"/>
|
|
261
|
+
</g>
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
const _DYNAMODB_GLYPH = `
|
|
265
|
+
<g fill="white" stroke="white" stroke-width="0" stroke-linejoin="round">
|
|
266
|
+
<ellipse cx="0" cy="-9" rx="12" ry="3.5"/>
|
|
267
|
+
<path d="M -12,-9 V -1 a 12,3.5 0 0 0 24,0 V -9" fill="white"/>
|
|
268
|
+
<ellipse cx="0" cy="-1" rx="12" ry="3.5" fill="#4D72F3" opacity="0.35"/>
|
|
269
|
+
<path d="M -12,0 V 8 a 12,3.5 0 0 0 24,0 V 0" fill="white"/>
|
|
270
|
+
<ellipse cx="0" cy="8" rx="12" ry="3.5" fill="#4D72F3" opacity="0.35"/>
|
|
271
|
+
<path d="M -12,9 V 12 a 12,3.5 0 0 0 24,0 V 9" fill="white"/>
|
|
272
|
+
</g>
|
|
273
|
+
`;
|
|
274
|
+
|
|
275
|
+
const _BEDROCK_GLYPH = `
|
|
276
|
+
<g fill="white" stroke="white" stroke-width="1.6" stroke-linecap="round">
|
|
277
|
+
<circle cx="0" cy="0" r="3.5" fill="white"/>
|
|
278
|
+
<circle cx="-10" cy="-7" r="2.5" fill="white"/>
|
|
279
|
+
<circle cx="10" cy="-7" r="2.5" fill="white"/>
|
|
280
|
+
<circle cx="-10" cy="7" r="2.5" fill="white"/>
|
|
281
|
+
<circle cx="10" cy="7" r="2.5" fill="white"/>
|
|
282
|
+
<line x1="-7" y1="-5" x2="-2" y2="-1"/>
|
|
283
|
+
<line x1="7" y1="-5" x2="2" y2="-1"/>
|
|
284
|
+
<line x1="-7" y1="5" x2="-2" y2="1"/>
|
|
285
|
+
<line x1="7" y1="5" x2="2" y2="1"/>
|
|
286
|
+
</g>
|
|
287
|
+
`;
|
|
288
|
+
|
|
289
|
+
const _S3_GLYPH = `
|
|
290
|
+
<g fill="white" stroke="none">
|
|
291
|
+
<path d="M -12,-8 L 12,-8 L 10,12 a 2,2 0 0 1 -2,2 L -8,14 a 2,2 0 0 1 -2,-2 Z"/>
|
|
292
|
+
<ellipse cx="0" cy="-8" rx="12" ry="3" fill="#7AA116"/>
|
|
293
|
+
<ellipse cx="0" cy="-8" rx="12" ry="3" fill="none" stroke="white" stroke-width="1.2"/>
|
|
294
|
+
</g>
|
|
295
|
+
`;
|
|
296
|
+
|
|
297
|
+
const _KENDRA_GLYPH = `
|
|
298
|
+
<g fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round">
|
|
299
|
+
<circle cx="-3" cy="-3" r="8"/>
|
|
300
|
+
<line x1="3" y1="3" x2="11" y2="11"/>
|
|
301
|
+
</g>
|
|
302
|
+
`;
|
|
303
|
+
|
|
304
|
+
const _CUSTOMER_PERSON = `
|
|
305
|
+
<g class="icon-shadow">
|
|
306
|
+
<circle r="34" fill="url(#g-user-blue)"/>
|
|
307
|
+
<circle cy="-8" r="9" fill="white"/>
|
|
308
|
+
<path d="M -16,18 a 16,12 0 0 1 32,0 z" fill="white"/>
|
|
309
|
+
</g>
|
|
310
|
+
`;
|
|
311
|
+
|
|
312
|
+
const _INTERNET_CLOUD = `
|
|
313
|
+
<g class="icon-shadow">
|
|
314
|
+
<path d="M -22,8 a 14,14 0 1 1 6,-26 a 18,18 0 0 1 26,16 a 11,11 0 0 1 -3,21 H -22 a 11,11 0 0 1 -7,-11 z"
|
|
315
|
+
fill="#dbeafe" stroke="#1d4ed8" stroke-width="1.6" stroke-linejoin="round"/>
|
|
316
|
+
<text x="0" y="6" text-anchor="middle"
|
|
317
|
+
style="font-size:9.5px;font-weight:700;fill:#1d4ed8;letter-spacing:0.05em">WWW</text>
|
|
318
|
+
</g>
|
|
319
|
+
`;
|
|
320
|
+
|
|
321
|
+
const _SLACK_BADGE = `
|
|
322
|
+
<g class="icon-shadow">
|
|
323
|
+
<rect x="-16" y="-16" width="32" height="32" rx="7" fill="white" stroke="#cbd5e1" stroke-width="1"/>
|
|
324
|
+
<g stroke-linecap="round" stroke-width="3.6" fill="none">
|
|
325
|
+
<line x1="-7" y1="-3" x2="7" y2="-3" stroke="#e01e5a"/>
|
|
326
|
+
<line x1="-7" y1="3" x2="7" y2="3" stroke="#36c5f0"/>
|
|
327
|
+
<line x1="-3" y1="-7" x2="-3" y2="7" stroke="#2eb67d"/>
|
|
328
|
+
<line x1="3" y1="-7" x2="3" y2="7" stroke="#ecb22e"/>
|
|
329
|
+
</g>
|
|
330
|
+
</g>
|
|
331
|
+
`;
|
|
332
|
+
|
|
333
|
+
const _PLUS_MARK = `
|
|
334
|
+
<g fill="#475569" stroke="#475569" stroke-width="2" stroke-linecap="round">
|
|
335
|
+
<line x1="-6" y1="0" x2="6" y2="0"/>
|
|
336
|
+
<line x1="0" y1="-6" x2="0" y2="6"/>
|
|
337
|
+
</g>
|
|
338
|
+
`;
|
|
339
|
+
|
|
340
|
+
const _AWS_LOGO = `
|
|
341
|
+
<g class="icon-shadow">
|
|
342
|
+
<rect x="-18" y="-18" width="36" height="36" rx="4" fill="#232f3e"/>
|
|
343
|
+
<text x="0" y="2" text-anchor="middle"
|
|
344
|
+
style="font-size:14px;font-weight:800;fill:white;font-family:Arial,Helvetica,sans-serif;letter-spacing:-0.4px">aws</text>
|
|
345
|
+
<path d="M -9,8 Q 0,13 9,8" fill="none" stroke="#ff9900" stroke-width="1.8" stroke-linecap="round"/>
|
|
346
|
+
</g>
|
|
347
|
+
`;
|
|
348
|
+
|
|
349
|
+
const _SITE_GLOBE = `
|
|
350
|
+
<g fill="none" stroke="#475569" stroke-width="1.4" stroke-linecap="round">
|
|
351
|
+
<circle r="9"/>
|
|
352
|
+
<ellipse cx="0" cy="0" rx="4" ry="9"/>
|
|
353
|
+
<line x1="-9" y1="0" x2="9" y2="0"/>
|
|
354
|
+
</g>
|
|
355
|
+
`;
|
|
356
|
+
|
|
357
|
+
function _stepBadge(n) {
|
|
358
|
+
return `<circle r="14" fill="#fff4e0" stroke="#d97706" stroke-width="1.8"/>` +
|
|
359
|
+
`<text x="0" y="4.5" text-anchor="middle" ` +
|
|
360
|
+
`style="font-size:14px;font-weight:700;fill:#92400e">${n}</text>`;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ── Public registry ───────────────────────────────────────────────────
|
|
364
|
+
export const ICONS = {
|
|
365
|
+
"user": _USER_CIRCLE,
|
|
366
|
+
"notebook": _cube(_NOTEBOOK_GLYPH),
|
|
367
|
+
"boxes": _cube(_DOCKER_GLYPH),
|
|
368
|
+
"neural": _halo(_cube(_NEURAL_GLYPH, 100)),
|
|
369
|
+
"neural-sm": _cube(_HEX_NET_GLYPH),
|
|
370
|
+
"send": _box(_SEND_GLYPH),
|
|
371
|
+
"zap": _box(_ZAP_GLYPH),
|
|
372
|
+
"archive": _box(_ARCHIVE_GLYPH),
|
|
373
|
+
"cloud": _box(_CLOUD_GLYPH),
|
|
374
|
+
"cylinder": _CYLINDER,
|
|
375
|
+
"key": _KEY,
|
|
376
|
+
"hex-agent": _HEX_AGENT,
|
|
377
|
+
"gear": _box(_GEAR_GLYPH),
|
|
378
|
+
"folder": _box(_FOLDER_GLYPH),
|
|
379
|
+
"files": _box(_FILES_STACK),
|
|
380
|
+
"checklist": _box(_CHECKLIST_GLYPH),
|
|
381
|
+
"magnifier": _box(_MAGNIFIER_GLYPH),
|
|
382
|
+
"aws-amplify": _awsTile("#DD344C", "#a31836", _AMPLIFY_GLYPH),
|
|
383
|
+
"aws-lex": _awsTile("#C925D1", "#8a1690", _LEX_GLYPH),
|
|
384
|
+
"aws-lambda": _awsTile("#ED7100", "#a44a00", _LAMBDA_GLYPH, true),
|
|
385
|
+
"aws-connect": _awsTile("#DD344C", "#a31836", _CONNECT_GLYPH),
|
|
386
|
+
"aws-dynamodb": _awsTile("#4D72F3", "#2a4ec2", _DYNAMODB_GLYPH),
|
|
387
|
+
"aws-bedrock": _awsTile("#01A88D", "#017364", _BEDROCK_GLYPH),
|
|
388
|
+
"aws-s3": _awsTile("#7AA116", "#506b0e", _S3_GLYPH),
|
|
389
|
+
"aws-kendra": _awsTile("#C925D1", "#8a1690", _KENDRA_GLYPH),
|
|
390
|
+
"customer-person": _CUSTOMER_PERSON,
|
|
391
|
+
"internet-cloud": _INTERNET_CLOUD,
|
|
392
|
+
"step-1": _stepBadge(1),
|
|
393
|
+
"step-2": _stepBadge(2),
|
|
394
|
+
"step-3": _stepBadge(3),
|
|
395
|
+
"aws-logo": _AWS_LOGO,
|
|
396
|
+
"site-globe": _SITE_GLOBE,
|
|
397
|
+
"slack": _SLACK_BADGE,
|
|
398
|
+
"plus": _PLUS_MARK,
|
|
399
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon loader — JS mirror of `src/icons.py:get_icon`.
|
|
3
|
+
*
|
|
4
|
+
* Built-in glyphs (from `icons-builtin.js`) are returned synchronously
|
|
5
|
+
* wrapped in `Promise.resolve()`. File-backed PNG icons are resolved
|
|
6
|
+
* lazily: on first request the manifest is fetched, then the PNG bytes
|
|
7
|
+
* are fetched and embedded as a base64 `<image>` tag inside an SVG
|
|
8
|
+
* fragment. Subsequent lookups are cache hits.
|
|
9
|
+
*
|
|
10
|
+
* Configure the base URL with `setIconBaseURL(url)` before the first
|
|
11
|
+
* call — defaults to `""` (paths are relative to the page).
|
|
12
|
+
*/
|
|
13
|
+
import { ICONS } from "./icons-builtin.js";
|
|
14
|
+
|
|
15
|
+
const IMAGE_SIZE = 64;
|
|
16
|
+
const _cache = new Map(Object.entries(ICONS)); // builtin keys start cached
|
|
17
|
+
let _manifest = null;
|
|
18
|
+
let _manifestPromise = null;
|
|
19
|
+
let _baseURL = "";
|
|
20
|
+
|
|
21
|
+
/** Set the URL prefix used to fetch the manifest + icon files. */
|
|
22
|
+
export function setIconBaseURL(url) {
|
|
23
|
+
_baseURL = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Optional override for tests: inject a manifest map directly. */
|
|
27
|
+
export function setManifest(map) {
|
|
28
|
+
_manifest = { ...map };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Optional override for tests: register a single key → SVG fragment. */
|
|
32
|
+
export function registerIcon(key, svg) {
|
|
33
|
+
_cache.set(key, svg);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function loadManifest() {
|
|
37
|
+
if (_manifest) return _manifest;
|
|
38
|
+
if (_manifestPromise) return _manifestPromise;
|
|
39
|
+
const url = `${_baseURL}/icons-manifest.json`.replace(/^\//, "");
|
|
40
|
+
_manifestPromise = fetch(url).then(r => {
|
|
41
|
+
if (!r.ok) throw new Error(`manifest fetch failed: ${r.status}`);
|
|
42
|
+
return r.json();
|
|
43
|
+
}).then(m => (_manifest = m));
|
|
44
|
+
return _manifestPromise;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function pngBytesToImageTag(bytes, size = IMAGE_SIZE) {
|
|
48
|
+
// Base64-encode the PNG bytes for embedding in an SVG `<image>` tag.
|
|
49
|
+
let bin = "";
|
|
50
|
+
for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
|
|
51
|
+
const b64 = (typeof btoa !== "undefined") ? btoa(bin) : Buffer.from(bytes).toString("base64");
|
|
52
|
+
const half = (size / 2) | 0;
|
|
53
|
+
return `<image href="data:image/png;base64,${b64}" ` +
|
|
54
|
+
`x="-${half}" y="-${half}" width="${size}" height="${size}"/>`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function svgTextToInline(text, size = IMAGE_SIZE) {
|
|
58
|
+
const half = (size / 2) | 0;
|
|
59
|
+
return `<svg x="-${half}" y="-${half}" width="${size}" height="${size}" ` +
|
|
60
|
+
`overflow="visible">${text}</svg>`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Resolve `key` to an SVG fragment. Returns a Promise; built-in icons
|
|
65
|
+
* resolve immediately, file-backed PNGs/SVGs after a network fetch.
|
|
66
|
+
* Throws when the key is not in the built-in registry and not in the
|
|
67
|
+
* manifest.
|
|
68
|
+
*/
|
|
69
|
+
export async function getIcon(key) {
|
|
70
|
+
if (_cache.has(key)) return _cache.get(key);
|
|
71
|
+
|
|
72
|
+
const manifest = await loadManifest();
|
|
73
|
+
const path = manifest[key];
|
|
74
|
+
if (!path) throw new Error(`unknown icon: ${JSON.stringify(key)}`);
|
|
75
|
+
|
|
76
|
+
const url = _baseURL ? `${_baseURL}/${path}` : path;
|
|
77
|
+
const res = await fetch(url);
|
|
78
|
+
if (!res.ok) throw new Error(`icon fetch failed: ${path} (${res.status})`);
|
|
79
|
+
|
|
80
|
+
let svg;
|
|
81
|
+
if (path.endsWith(".svg")) {
|
|
82
|
+
svg = svgTextToInline(await res.text());
|
|
83
|
+
} else {
|
|
84
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
85
|
+
svg = pngBytesToImageTag(buf);
|
|
86
|
+
}
|
|
87
|
+
_cache.set(key, svg);
|
|
88
|
+
return svg;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { ICONS };
|
package/src/js/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kymo — browser/Node port of the diagram-as-code model + icon library.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Python source-of-truth at `src/python/kymo/`. This entry
|
|
5
|
+
* point re-exports the data model (`makeComponent`, `makeEdge`, `anchor`,
|
|
6
|
+
* `resolveAnchors`, …) and the icon registry/loader (`ICONS`, `getIcon`,
|
|
7
|
+
* `setIconBaseURL`, …).
|
|
8
|
+
*
|
|
9
|
+
* Note: the DSL parser, layout engine and SVG renderer are currently
|
|
10
|
+
* Python-only; this package ships the shared model + icons.
|
|
11
|
+
*/
|
|
12
|
+
export * from "./model.js";
|
|
13
|
+
export * from "./icons-loader.js"; // re-exports ICONS, getIcon, setIconBaseURL, setManifest, registerIcon
|