@ytspar/devbar 1.7.5 → 1.8.2
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/dist/GlobalDevBar.d.ts +4 -2
- package/dist/GlobalDevBar.d.ts.map +1 -1
- package/dist/GlobalDevBar.js +22 -9
- package/dist/GlobalDevBar.js.map +1 -1
- package/dist/accessibility.js +2 -2
- package/dist/accessibility.js.map +1 -1
- package/dist/constants.d.ts +9 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +13 -1
- package/dist/constants.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/modules/index.d.ts +2 -2
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +2 -2
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/rendering/buttons.d.ts.map +1 -1
- package/dist/modules/rendering/buttons.js +3 -3
- package/dist/modules/rendering/buttons.js.map +1 -1
- package/dist/modules/rendering/collapsed.js +2 -2
- package/dist/modules/rendering/collapsed.js.map +1 -1
- package/dist/modules/rendering/common.d.ts +9 -0
- package/dist/modules/rendering/common.d.ts.map +1 -1
- package/dist/modules/rendering/common.js +52 -1
- package/dist/modules/rendering/common.js.map +1 -1
- package/dist/modules/rendering/compact.d.ts +2 -1
- package/dist/modules/rendering/compact.d.ts.map +1 -1
- package/dist/modules/rendering/compact.js +11 -4
- package/dist/modules/rendering/compact.js.map +1 -1
- package/dist/modules/rendering/console.d.ts.map +1 -1
- package/dist/modules/rendering/console.js +6 -2
- package/dist/modules/rendering/console.js.map +1 -1
- package/dist/modules/rendering/expanded.d.ts.map +1 -1
- package/dist/modules/rendering/expanded.js +3 -54
- package/dist/modules/rendering/expanded.js.map +1 -1
- package/dist/modules/rendering/index.d.ts.map +1 -1
- package/dist/modules/rendering/index.js +3 -3
- package/dist/modules/rendering/index.js.map +1 -1
- package/dist/modules/rendering/modals.d.ts.map +1 -1
- package/dist/modules/rendering/modals.js +264 -252
- package/dist/modules/rendering/modals.js.map +1 -1
- package/dist/modules/rendering/settings.d.ts.map +1 -1
- package/dist/modules/rendering/settings.js +41 -34
- package/dist/modules/rendering/settings.js.map +1 -1
- package/dist/modules/ruler.d.ts.map +1 -1
- package/dist/modules/ruler.js.map +1 -1
- package/dist/modules/screenshot.d.ts.map +1 -1
- package/dist/modules/screenshot.js +23 -5
- package/dist/modules/screenshot.js.map +1 -1
- package/dist/modules/theme.d.ts.map +1 -1
- package/dist/modules/theme.js +1 -1
- package/dist/modules/theme.js.map +1 -1
- package/dist/modules/tooltips.d.ts.map +1 -1
- package/dist/modules/tooltips.js +17 -5
- package/dist/modules/tooltips.js.map +1 -1
- package/dist/modules/types.d.ts +1 -1
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/modules/types.js.map +1 -1
- package/dist/modules/websocket.d.ts.map +1 -1
- package/dist/modules/websocket.js +43 -8
- package/dist/modules/websocket.js.map +1 -1
- package/dist/network.js +1 -1
- package/dist/network.js.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2 -11
- package/dist/storage.js.map +1 -1
- package/dist/ui/cards.js +1 -1
- package/dist/ui/cards.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/modals.d.ts.map +1 -1
- package/dist/ui/modals.js +3 -3
- package/dist/ui/modals.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -0
- package/dist/utils.js.map +1 -1
- package/package.json +11 -10
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Modal rendering for the DevBar: outline, schema, a11y, and design review modals.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { a11yToMarkdown, getImpactColor, getViolationCounts, groupViolationsByImpact, runA11yAudit, } from '../../accessibility.js';
|
|
5
|
+
import { BUTTON_COLORS, CATEGORY_COLORS, CSS_COLORS, FONT_MONO, withAlpha, } from '../../constants.js';
|
|
5
6
|
import { extractDocumentOutline, outlineToMarkdown } from '../../outline.js';
|
|
6
|
-
import { checkMissingTags, extractFavicons, extractPageSchema, isImageKey, schemaToMarkdown } from '../../schema.js';
|
|
7
|
+
import { checkMissingTags, extractFavicons, extractPageSchema, isImageKey, schemaToMarkdown, } from '../../schema.js';
|
|
7
8
|
import { createEmptyMessage, createInfoBox, createModalBox, createModalContent, createModalHeader, createModalOverlay, createStyledButton, } from '../../ui/index.js';
|
|
8
|
-
import { a11yToMarkdown, runA11yAudit, groupViolationsByImpact, getImpactColor, getViolationCounts, } from '../../accessibility.js';
|
|
9
9
|
import { calculateCostEstimate, closeDesignReviewConfirm, handleSaveA11yAudit, handleSaveOutline, handleSaveSchema, proceedWithDesignReview, } from '../screenshot.js';
|
|
10
10
|
import { clearChildren } from './common.js';
|
|
11
11
|
// ============================================================================
|
|
@@ -91,7 +91,7 @@ function renderOutlineNodes(nodes, parentEl, depth, headingTracker) {
|
|
|
91
91
|
}
|
|
92
92
|
const textSpan = document.createElement('span');
|
|
93
93
|
Object.assign(textSpan.style, {
|
|
94
|
-
color:
|
|
94
|
+
color: CSS_COLORS.textSecondary,
|
|
95
95
|
fontSize: '0.6875rem',
|
|
96
96
|
marginLeft: '8px',
|
|
97
97
|
});
|
|
@@ -375,7 +375,9 @@ function renderKeyValueItems(container, items) {
|
|
|
375
375
|
});
|
|
376
376
|
thumb.src = value;
|
|
377
377
|
thumb.alt = key;
|
|
378
|
-
thumb.onerror = () => {
|
|
378
|
+
thumb.onerror = () => {
|
|
379
|
+
frame.style.display = 'none';
|
|
380
|
+
};
|
|
379
381
|
thumb.onload = () => {
|
|
380
382
|
if (thumb.naturalWidth) {
|
|
381
383
|
dimEl.textContent = `${thumb.naturalWidth}\u00d7${thumb.naturalHeight}`;
|
|
@@ -434,139 +436,180 @@ function faviconDevice(label, size) {
|
|
|
434
436
|
return { text: 'Browser tab', color: CSS_COLORS.textSecondary };
|
|
435
437
|
return { text: 'General', color: CSS_COLORS.textMuted };
|
|
436
438
|
}
|
|
439
|
+
/** Create a single favicon card row with thumbnail, label, device pill, dimensions, and URL. */
|
|
440
|
+
function createFaviconCard(icon, index) {
|
|
441
|
+
const device = faviconDevice(icon.label, icon.size);
|
|
442
|
+
const row = document.createElement('div');
|
|
443
|
+
Object.assign(row.style, {
|
|
444
|
+
display: 'flex',
|
|
445
|
+
alignItems: 'center',
|
|
446
|
+
padding: '6px 8px',
|
|
447
|
+
gap: '10px',
|
|
448
|
+
borderRadius: '3px',
|
|
449
|
+
backgroundColor: index % 2 === 0 ? 'rgba(255, 255, 255, 0.02)' : 'transparent',
|
|
450
|
+
});
|
|
451
|
+
// Thumbnail frame
|
|
452
|
+
const frame = document.createElement('div');
|
|
453
|
+
Object.assign(frame.style, {
|
|
454
|
+
width: '32px',
|
|
455
|
+
height: '32px',
|
|
456
|
+
display: 'flex',
|
|
457
|
+
alignItems: 'center',
|
|
458
|
+
justifyContent: 'center',
|
|
459
|
+
backgroundColor: 'rgba(0, 0, 0, 0.25)',
|
|
460
|
+
border: '1px solid rgba(255, 255, 255, 0.06)',
|
|
461
|
+
borderRadius: '4px',
|
|
462
|
+
flexShrink: '0',
|
|
463
|
+
});
|
|
464
|
+
const thumb = document.createElement('img');
|
|
465
|
+
Object.assign(thumb.style, {
|
|
466
|
+
width: '22px',
|
|
467
|
+
height: '22px',
|
|
468
|
+
objectFit: 'contain',
|
|
469
|
+
});
|
|
470
|
+
thumb.src = icon.url;
|
|
471
|
+
thumb.alt = icon.label;
|
|
472
|
+
thumb.onerror = () => {
|
|
473
|
+
frame.style.opacity = '0.3';
|
|
474
|
+
};
|
|
475
|
+
frame.appendChild(thumb);
|
|
476
|
+
row.appendChild(frame);
|
|
477
|
+
// Info column: label, device, dimensions + URL
|
|
478
|
+
const infoCol = document.createElement('div');
|
|
479
|
+
Object.assign(infoCol.style, {
|
|
480
|
+
flex: '1',
|
|
481
|
+
minWidth: '0',
|
|
482
|
+
display: 'flex',
|
|
483
|
+
flexDirection: 'column',
|
|
484
|
+
gap: '2px',
|
|
485
|
+
});
|
|
486
|
+
// Top row: label + device pill
|
|
487
|
+
const topRow = document.createElement('div');
|
|
488
|
+
Object.assign(topRow.style, {
|
|
489
|
+
display: 'flex',
|
|
490
|
+
alignItems: 'center',
|
|
491
|
+
gap: '6px',
|
|
492
|
+
});
|
|
493
|
+
const labelEl = document.createElement('span');
|
|
494
|
+
Object.assign(labelEl.style, {
|
|
495
|
+
color: CSS_COLORS.text,
|
|
496
|
+
fontSize: '0.6875rem',
|
|
497
|
+
fontWeight: '500',
|
|
498
|
+
overflow: 'hidden',
|
|
499
|
+
textOverflow: 'ellipsis',
|
|
500
|
+
whiteSpace: 'nowrap',
|
|
501
|
+
});
|
|
502
|
+
labelEl.textContent = icon.label;
|
|
503
|
+
if (icon.label.length > 24)
|
|
504
|
+
labelEl.title = icon.label;
|
|
505
|
+
topRow.appendChild(labelEl);
|
|
506
|
+
const devicePill = document.createElement('span');
|
|
507
|
+
Object.assign(devicePill.style, {
|
|
508
|
+
color: device.color,
|
|
509
|
+
fontSize: '0.5rem',
|
|
510
|
+
backgroundColor: withAlpha(device.color, 7),
|
|
511
|
+
padding: '1px 6px',
|
|
512
|
+
borderRadius: '6px',
|
|
513
|
+
letterSpacing: '0.03em',
|
|
514
|
+
whiteSpace: 'nowrap',
|
|
515
|
+
flexShrink: '0',
|
|
516
|
+
});
|
|
517
|
+
devicePill.textContent = device.text;
|
|
518
|
+
topRow.appendChild(devicePill);
|
|
519
|
+
infoCol.appendChild(topRow);
|
|
520
|
+
// Bottom row: declared size + actual dimensions + URL
|
|
521
|
+
const bottomRow = document.createElement('div');
|
|
522
|
+
Object.assign(bottomRow.style, {
|
|
523
|
+
display: 'flex',
|
|
524
|
+
alignItems: 'center',
|
|
525
|
+
gap: '6px',
|
|
526
|
+
fontSize: '0.5625rem',
|
|
527
|
+
color: CSS_COLORS.textMuted,
|
|
528
|
+
});
|
|
529
|
+
if (icon.size) {
|
|
530
|
+
const declaredEl = document.createElement('span');
|
|
531
|
+
declaredEl.textContent = icon.size;
|
|
532
|
+
declaredEl.style.opacity = '0.8';
|
|
533
|
+
bottomRow.appendChild(declaredEl);
|
|
534
|
+
}
|
|
535
|
+
// Actual dimensions (populated on load)
|
|
536
|
+
const dimEl = document.createElement('span');
|
|
537
|
+
dimEl.style.letterSpacing = '0.02em';
|
|
538
|
+
bottomRow.appendChild(dimEl);
|
|
539
|
+
thumb.onload = () => {
|
|
540
|
+
if (thumb.naturalWidth) {
|
|
541
|
+
const actual = `${thumb.naturalWidth}\u00d7${thumb.naturalHeight}`;
|
|
542
|
+
if (icon.size) {
|
|
543
|
+
dimEl.textContent = `\u2192 ${actual}`;
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
dimEl.textContent = actual;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
const sep = document.createElement('span');
|
|
551
|
+
sep.textContent = '\u00b7';
|
|
552
|
+
sep.style.opacity = '0.4';
|
|
553
|
+
bottomRow.appendChild(sep);
|
|
554
|
+
const urlEl = document.createElement('span');
|
|
555
|
+
Object.assign(urlEl.style, {
|
|
556
|
+
overflow: 'hidden',
|
|
557
|
+
textOverflow: 'ellipsis',
|
|
558
|
+
whiteSpace: 'nowrap',
|
|
559
|
+
opacity: '0.6',
|
|
560
|
+
});
|
|
561
|
+
urlEl.textContent = icon.url;
|
|
562
|
+
urlEl.title = icon.url;
|
|
563
|
+
bottomRow.appendChild(urlEl);
|
|
564
|
+
infoCol.appendChild(bottomRow);
|
|
565
|
+
row.appendChild(infoCol);
|
|
566
|
+
return row;
|
|
567
|
+
}
|
|
437
568
|
function renderFaviconsSection(container, icons) {
|
|
438
569
|
const color = CSS_COLORS.purple;
|
|
439
570
|
const section = document.createElement('div');
|
|
440
571
|
section.style.marginBottom = '20px';
|
|
441
572
|
renderSchemaSectionHeader(section, 'Favicons', color, icons.length);
|
|
442
573
|
icons.forEach((icon, i) => {
|
|
443
|
-
|
|
444
|
-
const row = document.createElement('div');
|
|
445
|
-
Object.assign(row.style, {
|
|
446
|
-
display: 'flex',
|
|
447
|
-
alignItems: 'center',
|
|
448
|
-
padding: '6px 8px',
|
|
449
|
-
gap: '10px',
|
|
450
|
-
borderRadius: '3px',
|
|
451
|
-
backgroundColor: i % 2 === 0 ? 'rgba(255, 255, 255, 0.02)' : 'transparent',
|
|
452
|
-
});
|
|
453
|
-
// Thumbnail frame
|
|
454
|
-
const frame = document.createElement('div');
|
|
455
|
-
Object.assign(frame.style, {
|
|
456
|
-
width: '32px',
|
|
457
|
-
height: '32px',
|
|
458
|
-
display: 'flex',
|
|
459
|
-
alignItems: 'center',
|
|
460
|
-
justifyContent: 'center',
|
|
461
|
-
backgroundColor: 'rgba(0, 0, 0, 0.25)',
|
|
462
|
-
border: '1px solid rgba(255, 255, 255, 0.06)',
|
|
463
|
-
borderRadius: '4px',
|
|
464
|
-
flexShrink: '0',
|
|
465
|
-
});
|
|
466
|
-
const thumb = document.createElement('img');
|
|
467
|
-
Object.assign(thumb.style, {
|
|
468
|
-
width: '22px',
|
|
469
|
-
height: '22px',
|
|
470
|
-
objectFit: 'contain',
|
|
471
|
-
});
|
|
472
|
-
thumb.src = icon.url;
|
|
473
|
-
thumb.alt = icon.label;
|
|
474
|
-
thumb.onerror = () => { frame.style.opacity = '0.3'; };
|
|
475
|
-
frame.appendChild(thumb);
|
|
476
|
-
row.appendChild(frame);
|
|
477
|
-
// Info column: label, device, dimensions + URL
|
|
478
|
-
const infoCol = document.createElement('div');
|
|
479
|
-
Object.assign(infoCol.style, {
|
|
480
|
-
flex: '1',
|
|
481
|
-
minWidth: '0',
|
|
482
|
-
display: 'flex',
|
|
483
|
-
flexDirection: 'column',
|
|
484
|
-
gap: '2px',
|
|
485
|
-
});
|
|
486
|
-
// Top row: label + device pill
|
|
487
|
-
const topRow = document.createElement('div');
|
|
488
|
-
Object.assign(topRow.style, {
|
|
489
|
-
display: 'flex',
|
|
490
|
-
alignItems: 'center',
|
|
491
|
-
gap: '6px',
|
|
492
|
-
});
|
|
493
|
-
const labelEl = document.createElement('span');
|
|
494
|
-
Object.assign(labelEl.style, {
|
|
495
|
-
color: CSS_COLORS.text,
|
|
496
|
-
fontSize: '0.6875rem',
|
|
497
|
-
fontWeight: '500',
|
|
498
|
-
overflow: 'hidden',
|
|
499
|
-
textOverflow: 'ellipsis',
|
|
500
|
-
whiteSpace: 'nowrap',
|
|
501
|
-
});
|
|
502
|
-
labelEl.textContent = icon.label;
|
|
503
|
-
if (icon.label.length > 24)
|
|
504
|
-
labelEl.title = icon.label;
|
|
505
|
-
topRow.appendChild(labelEl);
|
|
506
|
-
const devicePill = document.createElement('span');
|
|
507
|
-
Object.assign(devicePill.style, {
|
|
508
|
-
color: device.color,
|
|
509
|
-
fontSize: '0.5rem',
|
|
510
|
-
backgroundColor: withAlpha(device.color, 7),
|
|
511
|
-
padding: '1px 6px',
|
|
512
|
-
borderRadius: '6px',
|
|
513
|
-
letterSpacing: '0.03em',
|
|
514
|
-
whiteSpace: 'nowrap',
|
|
515
|
-
flexShrink: '0',
|
|
516
|
-
});
|
|
517
|
-
devicePill.textContent = device.text;
|
|
518
|
-
topRow.appendChild(devicePill);
|
|
519
|
-
infoCol.appendChild(topRow);
|
|
520
|
-
// Bottom row: declared size + actual dimensions + URL
|
|
521
|
-
const bottomRow = document.createElement('div');
|
|
522
|
-
Object.assign(bottomRow.style, {
|
|
523
|
-
display: 'flex',
|
|
524
|
-
alignItems: 'center',
|
|
525
|
-
gap: '6px',
|
|
526
|
-
fontSize: '0.5625rem',
|
|
527
|
-
color: CSS_COLORS.textMuted,
|
|
528
|
-
});
|
|
529
|
-
if (icon.size) {
|
|
530
|
-
const declaredEl = document.createElement('span');
|
|
531
|
-
declaredEl.textContent = icon.size;
|
|
532
|
-
declaredEl.style.opacity = '0.8';
|
|
533
|
-
bottomRow.appendChild(declaredEl);
|
|
534
|
-
}
|
|
535
|
-
// Actual dimensions (populated on load)
|
|
536
|
-
const dimEl = document.createElement('span');
|
|
537
|
-
dimEl.style.letterSpacing = '0.02em';
|
|
538
|
-
bottomRow.appendChild(dimEl);
|
|
539
|
-
thumb.onload = () => {
|
|
540
|
-
if (thumb.naturalWidth) {
|
|
541
|
-
const actual = `${thumb.naturalWidth}\u00d7${thumb.naturalHeight}`;
|
|
542
|
-
if (icon.size) {
|
|
543
|
-
dimEl.textContent = `\u2192 ${actual}`;
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
dimEl.textContent = actual;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
const sep = document.createElement('span');
|
|
551
|
-
sep.textContent = '\u00b7';
|
|
552
|
-
sep.style.opacity = '0.4';
|
|
553
|
-
bottomRow.appendChild(sep);
|
|
554
|
-
const urlEl = document.createElement('span');
|
|
555
|
-
Object.assign(urlEl.style, {
|
|
556
|
-
overflow: 'hidden',
|
|
557
|
-
textOverflow: 'ellipsis',
|
|
558
|
-
whiteSpace: 'nowrap',
|
|
559
|
-
opacity: '0.6',
|
|
560
|
-
});
|
|
561
|
-
urlEl.textContent = icon.url;
|
|
562
|
-
urlEl.title = icon.url;
|
|
563
|
-
bottomRow.appendChild(urlEl);
|
|
564
|
-
infoCol.appendChild(bottomRow);
|
|
565
|
-
row.appendChild(infoCol);
|
|
566
|
-
section.appendChild(row);
|
|
574
|
+
section.appendChild(createFaviconCard(icon, i));
|
|
567
575
|
});
|
|
568
576
|
container.appendChild(section);
|
|
569
577
|
}
|
|
578
|
+
/** Create a colored summary pill (e.g. "3 errors", "2 warnings"). */
|
|
579
|
+
function createSummaryPill(text, color) {
|
|
580
|
+
const pill = document.createElement('span');
|
|
581
|
+
Object.assign(pill.style, {
|
|
582
|
+
color,
|
|
583
|
+
fontSize: '0.5625rem',
|
|
584
|
+
backgroundColor: withAlpha(color, 8),
|
|
585
|
+
padding: '2px 8px',
|
|
586
|
+
borderRadius: '8px',
|
|
587
|
+
letterSpacing: '0.03em',
|
|
588
|
+
});
|
|
589
|
+
pill.textContent = text;
|
|
590
|
+
return pill;
|
|
591
|
+
}
|
|
592
|
+
/** Create a striped row with alternating background and optional left border. */
|
|
593
|
+
function createStripedRow(index, borderColor) {
|
|
594
|
+
const row = document.createElement('div');
|
|
595
|
+
Object.assign(row.style, {
|
|
596
|
+
display: 'flex',
|
|
597
|
+
alignItems: 'center',
|
|
598
|
+
padding: '4px 8px',
|
|
599
|
+
gap: '8px',
|
|
600
|
+
borderRadius: '3px',
|
|
601
|
+
backgroundColor: index % 2 === 0 ? 'rgba(255, 255, 255, 0.02)' : 'transparent',
|
|
602
|
+
...(borderColor ? { borderLeft: `2px solid ${withAlpha(borderColor, 25)}` } : {}),
|
|
603
|
+
});
|
|
604
|
+
return row;
|
|
605
|
+
}
|
|
606
|
+
/** Create a styled text span for modal info items. */
|
|
607
|
+
function createInfoSpan(text, styles) {
|
|
608
|
+
const el = document.createElement('span');
|
|
609
|
+
Object.assign(el.style, styles);
|
|
610
|
+
el.textContent = text;
|
|
611
|
+
return el;
|
|
612
|
+
}
|
|
570
613
|
function renderMissingTagsSection(container, tags) {
|
|
571
614
|
const section = document.createElement('div');
|
|
572
615
|
section.style.marginBottom = '20px';
|
|
@@ -584,76 +627,39 @@ function renderMissingTagsSection(container, tags) {
|
|
|
584
627
|
marginBottom: '8px',
|
|
585
628
|
});
|
|
586
629
|
if (errorCount > 0) {
|
|
587
|
-
|
|
588
|
-
Object.assign(errPill.style, {
|
|
589
|
-
color: CSS_COLORS.error,
|
|
590
|
-
fontSize: '0.5625rem',
|
|
591
|
-
backgroundColor: withAlpha(CSS_COLORS.error, 8),
|
|
592
|
-
padding: '2px 8px',
|
|
593
|
-
borderRadius: '8px',
|
|
594
|
-
letterSpacing: '0.03em',
|
|
595
|
-
});
|
|
596
|
-
errPill.textContent = `${errorCount} error${errorCount > 1 ? 's' : ''}`;
|
|
597
|
-
summary.appendChild(errPill);
|
|
630
|
+
summary.appendChild(createSummaryPill(`${errorCount} error${errorCount > 1 ? 's' : ''}`, CSS_COLORS.error));
|
|
598
631
|
}
|
|
599
632
|
if (warnCount > 0) {
|
|
600
|
-
|
|
601
|
-
Object.assign(warnPill.style, {
|
|
602
|
-
color: CSS_COLORS.warning,
|
|
603
|
-
fontSize: '0.5625rem',
|
|
604
|
-
backgroundColor: withAlpha(CSS_COLORS.warning, 8),
|
|
605
|
-
padding: '2px 8px',
|
|
606
|
-
borderRadius: '8px',
|
|
607
|
-
letterSpacing: '0.03em',
|
|
608
|
-
});
|
|
609
|
-
warnPill.textContent = `${warnCount} warning${warnCount > 1 ? 's' : ''}`;
|
|
610
|
-
summary.appendChild(warnPill);
|
|
633
|
+
summary.appendChild(createSummaryPill(`${warnCount} warning${warnCount > 1 ? 's' : ''}`, CSS_COLORS.warning));
|
|
611
634
|
}
|
|
612
635
|
section.appendChild(summary);
|
|
613
636
|
}
|
|
614
637
|
tags.forEach((tag, i) => {
|
|
615
638
|
const isError = tag.severity === 'error';
|
|
616
639
|
const tagColor = isError ? CSS_COLORS.error : CSS_COLORS.warning;
|
|
617
|
-
const row =
|
|
618
|
-
|
|
619
|
-
display: 'flex',
|
|
620
|
-
alignItems: 'center',
|
|
621
|
-
padding: '4px 8px',
|
|
622
|
-
gap: '8px',
|
|
623
|
-
borderRadius: '3px',
|
|
624
|
-
backgroundColor: i % 2 === 0 ? 'rgba(255, 255, 255, 0.02)' : 'transparent',
|
|
625
|
-
borderLeft: `2px solid ${withAlpha(tagColor, 25)}`,
|
|
626
|
-
});
|
|
627
|
-
const icon = document.createElement('span');
|
|
628
|
-
Object.assign(icon.style, {
|
|
640
|
+
const row = createStripedRow(i, tagColor);
|
|
641
|
+
const icon = createInfoSpan(isError ? '\u2718' : '\u26a0', {
|
|
629
642
|
fontSize: '0.625rem',
|
|
630
643
|
flexShrink: '0',
|
|
631
644
|
width: '14px',
|
|
632
645
|
textAlign: 'center',
|
|
633
646
|
color: tagColor,
|
|
634
647
|
});
|
|
635
|
-
icon.textContent = isError ? '\u2718' : '\u26a0';
|
|
636
648
|
row.appendChild(icon);
|
|
637
|
-
|
|
638
|
-
Object.assign(tagName.style, {
|
|
649
|
+
row.appendChild(createInfoSpan(tag.tag, {
|
|
639
650
|
color: CSS_COLORS.text,
|
|
640
651
|
fontSize: '0.6875rem',
|
|
641
652
|
width: '120px',
|
|
642
653
|
minWidth: '120px',
|
|
643
654
|
flexShrink: '0',
|
|
644
655
|
fontWeight: '500',
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
row.appendChild(tagName);
|
|
648
|
-
const hint = document.createElement('span');
|
|
649
|
-
Object.assign(hint.style, {
|
|
656
|
+
}));
|
|
657
|
+
row.appendChild(createInfoSpan(tag.hint, {
|
|
650
658
|
color: CSS_COLORS.textMuted,
|
|
651
659
|
fontSize: '0.6875rem',
|
|
652
660
|
flex: '1',
|
|
653
661
|
opacity: '0.85',
|
|
654
|
-
});
|
|
655
|
-
hint.textContent = tag.hint;
|
|
656
|
-
row.appendChild(hint);
|
|
662
|
+
}));
|
|
657
663
|
section.appendChild(row);
|
|
658
664
|
});
|
|
659
665
|
container.appendChild(section);
|
|
@@ -674,7 +680,8 @@ export function renderA11yModal(state) {
|
|
|
674
680
|
state.overlayElement = overlay;
|
|
675
681
|
document.body.appendChild(overlay);
|
|
676
682
|
// Run the audit async and replace content when done
|
|
677
|
-
runA11yAudit()
|
|
683
|
+
runA11yAudit()
|
|
684
|
+
.then((result) => {
|
|
678
685
|
// Check modal is still open
|
|
679
686
|
if (!state.showA11yModal)
|
|
680
687
|
return;
|
|
@@ -702,7 +709,8 @@ export function renderA11yModal(state) {
|
|
|
702
709
|
const content = createModalContent();
|
|
703
710
|
renderA11ySuccessContent(content, result, color);
|
|
704
711
|
modal.appendChild(content);
|
|
705
|
-
})
|
|
712
|
+
})
|
|
713
|
+
.catch((err) => {
|
|
706
714
|
if (!state.showA11yModal)
|
|
707
715
|
return;
|
|
708
716
|
clearChildren(modal);
|
|
@@ -836,6 +844,85 @@ function createViolationNodeEl(node) {
|
|
|
836
844
|
el.title = node.html;
|
|
837
845
|
return el;
|
|
838
846
|
}
|
|
847
|
+
/** Create a single violation card with rule ID, help text, description, and affected nodes. */
|
|
848
|
+
function createViolationCard(violation, impactColor) {
|
|
849
|
+
const violationEl = document.createElement('div');
|
|
850
|
+
Object.assign(violationEl.style, {
|
|
851
|
+
marginBottom: '12px',
|
|
852
|
+
padding: '10px 12px',
|
|
853
|
+
backgroundColor: withAlpha(impactColor, 3),
|
|
854
|
+
border: `1px solid ${withAlpha(impactColor, 13)}`,
|
|
855
|
+
borderRadius: '6px',
|
|
856
|
+
});
|
|
857
|
+
// Rule ID
|
|
858
|
+
const ruleId = document.createElement('div');
|
|
859
|
+
Object.assign(ruleId.style, {
|
|
860
|
+
color: impactColor,
|
|
861
|
+
fontSize: '0.6875rem',
|
|
862
|
+
fontWeight: '600',
|
|
863
|
+
marginBottom: '4px',
|
|
864
|
+
});
|
|
865
|
+
ruleId.textContent = violation.id;
|
|
866
|
+
violationEl.appendChild(ruleId);
|
|
867
|
+
// Help text
|
|
868
|
+
const helpText = document.createElement('div');
|
|
869
|
+
Object.assign(helpText.style, {
|
|
870
|
+
color: CSS_COLORS.text,
|
|
871
|
+
fontSize: '0.75rem',
|
|
872
|
+
marginBottom: '4px',
|
|
873
|
+
});
|
|
874
|
+
helpText.textContent = violation.help;
|
|
875
|
+
violationEl.appendChild(helpText);
|
|
876
|
+
// Description
|
|
877
|
+
const desc = document.createElement('div');
|
|
878
|
+
Object.assign(desc.style, {
|
|
879
|
+
color: CSS_COLORS.textSecondary,
|
|
880
|
+
fontSize: '0.6875rem',
|
|
881
|
+
marginBottom: '6px',
|
|
882
|
+
});
|
|
883
|
+
desc.textContent = violation.description;
|
|
884
|
+
violationEl.appendChild(desc);
|
|
885
|
+
// Node count
|
|
886
|
+
const nodeCount = document.createElement('div');
|
|
887
|
+
Object.assign(nodeCount.style, {
|
|
888
|
+
color: CSS_COLORS.textMuted,
|
|
889
|
+
fontSize: '0.625rem',
|
|
890
|
+
marginBottom: '4px',
|
|
891
|
+
});
|
|
892
|
+
nodeCount.textContent = `${violation.nodes.length} element${violation.nodes.length === 1 ? '' : 's'} affected`;
|
|
893
|
+
violationEl.appendChild(nodeCount);
|
|
894
|
+
// Affected nodes (collapsed by default, show first 3)
|
|
895
|
+
const nodesPreview = document.createElement('div');
|
|
896
|
+
Object.assign(nodesPreview.style, {
|
|
897
|
+
marginTop: '6px',
|
|
898
|
+
});
|
|
899
|
+
const visibleNodes = violation.nodes.slice(0, 3);
|
|
900
|
+
for (const node of visibleNodes) {
|
|
901
|
+
nodesPreview.appendChild(createViolationNodeEl(node));
|
|
902
|
+
}
|
|
903
|
+
if (violation.nodes.length > 3) {
|
|
904
|
+
const moreBtn = document.createElement('button');
|
|
905
|
+
Object.assign(moreBtn.style, {
|
|
906
|
+
background: 'none',
|
|
907
|
+
border: 'none',
|
|
908
|
+
color: impactColor,
|
|
909
|
+
fontSize: '0.625rem',
|
|
910
|
+
cursor: 'pointer',
|
|
911
|
+
padding: '2px 0',
|
|
912
|
+
fontFamily: FONT_MONO,
|
|
913
|
+
});
|
|
914
|
+
moreBtn.textContent = `+ ${violation.nodes.length - 3} more`;
|
|
915
|
+
moreBtn.onclick = () => {
|
|
916
|
+
moreBtn.remove();
|
|
917
|
+
for (const node of violation.nodes.slice(3)) {
|
|
918
|
+
nodesPreview.appendChild(createViolationNodeEl(node));
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
nodesPreview.appendChild(moreBtn);
|
|
922
|
+
}
|
|
923
|
+
violationEl.appendChild(nodesPreview);
|
|
924
|
+
return violationEl;
|
|
925
|
+
}
|
|
839
926
|
function renderA11yViolationGroup(container, impact, violations) {
|
|
840
927
|
const impactColor = getImpactColor(impact);
|
|
841
928
|
const section = document.createElement('div');
|
|
@@ -854,82 +941,7 @@ function renderA11yViolationGroup(container, impact, violations) {
|
|
|
854
941
|
sectionTitle.textContent = `${impact} (${violations.length})`;
|
|
855
942
|
section.appendChild(sectionTitle);
|
|
856
943
|
for (const violation of violations) {
|
|
857
|
-
|
|
858
|
-
Object.assign(violationEl.style, {
|
|
859
|
-
marginBottom: '12px',
|
|
860
|
-
padding: '10px 12px',
|
|
861
|
-
backgroundColor: withAlpha(impactColor, 3),
|
|
862
|
-
border: `1px solid ${withAlpha(impactColor, 13)}`,
|
|
863
|
-
borderRadius: '6px',
|
|
864
|
-
});
|
|
865
|
-
// Rule ID
|
|
866
|
-
const ruleId = document.createElement('div');
|
|
867
|
-
Object.assign(ruleId.style, {
|
|
868
|
-
color: impactColor,
|
|
869
|
-
fontSize: '0.6875rem',
|
|
870
|
-
fontWeight: '600',
|
|
871
|
-
marginBottom: '4px',
|
|
872
|
-
});
|
|
873
|
-
ruleId.textContent = violation.id;
|
|
874
|
-
violationEl.appendChild(ruleId);
|
|
875
|
-
// Help text
|
|
876
|
-
const helpText = document.createElement('div');
|
|
877
|
-
Object.assign(helpText.style, {
|
|
878
|
-
color: CSS_COLORS.text,
|
|
879
|
-
fontSize: '0.75rem',
|
|
880
|
-
marginBottom: '4px',
|
|
881
|
-
});
|
|
882
|
-
helpText.textContent = violation.help;
|
|
883
|
-
violationEl.appendChild(helpText);
|
|
884
|
-
// Description
|
|
885
|
-
const desc = document.createElement('div');
|
|
886
|
-
Object.assign(desc.style, {
|
|
887
|
-
color: CSS_COLORS.textSecondary,
|
|
888
|
-
fontSize: '0.6875rem',
|
|
889
|
-
marginBottom: '6px',
|
|
890
|
-
});
|
|
891
|
-
desc.textContent = violation.description;
|
|
892
|
-
violationEl.appendChild(desc);
|
|
893
|
-
// Node count
|
|
894
|
-
const nodeCount = document.createElement('div');
|
|
895
|
-
Object.assign(nodeCount.style, {
|
|
896
|
-
color: CSS_COLORS.textMuted,
|
|
897
|
-
fontSize: '0.625rem',
|
|
898
|
-
marginBottom: '4px',
|
|
899
|
-
});
|
|
900
|
-
nodeCount.textContent = `${violation.nodes.length} element${violation.nodes.length === 1 ? '' : 's'} affected`;
|
|
901
|
-
violationEl.appendChild(nodeCount);
|
|
902
|
-
// Affected nodes (collapsed by default, show first 3)
|
|
903
|
-
const nodesPreview = document.createElement('div');
|
|
904
|
-
Object.assign(nodesPreview.style, {
|
|
905
|
-
marginTop: '6px',
|
|
906
|
-
});
|
|
907
|
-
const visibleNodes = violation.nodes.slice(0, 3);
|
|
908
|
-
for (const node of visibleNodes) {
|
|
909
|
-
nodesPreview.appendChild(createViolationNodeEl(node));
|
|
910
|
-
}
|
|
911
|
-
if (violation.nodes.length > 3) {
|
|
912
|
-
const moreBtn = document.createElement('button');
|
|
913
|
-
Object.assign(moreBtn.style, {
|
|
914
|
-
background: 'none',
|
|
915
|
-
border: 'none',
|
|
916
|
-
color: impactColor,
|
|
917
|
-
fontSize: '0.625rem',
|
|
918
|
-
cursor: 'pointer',
|
|
919
|
-
padding: '2px 0',
|
|
920
|
-
fontFamily: FONT_MONO,
|
|
921
|
-
});
|
|
922
|
-
moreBtn.textContent = `+ ${violation.nodes.length - 3} more`;
|
|
923
|
-
moreBtn.onclick = () => {
|
|
924
|
-
moreBtn.remove();
|
|
925
|
-
for (const node of violation.nodes.slice(3)) {
|
|
926
|
-
nodesPreview.appendChild(createViolationNodeEl(node));
|
|
927
|
-
}
|
|
928
|
-
};
|
|
929
|
-
nodesPreview.appendChild(moreBtn);
|
|
930
|
-
}
|
|
931
|
-
violationEl.appendChild(nodesPreview);
|
|
932
|
-
section.appendChild(violationEl);
|
|
944
|
+
section.appendChild(createViolationCard(violation, impactColor));
|
|
933
945
|
}
|
|
934
946
|
container.appendChild(section);
|
|
935
947
|
}
|