amalgm 0.1.143 → 0.1.144
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/package.json +1 -1
- package/runtime/lib/local/amalgmStore.js +0 -7
- package/runtime/scripts/amalgm-mcp/apps/rest.js +24 -1
- package/runtime/scripts/amalgm-mcp/apps/supervisor.js +16 -0
- package/runtime/scripts/amalgm-mcp/browser/cli.js +1 -5
- package/runtime/scripts/amalgm-mcp/browser/engine.js +18 -3
- package/runtime/scripts/amalgm-mcp/browser/paths.js +6 -1
- package/runtime/scripts/amalgm-mcp/browser/rest.js +12 -5
- package/runtime/scripts/amalgm-mcp/computer-use/index.js +1038 -0
- package/runtime/scripts/amalgm-mcp/lib/email-embeds.js +53 -23
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-aa-57534e-ffffff.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-nb-f37626-ffffff.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-p-d24726-ffffff.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-atsign-ffffff.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-box-d6d3d1.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-calendarclock-d6d3d1.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-file-a8a29e.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filearchive-facc15.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-fileimage-2dd4bf.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-fileimage-c084fc.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filespreadsheet-4ade80.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-60a5fa.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-a8a29e.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-f87171.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-folder-d6d3d1.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-globe-d6d3d1.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-video-f472b6.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-zap-fbbf24.png +0 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/manifest.json +56 -0
- package/runtime/scripts/amalgm-mcp/lib/email-icons.js +34 -1
- package/runtime/scripts/amalgm-mcp/lib/email-md.js +95 -51
- package/runtime/scripts/amalgm-mcp/lib/file-icon-registry.json +146 -3
- package/runtime/scripts/amalgm-mcp/lib/generated/email-render.json +153 -0
- package/runtime/scripts/amalgm-mcp/notify/index.js +5 -2
- package/runtime/scripts/amalgm-mcp/server/core-tools.js +6 -0
- package/runtime/scripts/amalgm-mcp/server/routes/apps.js +4 -0
- package/runtime/scripts/amalgm-mcp/tests/browser-cookie-push.test.js +60 -0
- package/runtime/scripts/amalgm-mcp/tests/bundle-entries.test.js +54 -0
- package/runtime/scripts/amalgm-mcp/tests/computer-use.test.js +151 -0
- package/runtime/scripts/amalgm-mcp/tests/core-tools.test.js +4 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-fixtures/citations.md +9 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-fixtures/entities.md +15 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-fixtures/links.md +5 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-fixtures/media.md +21 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-fixtures/text.md +30 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/citations.html +5 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/entities.html +8 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/links.html +3 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/media.html +11 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/notification-shell.html +11 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render-goldens/text.html +12 -0
- package/runtime/scripts/amalgm-mcp/tests/email-render.test.js +82 -0
- package/runtime/scripts/amalgm-mcp/tests/mcp-surface.test.js +2 -0
- package/runtime/scripts/amalgm-mcp/tests/system-catalog.test.js +5 -0
- package/runtime/scripts/amalgm-mcp/toolbox/loadout-context.js +1 -0
- package/runtime/scripts/amalgm-mcp/toolbox/mcp-surface.js +1 -0
- package/runtime/scripts/amalgm-mcp/toolbox/store.js +18 -0
|
@@ -15,14 +15,21 @@
|
|
|
15
15
|
* three in sync.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
// GENERATED tokens/chrome — serialized from lib/rendering/tokens.ts and
|
|
19
|
+
// chromeTokens.ts by scripts/amalgm-mcp/generate-email-render-assets.mts.
|
|
20
|
+
// No hand-mirrored values here: change the canonical file and regenerate.
|
|
21
|
+
const RENDER_ASSETS = require('./generated/email-render.json');
|
|
22
|
+
const TOKENS = RENDER_ASSETS.tokens;
|
|
23
|
+
const CHROME = RENDER_ASSETS.chrome;
|
|
24
|
+
|
|
18
25
|
const COLOR = {
|
|
19
|
-
text:
|
|
20
|
-
textMuted:
|
|
21
|
-
border:
|
|
22
|
-
pillBorder:
|
|
23
|
-
bg:
|
|
24
|
-
bgChip:
|
|
25
|
-
link:
|
|
26
|
+
text: TOKENS.color.text,
|
|
27
|
+
textMuted: TOKENS.color.textMuted,
|
|
28
|
+
border: TOKENS.color.border, // stone-900 — container borders
|
|
29
|
+
pillBorder: TOKENS.color.tableBorder, // stone-800
|
|
30
|
+
bg: TOKENS.color.bg,
|
|
31
|
+
bgChip: TOKENS.color.bgChip, // stone-950
|
|
32
|
+
link: TOKENS.color.link, // blue-400
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
const FILE_ICON_REGISTRY = require('./file-icon-registry.json');
|
|
@@ -182,7 +189,10 @@ function matchesSpecialFilename(rule, normalizedName) {
|
|
|
182
189
|
);
|
|
183
190
|
}
|
|
184
191
|
|
|
185
|
-
function resolveFileIconDescriptor(name) {
|
|
192
|
+
function resolveFileIconDescriptor(name, options = {}) {
|
|
193
|
+
// Mirrors lib/rendering/fileIconRegistry.ts resolveFileIconDescriptor.
|
|
194
|
+
if (options.isSkill) return FILE_ICON_REGISTRY.defaults.skill;
|
|
195
|
+
if (options.isDirectory) return FILE_ICON_REGISTRY.defaults.folder;
|
|
186
196
|
const normalizedName = normalizedBasename(name);
|
|
187
197
|
const special = (FILE_ICON_REGISTRY.specialFilenameIcons || []).find((rule) => matchesSpecialFilename(rule, normalizedName));
|
|
188
198
|
if (special) return special.icon;
|
|
@@ -195,10 +205,21 @@ function resolveEntityIconDescriptor(type) {
|
|
|
195
205
|
return FILE_ICON_REGISTRY.entityIcons[normalized] || FILE_ICON_REGISTRY.entityIcons.entity || FILE_ICON_REGISTRY.defaults.file;
|
|
196
206
|
}
|
|
197
207
|
|
|
198
|
-
function iconHtml(descriptor) {
|
|
208
|
+
function iconHtml(descriptor, size = CHROME.pillIconSize) {
|
|
199
209
|
if (!descriptor) descriptor = FILE_ICON_REGISTRY.defaults.file;
|
|
200
210
|
const contentId = iconContentId(descriptor);
|
|
201
|
-
return `<img src="cid:${contentId}" alt="" width="
|
|
211
|
+
return `<img src="cid:${contentId}" alt="" width="${size}" height="${size}" style="display:block;width:${size}px;height:${size}px;border:0;outline:none;text-decoration:none">`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Inline citation icon — the email form of Citation's 12px icon slot.
|
|
216
|
+
* display:inline-block (not block) so it rides in the text line.
|
|
217
|
+
*/
|
|
218
|
+
function citationIconHtml(descriptor) {
|
|
219
|
+
const size = CHROME.citationIconSize;
|
|
220
|
+
if (!descriptor) descriptor = FILE_ICON_REGISTRY.defaults.file;
|
|
221
|
+
const contentId = iconContentId(descriptor);
|
|
222
|
+
return `<img src="cid:${contentId}" alt="" width="${size}" height="${size}" style="display:inline-block;width:${size}px;height:${size}px;border:0;vertical-align:-1px">`;
|
|
202
223
|
}
|
|
203
224
|
|
|
204
225
|
function openIconHtml() {
|
|
@@ -223,11 +244,14 @@ function chromeLabelParts(name) {
|
|
|
223
244
|
*/
|
|
224
245
|
function chromePill(cells, extra = '') {
|
|
225
246
|
return (
|
|
226
|
-
`<table role="presentation" cellpadding="0" cellspacing="0" style="
|
|
247
|
+
`<table role="presentation" cellpadding="0" cellspacing="0" style="${CHROME.pillTableCss};${extra}">` +
|
|
227
248
|
`<tr>${cells}</tr></table>`
|
|
228
249
|
);
|
|
229
250
|
}
|
|
230
251
|
|
|
252
|
+
// Text centers vertically via line-height = pill height minus the 2px of border.
|
|
253
|
+
const PILL_TEXT_CSS = `font-size:${CHROME.pillFontSize}px;line-height:${CHROME.pillHeight - 2}px;color:${CHROME.pillText};font-weight:400`;
|
|
254
|
+
|
|
231
255
|
/** `[glyph] name` — title text fades after the tab-width budget, matching the UI treatment. */
|
|
232
256
|
function namePill(iconDescriptor, name) {
|
|
233
257
|
const { solid, fade } = chromeLabelParts(name);
|
|
@@ -240,9 +264,9 @@ function namePill(iconDescriptor, name) {
|
|
|
240
264
|
.join(''));
|
|
241
265
|
const labelStyle = fade ? 'width:122px;max-width:122px;' : 'max-width:224px;';
|
|
242
266
|
return chromePill(
|
|
243
|
-
`<td style="padding:0 0 0
|
|
244
|
-
`<td style="padding:0
|
|
245
|
-
`<div title="${escapeAttr(name)}" style="display:block;${labelStyle}overflow:hidden;white-space:nowrap;word-break:normal;overflow-wrap:normal
|
|
267
|
+
`<td style="padding:0 0 0 ${CHROME.pillPaddingX}px;vertical-align:middle;line-height:0;width:${CHROME.pillIconSize}px">${iconHtml(iconDescriptor)}</td>` +
|
|
268
|
+
`<td style="padding:0 ${CHROME.pillPaddingX}px 0 ${CHROME.pillGap}px;vertical-align:middle">` +
|
|
269
|
+
`<div title="${escapeAttr(name)}" style="display:block;${labelStyle}overflow:hidden;white-space:nowrap;word-break:normal;overflow-wrap:normal;${PILL_TEXT_CSS}">${label}</div>` +
|
|
246
270
|
`</td>`
|
|
247
271
|
);
|
|
248
272
|
}
|
|
@@ -250,8 +274,8 @@ function namePill(iconDescriptor, name) {
|
|
|
250
274
|
/** The single "Open ↗" affordance — a link when href is given. */
|
|
251
275
|
function openPill(href) {
|
|
252
276
|
const pill = chromePill(
|
|
253
|
-
`<td style="padding:0 0 0
|
|
254
|
-
`<td style="padding:0
|
|
277
|
+
`<td style="padding:0 0 0 ${CHROME.pillPaddingX}px;vertical-align:middle;line-height:0;width:${CHROME.pillIconSize}px">${openIconHtml()}</td>` +
|
|
278
|
+
`<td style="padding:0 ${CHROME.pillPaddingX}px 0 ${CHROME.pillGap - 2}px;vertical-align:middle;${PILL_TEXT_CSS};white-space:nowrap">Open</td>`
|
|
255
279
|
);
|
|
256
280
|
return href
|
|
257
281
|
? `<a href="${escapeAttr(href)}" target="_blank" style="text-decoration:none;display:inline-block">${pill}</a>`
|
|
@@ -269,7 +293,7 @@ function embedShell({ iconDescriptor, name, action, body = '', minHeight = 96 })
|
|
|
269
293
|
const right = action ? openPill(action.href) : '';
|
|
270
294
|
const content = body || `<div style="height:${minHeight}px;line-height:${minHeight}px;font-size:0;background:${COLOR.bg}"> </div>`;
|
|
271
295
|
return (
|
|
272
|
-
`<div style="
|
|
296
|
+
`<div style="${CHROME.frameCss}">` +
|
|
273
297
|
`<div style="padding:12px 12px 10px;background:${COLOR.bg}">` +
|
|
274
298
|
`<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse"><tr>` +
|
|
275
299
|
`<td align="left" style="padding:0;vertical-align:top;line-height:0">${left}</td>` +
|
|
@@ -291,7 +315,7 @@ function embedShell({ iconDescriptor, name, action, body = '', minHeight = 96 })
|
|
|
291
315
|
* images take the passed href (the "open in amalgm" target).
|
|
292
316
|
*/
|
|
293
317
|
function renderImageEmbed(alt, url, href) {
|
|
294
|
-
const img = `<img src="${escapeAttr(url)}" alt="${escapeAttr(alt || '')}" style="display:block;max-width:100%;height:auto;border-radius:16px;border:1px solid ${COLOR.border};margin:
|
|
318
|
+
const img = `<img src="${escapeAttr(url)}" alt="${escapeAttr(alt || '')}" style="display:block;max-width:100%;height:auto;border-radius:16px;border:1px solid ${COLOR.border};margin:0">`;
|
|
295
319
|
const link = href || (isHttpUrl(url) ? url : null);
|
|
296
320
|
return link
|
|
297
321
|
? `<a href="${escapeAttr(link)}" target="_blank" style="text-decoration:none;display:block">${img}</a>`
|
|
@@ -445,12 +469,15 @@ function renderEntityTile(label, type, id, renderContext = {}) {
|
|
|
445
469
|
const safeLabel = escapeText(label || entityTypeLabel(type));
|
|
446
470
|
const iconDescriptor = resolveEntityIconDescriptor(type);
|
|
447
471
|
const href = buildEntityDeepLink(type, id, renderContext);
|
|
472
|
+
const size = CHROME.entityTileIconSize;
|
|
473
|
+
const contentId = iconContentId(iconDescriptor);
|
|
474
|
+
// Pure inline markup — a table here is block-level, so Gmail would break a
|
|
475
|
+
// mid-sentence tile onto its own line and leave an empty anchor stub behind.
|
|
476
|
+
const icon = `<img src="cid:${contentId}" alt="" width="${size}" height="${size}" style="display:inline-block;width:${size}px;height:${size}px;border:0;vertical-align:-3px;margin:0 10px 0 0">`;
|
|
448
477
|
return (
|
|
449
|
-
`<a href="${escapeAttr(href)}" target="_blank" style="
|
|
450
|
-
|
|
451
|
-
`<
|
|
452
|
-
`<td style="padding:0;vertical-align:middle;font-size:14px;line-height:18px;color:${COLOR.text};font-weight:650">${safeLabel}</td>` +
|
|
453
|
-
`</tr></table>` +
|
|
478
|
+
`<a href="${escapeAttr(href)}" target="_blank" style="${CHROME.entityTileCss};white-space:nowrap">` +
|
|
479
|
+
icon +
|
|
480
|
+
`<span style="font-size:${CHROME.entityTileFontSize}px;line-height:18px;color:${CHROME.entityTileText};font-weight:${CHROME.entityTileFontWeight}">${safeLabel}</span>` +
|
|
454
481
|
`</a>`
|
|
455
482
|
);
|
|
456
483
|
}
|
|
@@ -482,6 +509,9 @@ function renderEntityEmbed(mode, type, label, idOrRenderContext, maybeRenderCont
|
|
|
482
509
|
}
|
|
483
510
|
|
|
484
511
|
module.exports = {
|
|
512
|
+
resolveFileIconDescriptor,
|
|
513
|
+
resolveEntityIconDescriptor,
|
|
514
|
+
citationIconHtml,
|
|
485
515
|
mediaExtensionOf,
|
|
486
516
|
mediaMimeOf,
|
|
487
517
|
mediaKindOf,
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-aa-57534e-ffffff.png
ADDED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-nb-f37626-ffffff.png
ADDED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-letter-p-d24726-ffffff.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-calendarclock-d6d3d1.png
CHANGED
|
Binary file
|
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filearchive-facc15.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-fileimage-2dd4bf.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-fileimage-c084fc.png
CHANGED
|
Binary file
|
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-60a5fa.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-a8a29e.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-filetext-f87171.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-folder-d6d3d1.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-globe-d6d3d1.png
CHANGED
|
Binary file
|
package/runtime/scripts/amalgm-mcp/lib/email-icon-assets/amalgm-icon-lucide-video-f472b6.png
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "GENERATED — SVG source per CID icon; the .png files are rasters of exactly this markup.",
|
|
3
|
+
"icons": {
|
|
4
|
+
"amalgm-icon-letter-aa-57534e-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#57534E\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">Aa</text></svg>",
|
|
5
|
+
"amalgm-icon-letter-c-00599c-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#00599C\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"6.4\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">C++</text></svg>",
|
|
6
|
+
"amalgm-icon-letter-c-5c6bc0-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#5C6BC0\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">C</text></svg>",
|
|
7
|
+
"amalgm-icon-letter-c-68217a-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#68217A\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">C#</text></svg>",
|
|
8
|
+
"amalgm-icon-letter-go-00add8-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#00ADD8\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">GO</text></svg>",
|
|
9
|
+
"amalgm-icon-letter-j-e76f00-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#E76F00\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">J</text></svg>",
|
|
10
|
+
"amalgm-icon-letter-js-f7df1e-1c1917": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#F7DF1E\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#1c1917\">JS</text></svg>",
|
|
11
|
+
"amalgm-icon-letter-kt-7f52ff-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#7F52FF\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">KT</text></svg>",
|
|
12
|
+
"amalgm-icon-letter-nb-f37626-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#F37626\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">Nb</text></svg>",
|
|
13
|
+
"amalgm-icon-letter-p-d24726-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#D24726\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">P</text></svg>",
|
|
14
|
+
"amalgm-icon-letter-php-777bb4-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#777BB4\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"6.4\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">PHP</text></svg>",
|
|
15
|
+
"amalgm-icon-letter-rb-cc342d-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#CC342D\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">RB</text></svg>",
|
|
16
|
+
"amalgm-icon-letter-rs-ce4a1f-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#CE4A1F\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">RS</text></svg>",
|
|
17
|
+
"amalgm-icon-letter-s-cd6799-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#CD6799\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">S</text></svg>",
|
|
18
|
+
"amalgm-icon-letter-sw-f05138-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#F05138\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">SW</text></svg>",
|
|
19
|
+
"amalgm-icon-letter-ts-3178c6-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#3178C6\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">TS</text></svg>",
|
|
20
|
+
"amalgm-icon-letter-v-42b883-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" fill=\"#42B883\"></rect><text x=\"8\" y=\"11.6\" text-anchor=\"middle\" font-size=\"8\" font-weight=\"700\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\" fill=\"#ffffff\">V</text></svg>",
|
|
21
|
+
"amalgm-icon-lucide-atsign-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-white\" style=\"width:28px;height:28px\"><circle cx=\"12\" cy=\"12\" r=\"4\"></circle><path d=\"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8\"></path></svg>",
|
|
22
|
+
"amalgm-icon-lucide-box-d6d3d1": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d6d3d1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-300\" style=\"width:28px;height:28px\"><path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"></path><path d=\"m3.3 7 8.7 5 8.7-5\"></path><path d=\"M12 22V12\"></path></svg>",
|
|
23
|
+
"amalgm-icon-lucide-box-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-white\" style=\"width:28px;height:28px\"><path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"></path><path d=\"m3.3 7 8.7 5 8.7-5\"></path><path d=\"M12 22V12\"></path></svg>",
|
|
24
|
+
"amalgm-icon-lucide-braces-facc15": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#facc15\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-yellow-400\" style=\"width:28px;height:28px\"><path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\"></path><path d=\"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\"></path></svg>",
|
|
25
|
+
"amalgm-icon-lucide-braces-fb923c": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fb923c\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-orange-400\" style=\"width:28px;height:28px\"><path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\"></path><path d=\"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\"></path></svg>",
|
|
26
|
+
"amalgm-icon-lucide-calendarclock-d6d3d1": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d6d3d1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-300\" style=\"width:28px;height:28px\"><path d=\"M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5\"></path><path d=\"M16 2v4\"></path><path d=\"M8 2v4\"></path><path d=\"M3 10h5\"></path><path d=\"M17.5 17.5 16 16.25V14\"></path><path d=\"M22 16a6 6 0 1 1-12 0 6 6 0 0 1 12 0Z\"></path></svg>",
|
|
27
|
+
"amalgm-icon-lucide-database-60a5fa": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#60a5fa\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-blue-400\" style=\"width:28px;height:28px\"><ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\"></ellipse><path d=\"M3 5V19A9 3 0 0 0 21 19V5\"></path><path d=\"M3 12A9 3 0 0 0 21 12\"></path></svg>",
|
|
28
|
+
"amalgm-icon-lucide-externallink-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-white\" style=\"width:28px;height:28px\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path><polyline points=\"15 3 21 3 21 9\"></polyline><line x1=\"10\" x2=\"21\" y1=\"14\" y2=\"3\"></line></svg>",
|
|
29
|
+
"amalgm-icon-lucide-file-a8a29e": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#a8a29e\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline></svg>",
|
|
30
|
+
"amalgm-icon-lucide-filearchive-facc15": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#facc15\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-yellow-400\" style=\"width:28px;height:28px\"><path d=\"M4 22V4c0-.5.2-1 .6-1.4C5 2.2 5.5 2 6 2h8.5L20 7.5V20c0 .5-.2 1-.6 1.4-.4.4-.9.6-1.4.6h-2\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><circle cx=\"10\" cy=\"20\" r=\"2\"></circle><path d=\"M10 7V6\"></path><path d=\"M10 12v-1\"></path><path d=\"M10 18v-2\"></path></svg>",
|
|
31
|
+
"amalgm-icon-lucide-fileimage-2dd4bf": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#2dd4bf\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-teal-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><circle cx=\"10\" cy=\"13\" r=\"2\"></circle><path d=\"m20 17-1.09-1.09a2 2 0 0 0-2.82 0L10 22\"></path></svg>",
|
|
32
|
+
"amalgm-icon-lucide-fileimage-c084fc": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#c084fc\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-purple-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><circle cx=\"10\" cy=\"13\" r=\"2\"></circle><path d=\"m20 17-1.09-1.09a2 2 0 0 0-2.82 0L10 22\"></path></svg>",
|
|
33
|
+
"amalgm-icon-lucide-filespreadsheet-4ade80": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#4ade80\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-green-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><path d=\"M8 13h2\"></path><path d=\"M8 17h2\"></path><path d=\"M14 13h2\"></path><path d=\"M14 17h2\"></path></svg>",
|
|
34
|
+
"amalgm-icon-lucide-filetext-60a5fa": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#60a5fa\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-blue-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\"></line><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\"></line><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\"></line></svg>",
|
|
35
|
+
"amalgm-icon-lucide-filetext-a8a29e": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#a8a29e\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\"></line><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\"></line><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\"></line></svg>",
|
|
36
|
+
"amalgm-icon-lucide-filetext-f87171": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f87171\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-red-400\" style=\"width:28px;height:28px\"><path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\"></line><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\"></line><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\"></line></svg>",
|
|
37
|
+
"amalgm-icon-lucide-folder-d6d3d1": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d6d3d1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-300\" style=\"width:28px;height:28px\"><path d=\"M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z\"></path></svg>",
|
|
38
|
+
"amalgm-icon-lucide-globe-d6d3d1": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d6d3d1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-300\" style=\"width:28px;height:28px\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"2\" x2=\"22\" y1=\"12\" y2=\"12\"></line><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"></path></svg>",
|
|
39
|
+
"amalgm-icon-lucide-lock-facc15": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#facc15\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-yellow-400\" style=\"width:28px;height:28px\"><rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>",
|
|
40
|
+
"amalgm-icon-lucide-messagesquare-ffffff": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-white\" style=\"width:28px;height:28px\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path></svg>",
|
|
41
|
+
"amalgm-icon-lucide-music-f472b6": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f472b6\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-pink-400\" style=\"width:28px;height:28px\"><path d=\"M9 18V5l12-2v13\"></path><circle cx=\"6\" cy=\"18\" r=\"3\"></circle><circle cx=\"18\" cy=\"16\" r=\"3\"></circle></svg>",
|
|
42
|
+
"amalgm-icon-lucide-package-38bdf8": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#38bdf8\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-sky-400\" style=\"width:28px;height:28px\"><path d=\"m7.5 4.27 9 5.15\"></path><path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"></path><path d=\"m3.3 7 8.7 5 8.7-5\"></path><path d=\"M12 22V12\"></path></svg>",
|
|
43
|
+
"amalgm-icon-lucide-package-facc15": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#facc15\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-yellow-400\" style=\"width:28px;height:28px\"><path d=\"m7.5 4.27 9 5.15\"></path><path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"></path><path d=\"m3.3 7 8.7 5 8.7-5\"></path><path d=\"M12 22V12\"></path></svg>",
|
|
44
|
+
"amalgm-icon-lucide-settings-a8a29e": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#a8a29e\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-400\" style=\"width:28px;height:28px\"><path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"></path><circle cx=\"12\" cy=\"12\" r=\"3\"></circle></svg>",
|
|
45
|
+
"amalgm-icon-lucide-settings-d6d3d1": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d6d3d1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-stone-300\" style=\"width:28px;height:28px\"><path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"></path><circle cx=\"12\" cy=\"12\" r=\"3\"></circle></svg>",
|
|
46
|
+
"amalgm-icon-lucide-settings-f87171": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f87171\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-red-400\" style=\"width:28px;height:28px\"><path d=\"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z\"></path><circle cx=\"12\" cy=\"12\" r=\"3\"></circle></svg>",
|
|
47
|
+
"amalgm-icon-lucide-terminal-4ade80": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#4ade80\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-green-400\" style=\"width:28px;height:28px\"><polyline points=\"4 17 10 11 4 5\"></polyline><line x1=\"12\" x2=\"20\" y1=\"19\" y2=\"19\"></line></svg>",
|
|
48
|
+
"amalgm-icon-lucide-video-f472b6": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f472b6\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-pink-400\" style=\"width:28px;height:28px\"><path d=\"m22 8-6 4 6 4V8Z\"></path><rect width=\"14\" height=\"12\" x=\"2\" y=\"6\" rx=\"2\" ry=\"2\"></rect></svg>",
|
|
49
|
+
"amalgm-icon-lucide-zap-fbbf24": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fbbf24\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"text-amber-400\" style=\"width:28px;height:28px\"><polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"></polygon></svg>",
|
|
50
|
+
"amalgm-icon-path-css3-1572b6": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><path fill=\"#1572B6\" d=\"M1.5 0h21l-1.91 21.563L11.977 24l-8.565-2.438L1.5 0zm17.09 4.413L5.41 4.41l.213 2.622 10.125.002-.255 2.716h-6.64l.24 2.573h6.182l-.366 3.523-2.91.804-2.956-.81-.188-2.11h-2.61l.29 3.855L12 19.288l5.373-1.53L18.59 4.414z\"></path></svg>",
|
|
51
|
+
"amalgm-icon-path-html5-e34f26": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><path fill=\"#E34F26\" d=\"M1.5 0h21l-1.91 21.563L11.977 24l-8.564-2.438L1.5 0zm7.031 9.75l-.232-2.718 10.059.003.23-2.622L5.412 4.41l.698 8.01h9.126l-.326 3.426-2.91.804-2.955-.81-.188-2.11H6.248l.33 4.171L12 19.351l5.379-1.443.744-8.157H8.531z\"></path></svg>",
|
|
52
|
+
"amalgm-icon-path-markdown-a8a29e": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><path fill=\"#a8a29e\" d=\"M22.27 19.385H1.73A1.73 1.73 0 010 17.655V6.345a1.73 1.73 0 011.73-1.73h20.54A1.73 1.73 0 0124 6.345v11.308a1.73 1.73 0 01-1.73 1.732zM5.769 15.923v-4.5l2.308 2.885 2.307-2.885v4.5h2.308V8.078h-2.308l-2.307 2.885-2.308-2.885H3.46v7.847zM21.232 12h-2.309V8.077h-2.307V12h-2.308l3.461 4.039z\"></path></svg>",
|
|
53
|
+
"amalgm-icon-path-python-4b8bbe": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><path fill=\"#4B8BBE\" d=\"M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01z\"></path></svg>",
|
|
54
|
+
"amalgm-icon-react": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"-11.5 -10.23 23 20.46\" style=\"width:28px;height:28px\" aria-hidden=\"true\"><circle r=\"2.05\" fill=\"#61dafb\"></circle><g stroke=\"#61dafb\" stroke-width=\"1\" fill=\"none\"><ellipse rx=\"11\" ry=\"4.2\"></ellipse><ellipse rx=\"11\" ry=\"4.2\" transform=\"rotate(60)\"></ellipse><ellipse rx=\"11\" ry=\"4.2\" transform=\"rotate(120)\"></ellipse></g></svg>"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -2,6 +2,10 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
4
|
const ICON_ASSET_DIR = path.join(__dirname, 'email-icon-assets');
|
|
5
|
+
// The notify proxy rejects payloads with more than 8 attachments, so media +
|
|
6
|
+
// icons share that budget. Icons that don't fit are stripped from the HTML
|
|
7
|
+
// (stripUnattachedIconImages) and degrade to plain text — never broken-image
|
|
8
|
+
// boxes. Raising this requires raising the cap in api-proxy-v2 /notify first.
|
|
5
9
|
const MAX_TOTAL_ATTACHMENTS = 8;
|
|
6
10
|
|
|
7
11
|
function sanitizeId(value) {
|
|
@@ -50,4 +54,33 @@ function prepareEmailIconAttachments(html, existingAttachments = []) {
|
|
|
50
54
|
return attachments;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Remove icon <img> tags whose cid never made it into the attachment list
|
|
59
|
+
* (budget overflow or missing asset) — a missing icon must degrade to plain
|
|
60
|
+
* text, never a broken-image box.
|
|
61
|
+
*/
|
|
62
|
+
function stripUnattachedIconImages(html, attachments) {
|
|
63
|
+
const attached = new Set(attachments.map((attachment) => attachment.contentId));
|
|
64
|
+
return (
|
|
65
|
+
html
|
|
66
|
+
// Icon slot span wrapping only the cid image — drop the whole slot so
|
|
67
|
+
// no empty 12px gap survives.
|
|
68
|
+
.replace(
|
|
69
|
+
/<span style="[^"]*"><img [^>]*src="cid:(amalgm-icon-[a-z0-9-]+)"[^>]*><\/span>/gi,
|
|
70
|
+
(tag, contentId) => (attached.has(contentId) ? tag : ''),
|
|
71
|
+
)
|
|
72
|
+
// Pill/tile icon cell wrapping only the cid image — collapse the cell
|
|
73
|
+
// (keeping the pill's left padding) so no empty icon slot survives.
|
|
74
|
+
.replace(
|
|
75
|
+
/<td style="([^"]*)"><img [^>]*src="cid:(amalgm-icon-[a-z0-9-]+)"[^>]*><\/td>/gi,
|
|
76
|
+
(tag, tdStyle, contentId) =>
|
|
77
|
+
attached.has(contentId) ? tag : '<td style="padding:0 0 0 4px;width:0;font-size:0;line-height:0"></td>',
|
|
78
|
+
)
|
|
79
|
+
// Bare cid icon images (pills, tiles).
|
|
80
|
+
.replace(/<img [^>]*src="cid:(amalgm-icon-[a-z0-9-]+)"[^>]*>/gi, (tag, contentId) =>
|
|
81
|
+
attached.has(contentId) ? tag : '',
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { iconContentId, prepareEmailIconAttachments, stripUnattachedIconImages };
|