snap-ally 0.0.2 → 0.1.0-beta

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.
@@ -5,373 +5,17 @@
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>Snap Ally - Test Execution</title>
8
+
9
+ <!-- Modern Typography and Core Styles -->
8
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@600;700&display=swap" rel="stylesheet">
11
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
12
- <style>
13
- :root {
14
- --bg-color: #f8fafc;
15
- --card-bg: rgba(255, 255, 255, 0.7);
16
- --primary: #4f46e5;
17
- --primary-dark: #4338ca;
18
- --text-main: #1e293b;
19
- --text-muted: #64748b;
20
- --passed: #10b981;
21
- --failed: #ef4444;
22
- --flaky: #f59e0b;
23
- --skipped: #6366f1;
24
- --glass-border: rgba(255, 255, 255, 0.4);
25
- --glass-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
26
-
27
- /* Severity Parameters */
28
- --critical: <%= colors.critical %>;
29
- --serious: <%= colors.serious %>;
30
- --moderate: <%= colors.moderate %>;
31
- --minor: <%= colors.minor %>;
32
- }
33
-
34
- * { box-sizing: border-box; margin: 0; padding: 0; }
35
-
36
- body {
37
- font-family: 'Inter', sans-serif;
38
- background-color: var(--bg-color);
39
- color: var(--text-main);
40
- padding: 100px 20px 0; /* Consistent top padding, no bottom padding */
41
- line-height: 1.6;
42
- display: flex;
43
- flex-direction: column;
44
- min-height: 100vh;
45
- }
46
-
47
- /* Fixed Header */
48
- header {
49
- position: fixed;
50
- top: 0; left: 0; right: 0;
51
- z-index: 1000;
52
- background: rgba(255, 255, 255, 0.8);
53
- backdrop-filter: blur(20px) saturate(180%);
54
- -webkit-backdrop-filter: blur(20px) saturate(180%);
55
- border-bottom: 1px solid var(--glass-border);
56
- padding: 14px 40px;
57
- display: flex;
58
- justify-content: space-between;
59
- align-items: center;
60
- box-shadow: 0 4px 30px rgba(0, 0, 0, 0.03);
61
- }
62
-
63
- .brand {
64
- display: flex;
65
- align-items: center;
66
- gap: 12px;
67
- text-decoration: none;
68
- }
69
-
70
- .brand-icon {
71
- width: 38px;
72
- height: 38px;
73
- background: linear-gradient(135deg, var(--primary), var(--primary-dark));
74
- border-radius: 12px;
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- color: white;
79
- box-shadow: 0 4px 15px rgba(99, 102, 241, 0.25);
80
- }
81
-
82
- header h1 {
83
- font-family: 'Outfit', sans-serif;
84
- font-size: 1.4rem;
85
- font-weight: 700;
86
- margin: 0;
87
- background: linear-gradient(to right, var(--primary-dark), #818cf8);
88
- -webkit-background-clip: text;
89
- background-clip: text;
90
- -webkit-text-fill-color: transparent;
91
- }
92
-
93
- /* Footer */
94
- footer {
95
- background: rgba(255, 255, 255, 0.7);
96
- backdrop-filter: blur(12px);
97
- -webkit-backdrop-filter: blur(12px);
98
- border-top: 1px solid var(--glass-border);
99
- padding: 24px 40px;
100
- margin-top: auto;
101
- display: flex;
102
- justify-content: space-between;
103
- align-items: center;
104
- color: var(--text-muted);
105
- font-size: 0.9rem;
106
- }
107
-
108
- .powered-by { display: flex; align-items: center; gap: 8px; font-weight: 500; }
109
- .badge-tool { background: #f1f5f9; padding: 2px 10px; border-radius: 8px; font-weight: 700; color: #334155; font-size: 0.8rem; }
110
-
111
- .container { max-width: 1200px !important; margin: 0 auto; width: 100%; padding-bottom: 40px; }
112
-
113
- /* Header Section (Hero) */
114
- .report-header {
115
- background: linear-gradient(135deg, #fff 0%, #f1f5f9 100%);
116
- border: 1px solid var(--glass-border);
117
- border-radius: 16px;
118
- padding: 16px 20px;
119
- margin-bottom: 16px;
120
- box-shadow: var(--glass-shadow);
121
- display: flex;
122
- justify-content: space-between;
123
- align-items: center;
124
- gap: 16px;
125
- }
126
-
127
- .header-info {
128
- display: flex;
129
- flex-direction: column;
130
- gap: 6px;
131
- width: 100%;
132
- }
133
-
134
- .header-title-row {
135
- display: flex;
136
- align-items: center;
137
- gap: 12px;
138
- justify-content: space-between;
139
- }
140
-
141
- .title-group {
142
- display: flex;
143
- align-items: center;
144
- gap: 12px;
145
- }
146
-
147
- .back-link {
148
- text-decoration: none;
149
- display: flex;
150
- align-items: center;
151
- gap: 6px;
152
- color: var(--text-muted);
153
- font-size: 0.9rem;
154
- font-weight: 500;
155
- transition: color 0.2s;
156
- background: rgba(0,0,0,0.05);
157
- padding: 8px 16px;
158
- border-radius: 8px;
159
- }
160
-
161
- .back-link:hover { color: var(--primary); }
162
-
163
- .status-badge {
164
- display: inline-flex;
165
- align-items: center;
166
- gap: 6px;
167
- padding: 4px 10px;
168
- border-radius: 8px;
169
- font-weight: 700;
170
- font-size: 0.65rem;
171
- text-transform: uppercase;
172
- letter-spacing: 0.05em;
173
- }
174
-
175
- .status-passed { background: #e6f9f3; color: var(--passed); }
176
- .status-failed { background: #fee2e2; color: var(--failed); }
177
- .status-flaky { background: #fffbeb; color: var(--flaky); }
178
-
179
- .report-title {
180
- font-family: 'Outfit', sans-serif;
181
- font-size: 1.4rem;
182
- font-weight: 700;
183
- margin: 0;
184
- color: #0f172a;
185
- line-height: 1.2;
186
- }
187
-
188
- .duration-text {
189
- font-variant-numeric: tabular-nums;
190
- font-weight: 600;
191
- font-size: 0.85rem;
192
- color: var(--text-muted);
193
- }
194
-
195
- .duration-val { color: var(--text-main); }
196
-
197
- .meta-row {
198
- display: flex;
199
- align-items: center;
200
- justify-content: space-between;
201
- width: 100%;
202
- color: var(--text-muted);
203
- font-size: 0.85rem;
204
- }
205
-
206
- .meta-left {
207
- display: flex;
208
- align-items: center;
209
- gap: 12px;
210
- }
211
-
212
- .browser-chip {
213
- background: #f1f5f9;
214
- padding: 4px 10px;
215
- border-radius: 6px;
216
- font-weight: 500;
217
- color: #475569;
218
- }
219
-
220
- .tag-badge {
221
- color: var(--primary);
222
- font-weight: 700;
223
- font-size: 0.75rem;
224
- background: #e0e7ff;
225
- padding: 2px 10px;
226
- border-radius: 6px;
227
- }
228
-
229
- .btn-a11y {
230
- display: inline-flex;
231
- background: #4f46e5;
232
- color: white;
233
- border: none;
234
- padding: 6px 14px;
235
- border-radius: 8px;
236
- font-weight: 700;
237
- box-shadow: 0 4px 12px rgba(79, 70, 229, 0.25);
238
- white-space: nowrap;
239
- margin: 0;
240
- font-size: 0.8rem;
241
- height: fit-content;
242
- text-decoration: none;
243
- align-items: center;
244
- gap: 6px;
245
- }
246
-
247
- /* Content Cards */
248
- .card {
249
- background: #fff;
250
- border-radius: 16px;
251
- padding: 20px;
252
- margin-bottom: 16px;
253
- border: 1px solid #f1f5f9;
254
- box-shadow: 0 2px 8px rgba(0,0,0,0.02);
255
- }
256
-
257
- h2 {
258
- font-family: 'Outfit', sans-serif;
259
- font-size: 1rem;
260
- font-weight: 600;
261
- margin-bottom: 12px;
262
- display: flex;
263
- align-items: center;
264
- gap: 8px;
265
- color: var(--text-main);
266
- }
267
-
268
- .section-icon { color: var(--primary); font-size: 20px; }
269
-
270
- /* Success State */
271
- .success-verified-card { text-align: center; padding: 80px 0; background: white; border-radius: 32px; border: 1px solid var(--glass-border); box-shadow: var(--glass-shadow); margin-bottom: 24px; }
272
- .success-hero-icon { font-size: 80px; color: #10b981; margin-bottom: 24px; filter: drop-shadow(0 4px 12px rgba(16,185,129,0.2)); }
273
- .success-hero-title { font-family: 'Outfit', sans-serif; font-weight: 700; font-size: 1.8rem; color: var(--text-main); margin-bottom: 12px; }
274
- .success-hero-desc { max-width: 400px; margin: 0 auto; color: var(--text-muted); }
275
-
276
- /* Lists */
277
- ol, ul { padding-left: 20px; }
278
- li { margin-bottom: 10px; padding-left: 4px; color: #334155; }
279
- li::marker { font-weight: 600; color: var(--text-muted); }
280
-
281
- /* Media */
282
- .screenshot-grid {
283
- display: grid;
284
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
285
- gap: 16px;
286
- margin-top: 20px;
287
- }
288
-
289
- .screenshot-item {
290
- border-radius: 10px;
291
- overflow: hidden;
292
- border: 1px solid #e2e8f0;
293
- }
294
-
295
- img { width: 100%; height: auto; display: block; }
296
- video { width: 100%; border-radius: 10px; margin-top: 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
297
-
298
- .attachment-item {
299
- display: flex;
300
- align-items: center;
301
- gap: 12px;
302
- padding: 10px 16px;
303
- background: #f8fafc;
304
- border-radius: 10px;
305
- text-decoration: none;
306
- color: var(--primary);
307
- font-weight: 500;
308
- margin-bottom: 8px;
309
- border: 1px solid transparent;
310
- transition: all 0.2s;
311
- font-size: 0.95rem;
312
- }
313
-
314
- .attachment-item:hover {
315
- background: #eff6ff;
316
- border-color: var(--primary-dark);
317
- transform: translateX(2px);
318
- }
319
-
320
- /* Errors & Violations */
321
- .error-card {
322
- background: #fff1f2;
323
- border-color: #fecdd3;
324
- }
325
-
326
- .violations-title { color: #9f1239; display: flex; align-items: center; gap: 10px; }
327
- .violations-container { display: flex; flex-direction: column; gap: 16px; }
328
-
329
- .violation-item {
330
- background: rgba(255,255,255,0.6);
331
- border-radius: 12px;
332
- padding: 16px;
333
- box-shadow: 0 2px 4px rgba(0,0,0,0.02);
334
- border-top: 1px solid rgba(255,255,255,0.8);
335
- border-left: 5px solid transparent;
336
- }
337
-
338
- .violation-item.critical { border-left-color: var(--critical); }
339
- .violation-item.serious { border-left-color: var(--serious); }
340
- .violation-item.moderate { border-left-color: var(--moderate); }
341
- .violation-item.minor { border-left-color: var(--minor); }
342
-
343
- .violation-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; }
344
- .rule-id { font-family: 'ui-monospace', monospace; font-weight: 700; color: var(--text-main); background: #f1f5f9; padding: 4px 8px; border-radius: 6px; font-size: 0.85rem; }
345
- .sev-badge { font-size: 0.75rem; font-weight: 800; text-transform: uppercase; color: white; padding: 4px 10px; border-radius: 6px; }
346
- .sev-badge.critical { background: var(--critical); }
347
- .sev-badge.serious { background: var(--serious); }
348
- .sev-badge.moderate { background: var(--moderate); }
349
- .sev-badge.minor { background: var(--minor); }
350
- .help-text { font-weight: 600; color: #881337; margin-bottom: 4px; }
351
- .desc-text { font-size: 0.9rem; color: #475569; margin-bottom: 8px; }
352
-
353
- .instance-grid { margin-top: 12px; display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
354
- .instance-card { border: 1px solid #fecdd3; border-radius: 8px; overflow: hidden; background: #fff; }
355
- .instance-img-wrap { position: relative; padding-top: 56.25%; }
356
- .instance-img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; }
357
- .instance-info { padding: 8px; font-size: 0.7rem; color: #881337; border-top: 1px solid #fecdd3; font-family: 'ui-monospace', monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
358
-
359
- .occ-row { font-size: 0.85rem; display: flex; align-items: center; gap: 6px; color: #64748b; margin-top: 12px; }
360
-
361
- .error-item {
362
- font-family: 'ui-monospace', monospace;
363
- font-size: 0.85rem;
364
- color: #9f1239;
365
- word-break: break-all;
366
- white-space: pre-wrap;
367
- }
368
-
369
- /* Exceptions */
370
- .exceptions-title { color: #9f1239; }
12
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@600;700&display=swap"
13
+ rel="stylesheet">
14
+ <link rel="stylesheet"
15
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
371
16
 
372
- /* Success Badge for Header */
373
- .status-badge.status-passed-a11y { background: #e6f9f3; color: var(--passed); }
374
- </style>
17
+ <!-- Snap Ally Shared Template Styles -->
18
+ <link rel="stylesheet" href="global-report-styles.css">
375
19
  </head>
376
20
 
377
21
  <body>
@@ -383,202 +27,173 @@
383
27
  <h1>Test Execution Report</h1>
384
28
  </a>
385
29
  <a href="../summary.html" class="back-link">
386
- <span class="material-symbols-outlined" style="font-size: 18px;">arrow_back</span>
387
- Back to Summary
30
+ <span class="material-symbols-outlined" style="font-size: 18px;">arrow_back</span>
31
+ Back to Summary
388
32
  </a>
389
33
  </header>
390
34
 
391
- <div class="container">
35
+ <div class="container" id="test-execution-root" style="display: none;">
36
+ <!-- Report Header -->
392
37
  <div class="report-header">
393
- <div class="header-info">
394
- <div class="header-title-row">
395
- <div class="title-group">
396
- <h1 class="report-title"><%= result.title %></h1>
397
- <div class="status-badge status-<%= result.status %>">
398
- <span class="material-symbols-outlined" style="font-size: 16px;"><%= result.statusIcon %></span>
399
- <%= result.status %>
400
- </div>
401
- <% if (result.a11yReportPath && result.a11yErrorCount === 0) { %>
402
- <div class="status-badge status-passed-a11y">
403
- <span class="material-symbols-outlined" style="font-size: 16px;">verified</span>
404
- A11y Verified
405
- </div>
406
- <% } %>
407
- </div>
408
- <div class="duration-text">
409
- Duration: <strong class="duration-val"><%= result.duration %></strong>
410
- </div>
38
+ <div class="header-info" style="width: 100%;">
39
+ <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 4px;">
40
+ <div style="display: flex; align-items: center; gap: 16px;">
41
+ <h1 class="report-title" id="report-title" style="margin: 0;"></h1>
42
+ <div class="status-badge" id="report-status-badge">
43
+ <span class="material-symbols-outlined" id="report-status-icon" style="font-size: 16px;"></span>
44
+ <span id="report-status-text"></span>
45
+ </div>
46
+ <div class="status-badge status-passed-a11y" id="report-a11y-verified" style="display: none;">
47
+ <span class="material-symbols-outlined" style="font-size: 16px;">verified</span>
48
+ A11y Verified
49
+ </div>
50
+ </div>
51
+
52
+ <div class="duration-text" style="color: var(--text-muted); font-size: 0.9rem;">
53
+ Duration: <strong class="duration-val" id="report-duration"
54
+ style="color: var(--text-main); font-size: 1.1rem;"></strong>
55
+ </div>
411
56
  </div>
412
- <div class="meta-row">
413
- <div class="meta-left">
414
- <span class="browser-chip"><%= result.browser %></span>
415
- <% if(result.tags && result.tags.length) { %>
416
- <% result.tags.forEach(function(tag) { %>
417
- <span class="tag-badge"><%= tag %></span>
418
- <% }); %>
419
- <% } %>
57
+
58
+ <div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
59
+ <div style="display: flex; align-items: center; gap: 8px;">
60
+ <span class="browser-chip" id="report-browser"></span>
61
+ <span id="report-tags-container"></span>
62
+ <template id="tag-template">
63
+ <span class="tag-badge"></span>
64
+ </template>
420
65
  </div>
421
-
422
- <% if (result.a11yReportPath) { %>
423
- <a href="./<%= result.a11yReportPath %>" class="btn-a11y">
424
- <span class="material-symbols-outlined" style="font-size: 18px;">accessibility_new</span>
425
- View Accessibility Report
426
- </a>
427
- <% } %>
66
+
67
+ <a href="#" id="view-a11y-report-link" class="text-link" style="display: none;">
68
+ <span class="material-symbols-outlined" style="font-size: 18px;">accessibility_new</span>
69
+ View Accessibility Report
70
+ </a>
428
71
  </div>
429
72
  </div>
430
73
  </div>
431
74
 
432
- <% if (result.description) { %>
433
- <div class="card">
434
- <h2><span class="material-symbols-outlined section-icon">info</span> Description</h2>
435
- <p><%= result.description %></p>
436
- </div>
437
- <% } %>
75
+ <!-- Description -->
76
+ <div class="card" id="card-description" style="display: none;">
77
+ <h2><span class="material-symbols-outlined section-icon">info</span> Description</h2>
78
+ <p id="report-description"></p>
79
+ </div>
438
80
 
439
- <% if (result.preConditions && result.preConditions.length) { %>
440
- <div class="card">
441
- <h2><span class="material-symbols-outlined section-icon">settings</span> Pre-conditions</h2>
442
- <ol>
443
- <% result.preConditions.forEach(function(pre) { %>
444
- <li><%= pre %></li>
445
- <% }); %>
446
- </ol>
447
- </div>
448
- <% } %>
81
+ <!-- Pre-conditions -->
82
+ <div class="card" id="card-preconditions" style="display: none;">
83
+ <h2><span class="material-symbols-outlined section-icon">settings</span> Pre-conditions</h2>
84
+ <ol id="list-preconditions"></ol>
85
+ </div>
449
86
 
450
- <% if (result.steps && result.steps.length) { %>
451
- <div class="card">
452
- <h2><span class="material-symbols-outlined section-icon">analytics</span> Test Steps</h2>
453
- <ol>
454
- <% result.steps.forEach(function(step) { %>
455
- <li><%= step %></li>
456
- <% }); %>
457
- </ol>
458
- </div>
459
- <% } %>
87
+ <!-- Test Steps -->
88
+ <div class="card" id="card-steps" style="display: none;">
89
+ <h2><span class="material-symbols-outlined section-icon">analytics</span> Test Steps</h2>
90
+ <ol id="list-steps"></ol>
91
+ </div>
460
92
 
461
- <% if (result.postConditions && result.postConditions.length) { %>
462
- <div class="card">
463
- <h2><span class="material-symbols-outlined section-icon">check_circle</span> Post-conditions</h2>
464
- <ol>
465
- <% result.postConditions.forEach(function(post) { %>
466
- <li><%= post %></li>
467
- <% }); %>
468
- </ol>
469
- </div>
470
- <% } %>
93
+ <!-- String Item Template (reused for Pre-conditions, Steps, Post-conditions, Exceptions) -->
94
+ <template id="string-item-template">
95
+ <li></li>
96
+ </template>
471
97
 
472
- <% if (result.videoPath) { %>
473
- <div class="card">
474
- <h2><span class="material-symbols-outlined section-icon">videocam</span> Recording</h2>
475
- <video controls>
476
- <source src="<%= result.videoPath %>" type="video/webm" />
477
- </video>
478
- </div>
479
- <% } %>
98
+ <!-- Post-conditions -->
99
+ <div class="card" id="card-postconditions" style="display: none;">
100
+ <h2><span class="material-symbols-outlined section-icon">check_circle</span> Post-conditions</h2>
101
+ <ol id="list-postconditions"></ol>
102
+ </div>
480
103
 
481
- <% if (result.screenshotPaths && result.screenshotPaths.length) { %>
482
- <div class="card">
483
- <h2><span class="material-symbols-outlined section-icon">image</span> Evidence Gap</h2>
484
- <div class="screenshot-grid">
485
- <% result.screenshotPaths.forEach(function(path, index) { %>
486
- <div class="screenshot-item">
487
- <img src="<%= path %>" alt="Evidence <%= index + 1 %>" />
488
- </div>
489
- <% }); %>
490
- </div>
491
- </div>
492
- <% } %>
104
+ <!-- Recording -->
105
+ <div class="card" id="card-video" style="display: none;">
106
+ <h2><span class="material-symbols-outlined section-icon">videocam</span> Recording</h2>
107
+ <video controls>
108
+ <source id="report-video-source" type="video/webm" />
109
+ </video>
110
+ </div>
493
111
 
494
- <% if (result.attachments && result.attachments.length) { %>
495
- <div class="card">
496
- <h2><span class="material-symbols-outlined section-icon">attachment</span> Attachments</h2>
497
- <% result.attachments.forEach(function(attachment) { %>
498
- <a href="<%= attachment.path %>" target="_blank" class="attachment-item">
499
- <span class="material-symbols-outlined" style="font-size: 18px;">description</span>
500
- <%= attachment.name %>
501
- </a>
502
- <% }); %>
112
+ <!-- Evidence Gap (Screenshots) -->
113
+ <div class="card" id="card-screenshots" style="display: none;">
114
+ <h2><span class="material-symbols-outlined section-icon">image</span> Evidence Gap</h2>
115
+ <div class="screenshot-grid" id="grid-screenshots"></div>
116
+ </div>
117
+ <template id="screenshot-template">
118
+ <div class="screenshot-item">
119
+ <img alt="Evidence" />
503
120
  </div>
504
- <% } %>
121
+ </template>
505
122
 
506
- <!-- Accessibility Violations Section -->
507
- <% if (result.a11yReportPath && result.a11yErrorCount === 0) { %>
508
- <div class="success-verified-card">
509
- <span class="material-symbols-outlined success-hero-icon">check_circle</span>
510
- <h3 class="success-hero-title">Compliance Verified</h3>
511
- <p class="success-hero-desc">Excellent! No accessibility violations were detected for this target resource.</p>
512
- </div>
513
- <% } else if (result.a11yErrors && result.a11yErrors.length) { %>
514
- <div class="card error-card">
515
- <h2 class="violations-title">
516
- <span class="material-symbols-outlined section-icon" style="color: #9f1239;">accessibility_new</span>
517
- Accessibility Violations
518
- </h2>
519
- <div class="violations-container">
520
- <% result.a11yErrors.forEach(function(error) { %>
521
- <div class="violation-item <%= error.severity %>">
522
- <div class="violation-header">
523
- <span class="rule-id"><%= error.id %></span>
524
- <span class="sev-badge <%= error.severity %>"><%= error.severity %></span>
525
- </div>
526
- <div class="help-text"><%= error.help %></div>
527
-
528
- <% if (error.description) { %>
529
- <div class="desc-text"><%= error.description %></div>
530
- <% } %>
123
+ <!-- Attachments -->
124
+ <div class="card" id="card-attachments" style="display: none;">
125
+ <h2><span class="material-symbols-outlined section-icon">attachment</span> Attachments</h2>
126
+ <div id="list-attachments"></div>
127
+ </div>
128
+ <template id="attachment-template">
129
+ <a target="_blank" class="attachment-item">
130
+ <span class="material-symbols-outlined" style="font-size: 18px;">description</span>
131
+ <span class="attachment-name"></span>
132
+ </a>
133
+ </template>
134
+
135
+ <!-- Accessibility Success -->
136
+ <div class="success-verified-card" id="card-a11y-success" style="display: none;">
137
+ <span class="material-symbols-outlined success-hero-icon">check_circle</span>
138
+ <h3 class="success-hero-title">Compliance Verified</h3>
139
+ <p class="success-hero-desc">Excellent! No accessibility violations were detected for this target resource.</p>
140
+ </div>
531
141
 
532
- <% if (error.target && error.target.length) { %>
533
- <div class="instance-grid">
534
- <% error.target.forEach(function(t) { %>
535
- <% if (t.screenshot) { %>
536
- <div class="instance-card">
537
- <div class="instance-img-wrap">
538
- <img src="<%= t.screenshot %>" alt="Violation on <%= t.element %>" class="instance-img">
539
- </div>
540
- <div class="instance-info" title="<%= t.element %>">
541
- <%= t.element %>
542
- </div>
543
- </div>
544
- <% } %>
545
- <% }); %>
546
- </div>
547
- <% } %>
142
+ <!-- Accessibility Errors -->
143
+ <div class="card error-card" id="card-a11y-errors" style="display: none;">
144
+ <h2 class="violations-title">
145
+ <span class="material-symbols-outlined section-icon" style="color: #9f1239;">accessibility_new</span>
146
+ Accessibility Violations
147
+ </h2>
148
+ <div class="violations-container" id="list-a11y-errors"></div>
149
+ </div>
150
+ <template id="a11y-error-template">
151
+ <div class="violation-item">
152
+ <div class="violation-header">
153
+ <span class="rule-id"></span>
154
+ <span class="sev-badge"></span>
155
+ </div>
156
+ <div class="help-text"></div>
157
+ <div class="desc-text" style="display: none;"></div>
548
158
 
549
- <div class="occ-row">
550
- <span class="material-symbols-outlined" style="font-size: 16px;">tag</span>
551
- <span>Occurrences: <strong><%= error.total %></strong></span>
552
- </div>
553
- </div>
554
- <% }); %>
159
+ <div class="instance-grid"></div>
160
+
161
+ <div class="occ-row">
162
+ <span class="material-symbols-outlined" style="font-size: 16px;">tag</span>
163
+ <span>Occurrences: <strong class="occ-count"></strong></span>
555
164
  </div>
556
165
  </div>
557
- <% } %>
558
-
559
- <!-- Other Exceptions -->
560
- <%
561
- // Filter out the generic accessibility assertion error if we have detailed reports
562
- const filteredErrors = result.errors.filter(err => !err.includes('Accessibility audit failed'));
563
- %>
564
- <% if (filteredErrors && filteredErrors.length) { %>
565
- <div class="card error-card">
566
- <h2 class="exceptions-title"><span class="material-symbols-outlined section-icon" style="color: #9f1239;">error</span> Exceptions</h2>
567
- <ol>
568
- <% filteredErrors.forEach(function(error) { %>
569
- <li class="error-item"><%= error %></li>
570
- <% }); %>
571
- </ol>
166
+ </template>
167
+ <template id="a11y-instance-template">
168
+ <div class="instance-card">
169
+ <div class="instance-img-wrap">
170
+ <img class="instance-img">
171
+ </div>
172
+ <div class="instance-info"></div>
572
173
  </div>
573
- <% } %>
174
+ </template>
175
+
176
+ <!-- Exceptions -->
177
+ <div class="card error-card" id="card-exceptions" style="display: none;">
178
+ <h2 class="exceptions-title"><span class="material-symbols-outlined section-icon"
179
+ style="color: #9f1239;">error</span> Exceptions</h2>
180
+ <ol id="list-exceptions"></ol>
181
+ </div>
574
182
  </div>
183
+
575
184
  <footer>
576
- <div class="powered-by">
577
- Generated by <span class="badge-tool">Snap Ally</span>
578
- </div>
579
- <div>
580
- <span style="opacity: 0.7;">&copy; <%= new Date().getFullYear() %> Snap Ally</span>
581
- </div>
185
+ <div class="powered-by">Generated by <span class="badge-tool">Snap Ally</span></div>
186
+ <div><span style="opacity: 0.7;">&copy; <span id="year"></span> Snap Ally</span></div>
582
187
  </footer>
188
+
189
+ <!-- Scripts -->
190
+ <script>document.getElementById('year').textContent = new Date().getFullYear();</script>
191
+
192
+ <!-- Injected JSON Payload -->
193
+ <script src="data.js"></script>
194
+
195
+ <!-- Report Logic -->
196
+ <script src="report-app.js"></script>
583
197
  </body>
584
- </html>
198
+
199
+ </html>