@digital-ai/dot-illustrations 2.0.33 → 2.0.35
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/.github/workflows/publish.yml +21 -10
- package/demo/demo.css +27 -0
- package/demo/github-upload.js +289 -0
- package/demo/index.html +158 -19
- package/demo/script.js +395 -120
- package/illustrations/dark/global/remote-cloud.svg +37 -0
- package/illustrations/light/global/remote-cloud.svg +37 -0
- package/index.css +8 -0
- package/package.json +1 -1
package/demo/script.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Make currentTab and root globally accessible
|
|
2
2
|
const root = document.documentElement;
|
|
3
|
-
let currentTab
|
|
3
|
+
let currentTab = 'all';
|
|
4
|
+
let alphabetFilter = ''; // '' = show all letters
|
|
4
5
|
|
|
5
6
|
function myFunction() {
|
|
6
7
|
var input, filter, divs, i, div, txtValue;
|
|
@@ -69,20 +70,18 @@ window.copyCode = function(button) {
|
|
|
69
70
|
const origCopyText = window.copyText;
|
|
70
71
|
window.copyText = function(button) {
|
|
71
72
|
var parentDiv = button.closest('.copy-container');
|
|
72
|
-
var
|
|
73
|
-
var
|
|
74
|
-
var
|
|
73
|
+
var idEl = parentDiv.querySelector('.iconID');
|
|
74
|
+
var itemId = idEl.textContent;
|
|
75
|
+
var isInteg = integrationsList && integrationsList.includes(itemId) && !globalList.concat(dashboardsList).includes(itemId);
|
|
76
|
+
var dotCode = isInteg
|
|
77
|
+
? `<span class="dot-integration"><img class="${itemId}"/></span>`
|
|
78
|
+
: `<DotIllustration illustrationId="${itemId}" />`;
|
|
75
79
|
navigator.clipboard.writeText(dotCode).then(function() {
|
|
76
80
|
var tooltip = button.querySelector('.tooltiptext');
|
|
77
81
|
tooltip.innerHTML = "Copied Dot Code";
|
|
78
82
|
tooltip.style.visibility = 'visible';
|
|
79
|
-
setTimeout(function() {
|
|
80
|
-
tooltip.innerHTML = "Copy Dot Code";
|
|
81
|
-
tooltip.style.visibility = 'hidden';
|
|
82
|
-
}, 2000);
|
|
83
|
+
setTimeout(function() { tooltip.innerHTML = "Copy Dot Code"; tooltip.style.visibility = 'hidden'; }, 2000);
|
|
83
84
|
showToast('Copied Dot Code: ' + dotCode);
|
|
84
|
-
}, function(err) {
|
|
85
|
-
console.error('Failed to copy dot code: ', err);
|
|
86
85
|
});
|
|
87
86
|
}
|
|
88
87
|
|
|
@@ -117,43 +116,54 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
117
116
|
const mainTabs = document.querySelectorAll('.tab-btn');
|
|
118
117
|
const floatingTabs = document.querySelectorAll('.floating-tab');
|
|
119
118
|
|
|
119
|
+
function updateTabUI(tab) {
|
|
120
|
+
[...mainTabs, ...floatingTabs].forEach(t => {
|
|
121
|
+
const isActive = t.dataset.tab === tab;
|
|
122
|
+
t.classList.toggle('text-blue-600', isActive);
|
|
123
|
+
t.classList.toggle('dark:text-blue-400', isActive);
|
|
124
|
+
t.classList.toggle('bg-blue-100', isActive);
|
|
125
|
+
t.classList.toggle('dark:bg-blue-900', isActive);
|
|
126
|
+
t.classList.toggle('text-gray-700', !isActive && t.dataset.tab !== 'upload');
|
|
127
|
+
t.classList.toggle('dark:text-gray-300', !isActive && t.dataset.tab !== 'upload');
|
|
128
|
+
t.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
function setTab(tab) {
|
|
121
133
|
currentTab = tab;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
alphabetFilter = '';
|
|
135
|
+
updateTabUI(tab);
|
|
136
|
+
|
|
137
|
+
const uploadPanel = document.getElementById('upload-panel');
|
|
138
|
+
const grid = document.getElementById('illustration-list');
|
|
139
|
+
const alphaStrip = document.getElementById('alphabet-strip');
|
|
140
|
+
const integNote = document.getElementById('integrations-note');
|
|
141
|
+
|
|
142
|
+
if (tab === 'upload') {
|
|
143
|
+
uploadPanel.classList.remove('hidden');
|
|
144
|
+
grid.classList.add('hidden');
|
|
145
|
+
alphaStrip.classList.add('hidden');
|
|
146
|
+
integNote.classList.add('hidden');
|
|
147
|
+
document.getElementById('result-count').textContent = '';
|
|
148
|
+
updateUploadAuthUI();
|
|
149
|
+
} else {
|
|
150
|
+
uploadPanel.classList.add('hidden');
|
|
151
|
+
grid.classList.remove('hidden');
|
|
152
|
+
// Show alphabet strip only for tabs that have many items
|
|
153
|
+
const showStrip = ['all','global','dashboards','integrations','favourites'].includes(tab);
|
|
154
|
+
alphaStrip.classList.toggle('hidden', !showStrip);
|
|
155
|
+
integNote.classList.toggle('hidden', tab !== 'integrations');
|
|
156
|
+
renderAlphabetStrip();
|
|
157
|
+
renderIllustrations();
|
|
158
|
+
}
|
|
145
159
|
}
|
|
146
160
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
setTab(this.dataset.tab);
|
|
161
|
+
function wireTabs() {
|
|
162
|
+
document.querySelectorAll('.tab-btn').forEach(tab => {
|
|
163
|
+
tab.addEventListener('click', function() { setTab(this.dataset.tab); });
|
|
150
164
|
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
tab.addEventListener('click', function() {
|
|
154
|
-
setTab(this.dataset.tab);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
165
|
+
}
|
|
166
|
+
wireTabs();
|
|
157
167
|
|
|
158
168
|
// --- ILLUSTRATION DATA ---
|
|
159
169
|
const globalList = [
|
|
@@ -191,6 +201,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
191
201
|
"nothing-defined",
|
|
192
202
|
"password-token",
|
|
193
203
|
"protection-in-progress",
|
|
204
|
+
"remote-cloud",
|
|
194
205
|
"reports","scan-document",
|
|
195
206
|
"releases",
|
|
196
207
|
"survey",
|
|
@@ -228,7 +239,28 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
228
239
|
"data-extraction",
|
|
229
240
|
"workflow"
|
|
230
241
|
];
|
|
231
|
-
const illustrations = [...globalList, ...dashboardsList
|
|
242
|
+
const illustrations = [...globalList, ...dashboardsList];
|
|
243
|
+
|
|
244
|
+
const integrationsList = [
|
|
245
|
+
"agility","amazon-eks","ansible","apache-tomcat","app-aware","app-dynamics",
|
|
246
|
+
"app-management","application-protection","aras","arc-sight","argocd","atlassian",
|
|
247
|
+
"avaya","aws","azure","azure-aks-2","azure-devops-tfs","azure-functions",
|
|
248
|
+
"bamboo","bit-bucket","biztalk","black-duck","blazemeter","bmc-helix",
|
|
249
|
+
"checkmarx","chef","chrome","cisco","citrix","clarity-ppm","cloud-foundry",
|
|
250
|
+
"continuostesting","cyberark","dai-logo","delphix","deploy","docker","docker-compose",
|
|
251
|
+
"dynatrace","edge","essential-app-protection","explorer","f5","firefox",
|
|
252
|
+
"flux-cd","fortify","fortify-on-demand","free-marker","git-ops","github",
|
|
253
|
+
"github-actions","gitlab","google","google-cloud","google-cloud-functions",
|
|
254
|
+
"hashi-corp-vault","helm","ibm","ingress","inteligence","jboss","jenkins",
|
|
255
|
+
"jfrog","jira","key","kubernetes","linux","mailhog","microsoft-iis",
|
|
256
|
+
"microsoft-teams","mysql","netscaler","new-relic","octopus-deploy",
|
|
257
|
+
"open-policy-agent","openid","openshift","opsgenie","oracle","parasoft",
|
|
258
|
+
"pendo","planview","podman","powershell","progress-chef","puppet","python",
|
|
259
|
+
"rabbitmq","release","safari","salesforce","servicenow","skytab","slack",
|
|
260
|
+
"sonarcloud","sonarqube","sonatype","svn","team-forge","teamcity","terraform",
|
|
261
|
+
"testlink","topaz","travis-ci","urbancode-deploy","vmware","webhook",
|
|
262
|
+
"windows","xray","zendesk",
|
|
263
|
+
];
|
|
232
264
|
|
|
233
265
|
// --- FAVOURITES LOGIC ---
|
|
234
266
|
function getFavourites() {
|
|
@@ -270,43 +302,44 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
270
302
|
const modalClose = document.getElementById('modal-close');
|
|
271
303
|
const modalCloseBottom = document.getElementById('modal-close-bottom');
|
|
272
304
|
|
|
273
|
-
function openModal(
|
|
305
|
+
function openModal(item, type) {
|
|
274
306
|
if (modalDescription) modalDescription.innerHTML = '';
|
|
275
307
|
if (!descriptionsLoaded) return;
|
|
308
|
+
|
|
276
309
|
const themeClass = root.classList.contains('dark') ? 'dark' : 'light';
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
310
|
+
const isInteg = type === 'integration' || integrationsList.includes(item) && !illustrations.includes(item);
|
|
311
|
+
|
|
312
|
+
let imgHtml, dotCodeString, codeString;
|
|
313
|
+
if (isInteg) {
|
|
314
|
+
imgHtml = `<span class="dot-integration" style="display:inline-flex;align-items:center;justify-content:center;width:200px;height:200px;"><img class="${item}" style="width:100%;height:100%;object-fit:contain;"/></span>`;
|
|
315
|
+
dotCodeString = `<span class="dot-integration"><img class="${item}"/></span>`;
|
|
316
|
+
codeString = dotCodeString;
|
|
317
|
+
} else {
|
|
318
|
+
const cat = globalList.includes(item) ? 'global' : 'dashboards';
|
|
319
|
+
const svgPath = `illustrations/${themeClass}/${cat}/${item}.svg`;
|
|
320
|
+
imgHtml = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}" style="width:286px;height:286px;object-fit:contain;"/></span>`;
|
|
321
|
+
dotCodeString = `<DotIllustration illustrationId="${item}" />`;
|
|
322
|
+
codeString = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>`;
|
|
282
323
|
}
|
|
283
|
-
|
|
284
|
-
modalImage.innerHTML =
|
|
285
|
-
// Set the illustration name
|
|
324
|
+
|
|
325
|
+
modalImage.innerHTML = imgHtml;
|
|
286
326
|
const modalIllustrationName = document.getElementById('modal-illustration-name');
|
|
287
|
-
if (modalIllustrationName) modalIllustrationName.textContent =
|
|
288
|
-
// Set the Dot Code textarea value
|
|
289
|
-
const dotCodeString = `<DotIllustration illustrationId=\"${illustration}\" />`;
|
|
327
|
+
if (modalIllustrationName) modalIllustrationName.textContent = item;
|
|
290
328
|
const modalDotCode = document.getElementById('modal-dot-code');
|
|
291
329
|
if (modalDotCode) modalDotCode.value = dotCodeString;
|
|
292
|
-
// Show the HTML code snippet in the modal
|
|
293
|
-
const codeString = `<span class=\"dot-illustration\"><img src=\"${svgPath}\" class=\"${illustration} ${themeClass}\"/></span>`;
|
|
294
330
|
modalCode.value = codeString;
|
|
331
|
+
|
|
295
332
|
modal.classList.add('active');
|
|
296
333
|
modal.classList.remove('hidden');
|
|
297
|
-
|
|
334
|
+
|
|
298
335
|
const modalCopyDotCode = document.getElementById('modal-copy-dot-code');
|
|
299
336
|
if (modalCopyDotCode) {
|
|
300
|
-
modalCopyDotCode.onclick =
|
|
337
|
+
modalCopyDotCode.onclick = () => {
|
|
301
338
|
if (modalDotCode) {
|
|
302
|
-
navigator.clipboard.writeText(modalDotCode.value).then(
|
|
339
|
+
navigator.clipboard.writeText(modalDotCode.value).then(() => {
|
|
303
340
|
modalCopyDotCode.textContent = 'Copied!';
|
|
304
341
|
showToast('Copied Dot Code: ' + modalDotCode.value);
|
|
305
|
-
setTimeout(() => {
|
|
306
|
-
modalCopyDotCode.textContent = 'Copy Dot Code';
|
|
307
|
-
}, 2000);
|
|
308
|
-
}, function(err) {
|
|
309
|
-
console.error('Failed to copy dot code: ', err);
|
|
342
|
+
setTimeout(() => { modalCopyDotCode.textContent = 'Copy Dot Code'; }, 2000);
|
|
310
343
|
});
|
|
311
344
|
}
|
|
312
345
|
};
|
|
@@ -325,75 +358,139 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
325
358
|
showToast('Copied code: ' + modalCode.value);
|
|
326
359
|
});
|
|
327
360
|
|
|
328
|
-
// ---
|
|
361
|
+
// --- ALPHABET STRIP ---
|
|
362
|
+
function renderAlphabetStrip() {
|
|
363
|
+
const strip = document.getElementById('alphabet-strip');
|
|
364
|
+
if (!strip) return;
|
|
365
|
+
|
|
366
|
+
const pool = getCurrentPool('');
|
|
367
|
+
const available = new Set(pool.map(id => id[0].toUpperCase()).filter(c => /[A-Z]/.test(c)));
|
|
368
|
+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
|
369
|
+
|
|
370
|
+
strip.innerHTML = `
|
|
371
|
+
<button class="alpha-btn px-2 py-0.5 text-xs rounded font-mono ${alphabetFilter === '' ? 'bg-blue-600 text-white' : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'} transition" data-letter="">All</button>
|
|
372
|
+
${letters.map(l => `
|
|
373
|
+
<button class="alpha-btn px-2 py-0.5 text-xs rounded font-mono ${
|
|
374
|
+
available.has(l)
|
|
375
|
+
? alphabetFilter === l
|
|
376
|
+
? 'bg-blue-600 text-white'
|
|
377
|
+
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-blue-100 dark:hover:bg-blue-800 transition'
|
|
378
|
+
: 'opacity-30 cursor-default bg-gray-100 dark:bg-gray-800 text-gray-400'
|
|
379
|
+
}" data-letter="${l}" ${available.has(l) ? '' : 'disabled'}>${l}</button>
|
|
380
|
+
`).join('')}
|
|
381
|
+
`;
|
|
382
|
+
strip.querySelectorAll('.alpha-btn:not([disabled])').forEach(btn => {
|
|
383
|
+
btn.addEventListener('click', () => {
|
|
384
|
+
alphabetFilter = btn.dataset.letter;
|
|
385
|
+
renderAlphabetStrip();
|
|
386
|
+
renderIllustrations();
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function getCurrentPool(filterOverride) {
|
|
392
|
+
const f = filterOverride !== undefined ? filterOverride : alphabetFilter;
|
|
393
|
+
let base = [];
|
|
394
|
+
if (currentTab === 'all') base = illustrations;
|
|
395
|
+
else if (currentTab === 'global') base = globalList;
|
|
396
|
+
else if (currentTab === 'dashboards') base = dashboardsList;
|
|
397
|
+
else if (currentTab === 'integrations') base = integrationsList;
|
|
398
|
+
else if (currentTab === 'favourites') base = [...illustrations, ...integrationsList].filter(id => getFavourites().includes(id));
|
|
399
|
+
if (f) base = base.filter(id => id[0].toUpperCase() === f);
|
|
400
|
+
return base;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// --- ILLUSTRATION + INTEGRATION RENDERING ---
|
|
329
404
|
function renderIllustrations() {
|
|
330
405
|
const list = document.getElementById("illustration-list");
|
|
331
406
|
list.innerHTML = "";
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
toShow = dashboardsList;
|
|
339
|
-
} else if (currentTab === 'favourites') {
|
|
340
|
-
const favs = getFavourites();
|
|
341
|
-
toShow = illustrations.filter(id => favs.includes(id));
|
|
342
|
-
}
|
|
343
|
-
const filter = (document.getElementById('myInput')?.value || '').toUpperCase();
|
|
344
|
-
toShow = toShow.filter(id => id.toUpperCase().includes(filter));
|
|
407
|
+
const searchFilter = (document.getElementById('myInput')?.value || '').toUpperCase();
|
|
408
|
+
let toShow = getCurrentPool().filter(id => id.toUpperCase().includes(searchFilter));
|
|
409
|
+
|
|
410
|
+
const countEl = document.getElementById('result-count');
|
|
411
|
+
if (countEl) countEl.textContent = toShow.length > 0 ? `${toShow.length} item${toShow.length === 1 ? '' : 's'}` : '';
|
|
412
|
+
|
|
345
413
|
if (toShow.length === 0) {
|
|
346
|
-
list.innerHTML =
|
|
414
|
+
list.innerHTML = `<div class="col-span-full text-center text-gray-500 dark:text-gray-400 py-8">${
|
|
415
|
+
currentTab === 'favourites' ? 'No favourites yet.' : 'No items found.'
|
|
416
|
+
}</div>`;
|
|
347
417
|
return;
|
|
348
418
|
}
|
|
419
|
+
|
|
420
|
+
const isIntegrations = currentTab === 'integrations' ||
|
|
421
|
+
(currentTab === 'favourites' && toShow.every(id => integrationsList.includes(id)));
|
|
349
422
|
const favs = getFavourites();
|
|
350
423
|
const themeClass = root.classList.contains('dark') ? 'dark' : 'light';
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="${isFav ? 'gold' : 'none'}" viewBox="0 0 24 24" stroke="gold">
|
|
367
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/>
|
|
368
|
-
</svg>
|
|
369
|
-
</button>
|
|
370
|
-
<div class="flex-1 flex flex-col justify-center items-center">
|
|
371
|
-
<span class="dot-illustration">
|
|
372
|
-
<img src="${svgPath}" class="${illustration} ${themeClass}"/>
|
|
373
|
-
</span>
|
|
374
|
-
<span class="iconID block text-center text-base font-medium text-gray-800 dark:text-gray-200 my-2">${illustration}</span>
|
|
375
|
-
</div>
|
|
376
|
-
<div class="button-group flex flex-row items-center justify-center gap-2 mt-2">
|
|
377
|
-
<button id="CopyID" class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyText(this)">
|
|
378
|
-
Copy Dot Code
|
|
379
|
-
<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Dot Code</span>
|
|
424
|
+
|
|
425
|
+
toShow.forEach(item => {
|
|
426
|
+
const isInteg = integrationsList.includes(item) && !illustrations.includes(item);
|
|
427
|
+
const isFav = favs.includes(item);
|
|
428
|
+
|
|
429
|
+
if (isInteg) {
|
|
430
|
+
// Integration card (single SVG, dot-integration wrapper)
|
|
431
|
+
const codeString = `<span class="dot-integration"><img class="${item}"/></span>`;
|
|
432
|
+
const div = document.createElement('div');
|
|
433
|
+
div.setAttribute('class', 'copy-container relative group flex flex-col items-center justify-between bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg p-2 md:p-3 transition-transform duration-200 hover:scale-105 hover:shadow-2xl h-[302px] w-full');
|
|
434
|
+
div.dataset.itemId = item;
|
|
435
|
+
div.dataset.itemType = 'integration';
|
|
436
|
+
div.innerHTML = `
|
|
437
|
+
<button class="absolute top-2 right-2 z-10 p-1 rounded-full bg-white/80 dark:bg-gray-800/80 hover:bg-yellow-100 dark:hover:bg-yellow-300 transition" title="Toggle favourite" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
|
|
438
|
+
<svg class="h-5 w-5" fill="${isFav ? 'gold' : 'none'}" viewBox="0 0 24 24" stroke="gold"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
|
|
380
439
|
</button>
|
|
381
|
-
<
|
|
382
|
-
|
|
383
|
-
<span class="
|
|
440
|
+
<div class="flex-1 flex flex-col justify-center items-center">
|
|
441
|
+
<span class="dot-integration flex items-center justify-center" style="width:160px;height:160px;"><img class="${item}" style="width:100%;height:100%;object-fit:contain;"/></span>
|
|
442
|
+
<span class="iconID block text-center text-base font-medium text-gray-800 dark:text-gray-200 my-2">${item}</span>
|
|
443
|
+
</div>
|
|
444
|
+
<div class="button-group flex flex-row items-center justify-center gap-2 mt-2">
|
|
445
|
+
<button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyText(this)">
|
|
446
|
+
Copy Dot Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Dot Code</span>
|
|
447
|
+
</button>
|
|
448
|
+
<button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyCode(this)">
|
|
449
|
+
Copy Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Code</span>
|
|
450
|
+
</button>
|
|
451
|
+
</div>
|
|
452
|
+
<pre class="codeBlock"><code class="codeBlock">${codeString}</code></pre>
|
|
453
|
+
`;
|
|
454
|
+
list.appendChild(div);
|
|
455
|
+
} else {
|
|
456
|
+
// Illustration card (light/dark, dot-illustration wrapper)
|
|
457
|
+
let categoryFolder = globalList.includes(item) ? 'global' : 'dashboards';
|
|
458
|
+
const svgPath = `illustrations/${themeClass}/${categoryFolder}/${item}.svg`;
|
|
459
|
+
const codeString = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>`;
|
|
460
|
+
const div = document.createElement('div');
|
|
461
|
+
div.setAttribute('class', 'copy-container relative group flex flex-col items-center justify-between bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg p-2 md:p-3 transition-transform duration-200 hover:scale-105 hover:shadow-2xl h-[302px] w-full');
|
|
462
|
+
div.dataset.itemId = item;
|
|
463
|
+
div.dataset.itemType = 'illustration';
|
|
464
|
+
div.innerHTML = `
|
|
465
|
+
<button class="absolute top-2 right-2 z-10 p-1 rounded-full bg-white/80 dark:bg-gray-800/80 hover:bg-yellow-100 dark:hover:bg-yellow-300 transition" title="Toggle favourite" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
|
|
466
|
+
<svg class="h-5 w-5" fill="${isFav ? 'gold' : 'none'}" viewBox="0 0 24 24" stroke="gold"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
|
|
384
467
|
</button>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
468
|
+
<div class="flex-1 flex flex-col justify-center items-center">
|
|
469
|
+
<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>
|
|
470
|
+
<span class="iconID block text-center text-base font-medium text-gray-800 dark:text-gray-200 my-2">${item}</span>
|
|
471
|
+
</div>
|
|
472
|
+
<div class="button-group flex flex-row items-center justify-center gap-2 mt-2">
|
|
473
|
+
<button id="CopyID" class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyText(this)">
|
|
474
|
+
Copy Dot Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Dot Code</span>
|
|
475
|
+
</button>
|
|
476
|
+
<button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyCode(this)">
|
|
477
|
+
Copy Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Code</span>
|
|
478
|
+
</button>
|
|
479
|
+
</div>
|
|
480
|
+
<pre class="codeBlock"><code class="codeBlock">${codeString}</code></pre>
|
|
481
|
+
`;
|
|
482
|
+
list.appendChild(div);
|
|
483
|
+
}
|
|
389
484
|
});
|
|
390
|
-
|
|
485
|
+
|
|
486
|
+
// Modal click on each card
|
|
391
487
|
document.querySelectorAll('.copy-container').forEach(card => {
|
|
392
488
|
card.addEventListener('click', function(e) {
|
|
393
489
|
if (e.target.closest('button')) return;
|
|
394
|
-
if (!descriptionsLoaded) return;
|
|
395
|
-
const id
|
|
396
|
-
|
|
490
|
+
if (!descriptionsLoaded) return;
|
|
491
|
+
const id = this.dataset.itemId || this.querySelector('.iconID')?.textContent;
|
|
492
|
+
const type = this.dataset.itemType;
|
|
493
|
+
if (id) openModal(id, type);
|
|
397
494
|
});
|
|
398
495
|
});
|
|
399
496
|
}
|
|
@@ -409,6 +506,183 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
409
506
|
document.getElementById('myInput').value = '';
|
|
410
507
|
document.getElementById('floatingInput').value = '';
|
|
411
508
|
|
|
509
|
+
// ── GitHub auth ──────────────────────────────────────────────────────────
|
|
510
|
+
function updateAuthBadge(user) {
|
|
511
|
+
const btn = document.getElementById('gh-connect-btn');
|
|
512
|
+
const badge = document.getElementById('gh-user-badge');
|
|
513
|
+
const name = document.getElementById('gh-user-name');
|
|
514
|
+
if (user) {
|
|
515
|
+
btn.classList.add('hidden');
|
|
516
|
+
badge.classList.remove('hidden');
|
|
517
|
+
badge.style.display = 'flex';
|
|
518
|
+
name.textContent = `@${user.login}`;
|
|
519
|
+
localStorage.setItem('gh_illus_user', JSON.stringify(user));
|
|
520
|
+
} else {
|
|
521
|
+
btn.classList.remove('hidden');
|
|
522
|
+
badge.style.display = 'none';
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function updateUploadAuthUI() {
|
|
527
|
+
const token = window.GitHubUpload?.getToken?.();
|
|
528
|
+
['upload-illus-auth-gate','upload-integ-auth-gate'].forEach(id => {
|
|
529
|
+
document.getElementById(id)?.classList.toggle('hidden', !!token);
|
|
530
|
+
});
|
|
531
|
+
['upload-illus-form','upload-integ-form'].forEach(id => {
|
|
532
|
+
document.getElementById(id)?.classList.toggle('hidden', !token);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async function tryDeviceFlow() {
|
|
537
|
+
const modal = document.getElementById('gh-device-modal');
|
|
538
|
+
modal.classList.remove('hidden');
|
|
539
|
+
document.getElementById('gh-device-step-code').classList.remove('hidden');
|
|
540
|
+
document.getElementById('gh-device-step-pat').classList.add('hidden');
|
|
541
|
+
document.getElementById('gh-device-error').classList.add('hidden');
|
|
542
|
+
try {
|
|
543
|
+
const { user_code, verification_uri, device_code, expires_in, interval } =
|
|
544
|
+
await window.GitHubUpload.startDeviceFlow();
|
|
545
|
+
document.getElementById('gh-device-uri').href = verification_uri;
|
|
546
|
+
document.getElementById('gh-device-uri').textContent = verification_uri;
|
|
547
|
+
document.getElementById('gh-device-code').textContent = user_code;
|
|
548
|
+
document.getElementById('gh-copy-code-btn').onclick = () =>
|
|
549
|
+
navigator.clipboard.writeText(user_code).then(() => showToast('Code copied!'));
|
|
550
|
+
const token = await window.GitHubUpload.pollForToken(device_code, interval || 5);
|
|
551
|
+
window.GitHubUpload.setToken(token);
|
|
552
|
+
const user = await window.GitHubUpload.getUser();
|
|
553
|
+
updateAuthBadge(user);
|
|
554
|
+
modal.classList.add('hidden');
|
|
555
|
+
updateUploadAuthUI();
|
|
556
|
+
showToast(`Connected as @${user.login}`);
|
|
557
|
+
} catch (err) {
|
|
558
|
+
if (err.message === 'NO_CLIENT_ID' || err.name === 'TypeError') {
|
|
559
|
+
document.getElementById('gh-device-step-code').classList.add('hidden');
|
|
560
|
+
document.getElementById('gh-device-step-pat').classList.remove('hidden');
|
|
561
|
+
} else {
|
|
562
|
+
document.getElementById('gh-device-error').textContent = err.message;
|
|
563
|
+
document.getElementById('gh-device-error').classList.remove('hidden');
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
document.getElementById('gh-connect-btn')?.addEventListener('click', tryDeviceFlow);
|
|
569
|
+
document.getElementById('gh-logout-btn')?.addEventListener('click', () => {
|
|
570
|
+
window.GitHubUpload?.clearToken?.();
|
|
571
|
+
updateAuthBadge(null);
|
|
572
|
+
updateUploadAuthUI();
|
|
573
|
+
showToast('Disconnected from GitHub');
|
|
574
|
+
});
|
|
575
|
+
document.getElementById('gh-device-close')?.addEventListener('click', () => {
|
|
576
|
+
document.getElementById('gh-device-modal').classList.add('hidden');
|
|
577
|
+
});
|
|
578
|
+
document.getElementById('gh-pat-submit')?.addEventListener('click', async () => {
|
|
579
|
+
const pat = document.getElementById('gh-pat-input').value.trim();
|
|
580
|
+
if (!pat) return;
|
|
581
|
+
window.GitHubUpload.setToken(pat);
|
|
582
|
+
try {
|
|
583
|
+
const user = await window.GitHubUpload.getUser();
|
|
584
|
+
updateAuthBadge(user);
|
|
585
|
+
document.getElementById('gh-device-modal').classList.add('hidden');
|
|
586
|
+
updateUploadAuthUI();
|
|
587
|
+
showToast(`Connected as @${user.login}`);
|
|
588
|
+
} catch {
|
|
589
|
+
document.getElementById('gh-device-error').textContent = 'Invalid token.';
|
|
590
|
+
document.getElementById('gh-device-error').classList.remove('hidden');
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Restore session
|
|
595
|
+
const savedUser = localStorage.getItem('gh_illus_user');
|
|
596
|
+
if (window.GitHubUpload?.getToken?.() && savedUser) {
|
|
597
|
+
try { updateAuthBadge(JSON.parse(savedUser)); } catch {}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// ── Upload panel ─────────────────────────────────────────────────────────
|
|
601
|
+
const uploadBufs = { illusLight: null, illusDark: null, integSvg: null };
|
|
602
|
+
|
|
603
|
+
function bindFileDrop(dropId, inputId, nameId, bufKey) {
|
|
604
|
+
const drop = document.getElementById(dropId);
|
|
605
|
+
const input = document.getElementById(inputId);
|
|
606
|
+
const nameEl = document.getElementById(nameId);
|
|
607
|
+
if (!drop || !input) return;
|
|
608
|
+
drop.addEventListener('click', () => input.click());
|
|
609
|
+
drop.addEventListener('dragover', e => { e.preventDefault(); drop.classList.add('border-blue-400'); });
|
|
610
|
+
drop.addEventListener('dragleave', () => drop.classList.remove('border-blue-400'));
|
|
611
|
+
drop.addEventListener('drop', e => { e.preventDefault(); drop.classList.remove('border-blue-400'); handleFile(e.dataTransfer.files[0], bufKey, nameEl, drop); });
|
|
612
|
+
input.addEventListener('change', () => handleFile(input.files[0], bufKey, nameEl, drop));
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function handleFile(file, bufKey, nameEl, drop) {
|
|
616
|
+
if (!file || !file.name.endsWith('.svg')) { showToast('Please select an SVG file'); return; }
|
|
617
|
+
const reader = new FileReader();
|
|
618
|
+
reader.onload = e => {
|
|
619
|
+
uploadBufs[bufKey] = e.target.result;
|
|
620
|
+
if (nameEl) { nameEl.textContent = `✓ ${file.name}`; nameEl.classList.remove('hidden'); }
|
|
621
|
+
drop.classList.add('border-green-400', 'dark:border-green-600');
|
|
622
|
+
drop.classList.remove('border-gray-300', 'dark:border-gray-600');
|
|
623
|
+
};
|
|
624
|
+
reader.readAsArrayBuffer(file);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
bindFileDrop('illus-light-drop', 'illus-light-input', 'illus-light-name', 'illusLight');
|
|
628
|
+
bindFileDrop('illus-dark-drop', 'illus-dark-input', 'illus-dark-name', 'illusDark');
|
|
629
|
+
bindFileDrop('integ-svg-drop', 'integ-svg-input', 'integ-svg-name', 'integSvg');
|
|
630
|
+
|
|
631
|
+
async function handleIllusUpload() {
|
|
632
|
+
const id = document.getElementById('upload-illus-id')?.value.trim();
|
|
633
|
+
const cat = document.getElementById('upload-illus-category')?.value;
|
|
634
|
+
const btn = document.getElementById('upload-illus-btn');
|
|
635
|
+
const status = document.getElementById('upload-illus-status');
|
|
636
|
+
const prLink = document.getElementById('upload-illus-pr-link');
|
|
637
|
+
if (!id) { showToast('Enter illustration ID'); return; }
|
|
638
|
+
if (!uploadBufs.illusLight) { showToast('Select the light SVG'); return; }
|
|
639
|
+
if (!uploadBufs.illusDark) { showToast('Select the dark SVG'); return; }
|
|
640
|
+
if (!window.GitHubUpload?.getToken?.()) { showToast('Connect GitHub first'); return; }
|
|
641
|
+
btn.disabled = true; btn.textContent = 'Creating PR…';
|
|
642
|
+
status.classList.add('hidden'); prLink.classList.add('hidden');
|
|
643
|
+
try {
|
|
644
|
+
const url = await window.GitHubUpload.createIllustrationPR(id, cat, uploadBufs.illusLight, uploadBufs.illusDark);
|
|
645
|
+
status.textContent = 'PR created!';
|
|
646
|
+
status.className = 'text-sm text-center text-green-600 dark:text-green-400';
|
|
647
|
+
status.classList.remove('hidden');
|
|
648
|
+
document.getElementById('upload-illus-pr-anchor').href = url;
|
|
649
|
+
prLink.classList.remove('hidden');
|
|
650
|
+
showToast('PR created!');
|
|
651
|
+
} catch (err) {
|
|
652
|
+
status.textContent = `Error: ${err.message}`;
|
|
653
|
+
status.className = 'text-sm text-center text-red-600 dark:text-red-400';
|
|
654
|
+
status.classList.remove('hidden');
|
|
655
|
+
} finally { btn.disabled = false; btn.textContent = 'Create PR'; }
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
async function handleIntegUpload() {
|
|
659
|
+
const id = document.getElementById('upload-integ-id')?.value.trim();
|
|
660
|
+
const btn = document.getElementById('upload-integ-btn');
|
|
661
|
+
const status = document.getElementById('upload-integ-status');
|
|
662
|
+
const prLink = document.getElementById('upload-integ-pr-link');
|
|
663
|
+
if (!id) { showToast('Enter integration ID'); return; }
|
|
664
|
+
if (!uploadBufs.integSvg) { showToast('Select an SVG file'); return; }
|
|
665
|
+
if (!window.GitHubUpload?.getToken?.()) { showToast('Connect GitHub first'); return; }
|
|
666
|
+
btn.disabled = true; btn.textContent = 'Creating PR…';
|
|
667
|
+
status.classList.add('hidden'); prLink.classList.add('hidden');
|
|
668
|
+
try {
|
|
669
|
+
const url = await window.GitHubUpload.createIntegrationPR(id, uploadBufs.integSvg);
|
|
670
|
+
status.textContent = 'PR created!';
|
|
671
|
+
status.className = 'text-sm text-center text-green-600 dark:text-green-400';
|
|
672
|
+
status.classList.remove('hidden');
|
|
673
|
+
document.getElementById('upload-integ-pr-anchor').href = url;
|
|
674
|
+
prLink.classList.remove('hidden');
|
|
675
|
+
showToast('PR created!');
|
|
676
|
+
} catch (err) {
|
|
677
|
+
status.textContent = `Error: ${err.message}`;
|
|
678
|
+
status.className = 'text-sm text-center text-red-600 dark:text-red-400';
|
|
679
|
+
status.classList.remove('hidden');
|
|
680
|
+
} finally { btn.disabled = false; btn.textContent = 'Create PR'; }
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
document.getElementById('upload-illus-btn')?.addEventListener('click', handleIllusUpload);
|
|
684
|
+
document.getElementById('upload-integ-btn')?.addEventListener('click', handleIntegUpload);
|
|
685
|
+
|
|
412
686
|
// Set initial tab state to 'all' and update UI (this will also render illustrations)
|
|
413
687
|
setTab('all');
|
|
414
688
|
|
|
@@ -445,6 +719,7 @@ function getSuggestions(query) {
|
|
|
445
719
|
if (currentTab === 'all') pool = illustrations;
|
|
446
720
|
else if (currentTab === 'global') pool = globalList;
|
|
447
721
|
else if (currentTab === 'dashboards') pool = dashboardsList;
|
|
722
|
+
else if (currentTab === 'integrations') pool = integrationsList;
|
|
448
723
|
else if (currentTab === 'favourites') pool = getFavourites();
|
|
449
724
|
// Fuzzy match, sort by closeness (shorter index of first match, then length)
|
|
450
725
|
let scored = pool
|