tech-debt-visualizer 0.2.3 → 0.2.5
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/reports/assets/report.css +279 -86
- package/dist/reports/html.js +84 -69
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Technical Debt Report —
|
|
1
|
+
/* Technical Debt Report — Colorful dashboard, clean fit, scroll in sections */
|
|
2
2
|
:root {
|
|
3
3
|
--bg: #0b0c0e;
|
|
4
4
|
--bg-elevated: #111214;
|
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
--text: #e8e9ea;
|
|
10
10
|
--text-muted: #8b9199;
|
|
11
11
|
--link: #5794f2;
|
|
12
|
-
--radius:
|
|
13
|
-
--shadow: 0 1px
|
|
12
|
+
--radius: 6px;
|
|
13
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
|
|
14
|
+
--tier-1: #e53935;
|
|
15
|
+
--tier-2: #f57c00;
|
|
16
|
+
--tier-3: #f9a825;
|
|
17
|
+
--tier-4: #29b6f6;
|
|
18
|
+
--tier-5: #43a047;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
[data-theme="light"] {
|
|
@@ -24,6 +29,11 @@
|
|
|
24
29
|
--text-muted: #6b7077;
|
|
25
30
|
--link: #3274d9;
|
|
26
31
|
--shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
32
|
+
--tier-1: #c62828;
|
|
33
|
+
--tier-2: #ef6c00;
|
|
34
|
+
--tier-3: #f9a825;
|
|
35
|
+
--tier-4: #0288d1;
|
|
36
|
+
--tier-5: #2e7d32;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
* { box-sizing: border-box; }
|
|
@@ -40,17 +50,21 @@ body {
|
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
body.dashboard-page {
|
|
43
|
-
padding-bottom:
|
|
53
|
+
padding-bottom: 0;
|
|
54
|
+
height: 100vh;
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
/* ——— Dashboard header (Grafana
|
|
60
|
+
/* ——— Dashboard header (Grafana top bar: title left, score right) ——— */
|
|
47
61
|
.dashboard-header {
|
|
48
62
|
display: flex;
|
|
49
|
-
align-items:
|
|
63
|
+
align-items: center;
|
|
50
64
|
justify-content: space-between;
|
|
51
65
|
flex-wrap: wrap;
|
|
52
|
-
gap:
|
|
53
|
-
padding:
|
|
66
|
+
gap: 0.75rem;
|
|
67
|
+
padding: 0.75rem 1.5rem;
|
|
54
68
|
background: var(--bg-elevated);
|
|
55
69
|
border-bottom: 1px solid var(--border);
|
|
56
70
|
position: sticky;
|
|
@@ -60,98 +74,126 @@ body.dashboard-page {
|
|
|
60
74
|
|
|
61
75
|
.dashboard-header-left {
|
|
62
76
|
display: flex;
|
|
63
|
-
align-items:
|
|
64
|
-
gap:
|
|
65
|
-
min-width: 0;
|
|
66
|
-
flex: 1;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.dashboard-score-badge {
|
|
70
|
-
flex-shrink: 0;
|
|
71
|
-
line-height: 0;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.dashboard-score-badge .score-badge-svg {
|
|
75
|
-
width: 56px;
|
|
76
|
-
height: auto;
|
|
77
|
-
display: block;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.dashboard-score-badge .score-badge-num { font-size: 22px; }
|
|
81
|
-
.dashboard-score-badge .score-badge-of { font-size: 9px; }
|
|
82
|
-
|
|
83
|
-
.dashboard-hero {
|
|
77
|
+
align-items: baseline;
|
|
78
|
+
gap: 0.75rem;
|
|
84
79
|
min-width: 0;
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
.dashboard-title {
|
|
88
|
-
margin: 0
|
|
83
|
+
margin: 0;
|
|
89
84
|
font-size: 1.125rem;
|
|
90
85
|
font-weight: 600;
|
|
91
86
|
letter-spacing: -0.01em;
|
|
92
87
|
color: var(--text);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
margin: 0 0 0.35rem;
|
|
97
|
-
font-size: 14px;
|
|
98
|
-
line-height: 1.45;
|
|
99
|
-
color: var(--text);
|
|
100
|
-
max-width: 42em;
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
text-overflow: ellipsis;
|
|
101
91
|
}
|
|
102
92
|
|
|
103
93
|
.dashboard-meta {
|
|
104
94
|
font-size: 12px;
|
|
105
95
|
color: var(--text-muted);
|
|
96
|
+
white-space: nowrap;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
text-overflow: ellipsis;
|
|
106
99
|
}
|
|
107
100
|
|
|
108
101
|
.dashboard-header-right {
|
|
109
102
|
display: flex;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
gap: 0.25rem;
|
|
103
|
+
align-items: center;
|
|
104
|
+
gap: 1rem;
|
|
113
105
|
flex-shrink: 0;
|
|
114
106
|
}
|
|
115
107
|
|
|
116
|
-
.dashboard-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
.dashboard-score {
|
|
109
|
+
display: inline-flex;
|
|
110
|
+
align-items: baseline;
|
|
111
|
+
gap: 0.2rem;
|
|
112
|
+
padding: 0.35rem 0.65rem;
|
|
113
|
+
border-radius: var(--radius);
|
|
114
|
+
font-weight: 600;
|
|
120
115
|
}
|
|
121
116
|
|
|
117
|
+
.dashboard-score-value { font-size: 1.25rem; line-height: 1; }
|
|
118
|
+
.dashboard-score-of { font-size: 0.85rem; font-weight: 500; color: var(--text-muted); }
|
|
119
|
+
.dashboard-score-label { font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em; margin-left: 0.35rem; opacity: 0.95; }
|
|
120
|
+
|
|
121
|
+
.dashboard-score.tier-1 { background: rgba(229, 57, 53, 0.25); color: #ff8a80; font-weight: 700; }
|
|
122
|
+
.dashboard-score.tier-2 { background: rgba(245, 124, 0, 0.25); color: #ffb74d; font-weight: 700; }
|
|
123
|
+
.dashboard-score.tier-3 { background: rgba(249, 168, 37, 0.25); color: #ffd54f; font-weight: 700; }
|
|
124
|
+
.dashboard-score.tier-4 { background: rgba(41, 182, 246, 0.25); color: #82b1ff; font-weight: 700; }
|
|
125
|
+
.dashboard-score.tier-5 { background: rgba(67, 160, 71, 0.25); color: #81c784; font-weight: 700; }
|
|
126
|
+
|
|
122
127
|
.dashboard-date {
|
|
123
|
-
font-size:
|
|
128
|
+
font-size: 12px;
|
|
124
129
|
color: var(--text-muted);
|
|
125
|
-
opacity: 0.9;
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
/* ——— Main content
|
|
132
|
+
/* ——— Main content: 2×2 grid, fills viewport, scroll inside cells ——— */
|
|
129
133
|
.dashboard-main {
|
|
130
|
-
|
|
134
|
+
flex: 1;
|
|
135
|
+
min-height: 0;
|
|
136
|
+
max-width: 1600px;
|
|
131
137
|
margin: 0 auto;
|
|
132
|
-
padding:
|
|
138
|
+
padding: 0.75rem 1rem;
|
|
139
|
+
width: 100%;
|
|
140
|
+
overflow: hidden;
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
.dashboard-grid {
|
|
143
|
+
.dashboard-grid-2x2 {
|
|
136
144
|
display: grid;
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
grid-template-columns: 1fr 1fr;
|
|
146
|
+
grid-template-rows: auto 1fr;
|
|
147
|
+
gap: 0.75rem;
|
|
148
|
+
height: 100%;
|
|
149
|
+
min-height: 0;
|
|
150
|
+
align-items: stretch;
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
.dashboard-
|
|
142
|
-
|
|
153
|
+
.dashboard-cell {
|
|
154
|
+
min-height: 0;
|
|
155
|
+
min-width: 0;
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.dashboard-cell .panel {
|
|
160
|
+
height: 100%;
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: column;
|
|
163
|
+
min-height: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.dashboard-cell .panel-body {
|
|
167
|
+
flex: 1;
|
|
168
|
+
min-height: 0;
|
|
169
|
+
overflow: auto;
|
|
170
|
+
-webkit-overflow-scrolling: touch;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.dashboard-cell-score .panel-body-score { flex: 0 1 auto; overflow: visible; min-height: 0; }
|
|
174
|
+
|
|
175
|
+
.dashboard-cell-heatmap .panel-body-heatmap,
|
|
176
|
+
.dashboard-cell-list .panel-body {
|
|
177
|
+
min-height: 0;
|
|
143
178
|
}
|
|
144
179
|
|
|
145
180
|
@media (max-width: 900px) {
|
|
146
|
-
.dashboard-
|
|
181
|
+
body.dashboard-page { height: auto; overflow: auto; }
|
|
182
|
+
.dashboard-grid-2x2 {
|
|
183
|
+
grid-template-columns: 1fr;
|
|
184
|
+
grid-template-rows: auto auto auto auto;
|
|
185
|
+
height: auto;
|
|
186
|
+
}
|
|
187
|
+
.dashboard-cell-heatmap .panel-body-heatmap { min-height: 240px; }
|
|
188
|
+
.dashboard-cell-list .panel-body { min-height: 240px; }
|
|
147
189
|
}
|
|
148
190
|
|
|
149
191
|
@media (max-width: 560px) {
|
|
150
|
-
.dashboard-header { padding: 0.75rem
|
|
151
|
-
.dashboard-main { padding:
|
|
192
|
+
.dashboard-header { padding: 0.5rem 0.75rem; }
|
|
193
|
+
.dashboard-main { padding: 0.5rem 0.75rem; }
|
|
152
194
|
}
|
|
153
195
|
|
|
154
|
-
/* ——— Panels
|
|
196
|
+
/* ——— Panels: borders, colored accents ——— */
|
|
155
197
|
.panel {
|
|
156
198
|
background: var(--surface);
|
|
157
199
|
border: 1px solid var(--border);
|
|
@@ -161,39 +203,189 @@ body.dashboard-page {
|
|
|
161
203
|
}
|
|
162
204
|
|
|
163
205
|
.panel-header {
|
|
164
|
-
padding: 0.
|
|
206
|
+
padding: 0.6rem 0.85rem;
|
|
165
207
|
border-bottom: 1px solid var(--border-subtle);
|
|
166
|
-
background: rgba(0, 0, 0, 0.
|
|
208
|
+
background: rgba(0, 0, 0, 0.04);
|
|
209
|
+
flex-shrink: 0;
|
|
167
210
|
}
|
|
168
211
|
|
|
212
|
+
.panel-header-accent { border-left: 3px solid var(--tier-4); }
|
|
213
|
+
.panel-header-accent-orange { border-left: 3px solid var(--tier-2); }
|
|
214
|
+
.panel-header-accent-blue { border-left: 3px solid var(--link); }
|
|
215
|
+
|
|
216
|
+
.panel-score-tier-1 .panel-header-accent { border-left-color: var(--tier-1); }
|
|
217
|
+
.panel-score-tier-2 .panel-header-accent { border-left-color: var(--tier-2); }
|
|
218
|
+
.panel-score-tier-3 .panel-header-accent { border-left-color: var(--tier-3); }
|
|
219
|
+
.panel-score-tier-4 .panel-header-accent { border-left-color: var(--tier-4); }
|
|
220
|
+
.panel-score-tier-5 .panel-header-accent { border-left-color: var(--tier-5); }
|
|
221
|
+
|
|
169
222
|
[data-theme="light"] .panel-header {
|
|
170
223
|
background: rgba(0, 0, 0, 0.02);
|
|
171
224
|
}
|
|
172
225
|
|
|
173
226
|
.panel-title {
|
|
174
227
|
margin: 0;
|
|
175
|
-
font-size:
|
|
176
|
-
font-weight:
|
|
228
|
+
font-size: 12px;
|
|
229
|
+
font-weight: 700;
|
|
177
230
|
color: var(--text);
|
|
178
|
-
letter-spacing:
|
|
231
|
+
letter-spacing: 0.02em;
|
|
232
|
+
text-transform: uppercase;
|
|
179
233
|
}
|
|
180
234
|
|
|
181
235
|
.panel-desc {
|
|
182
|
-
margin: 0.
|
|
183
|
-
font-size:
|
|
236
|
+
margin: 0.2rem 0 0;
|
|
237
|
+
font-size: 11px;
|
|
184
238
|
color: var(--text-muted);
|
|
185
|
-
line-height: 1.
|
|
239
|
+
line-height: 1.35;
|
|
186
240
|
}
|
|
187
241
|
|
|
188
242
|
.panel-body {
|
|
189
|
-
padding: 1rem;
|
|
243
|
+
padding: 0.85rem 1rem;
|
|
190
244
|
}
|
|
191
245
|
|
|
192
246
|
.panel-body-center {
|
|
193
247
|
text-align: center;
|
|
194
248
|
}
|
|
195
249
|
|
|
196
|
-
/* ———
|
|
250
|
+
/* ——— Score panel: shield + big number + tier color ——— */
|
|
251
|
+
.panel-score {
|
|
252
|
+
border-top: 2px solid transparent;
|
|
253
|
+
}
|
|
254
|
+
.panel-score-tier-1 { border-top-color: var(--tier-1); }
|
|
255
|
+
.panel-score-tier-2 { border-top-color: var(--tier-2); }
|
|
256
|
+
.panel-score-tier-3 { border-top-color: var(--tier-3); }
|
|
257
|
+
.panel-score-tier-4 { border-top-color: var(--tier-4); }
|
|
258
|
+
.panel-score-tier-5 { border-top-color: var(--tier-5); }
|
|
259
|
+
|
|
260
|
+
.panel-score .panel-body-score {
|
|
261
|
+
text-align: center;
|
|
262
|
+
padding: 1rem 0.85rem;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.score-display {
|
|
266
|
+
display: flex;
|
|
267
|
+
align-items: center;
|
|
268
|
+
justify-content: center;
|
|
269
|
+
gap: 1rem;
|
|
270
|
+
margin-bottom: 0.6rem;
|
|
271
|
+
flex-wrap: wrap;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.score-shield-wrap {
|
|
275
|
+
line-height: 0;
|
|
276
|
+
flex-shrink: 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.panel-score .score-badge-svg {
|
|
280
|
+
display: block;
|
|
281
|
+
width: 72px;
|
|
282
|
+
height: auto;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.panel-score .score-badge-svg .score-badge-num {
|
|
286
|
+
font-size: 28px;
|
|
287
|
+
font-weight: 900;
|
|
288
|
+
letter-spacing: -0.03em;
|
|
289
|
+
fill: #fff;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.panel-score .score-badge-svg .score-badge-of {
|
|
293
|
+
font-size: 10px;
|
|
294
|
+
font-weight: 700;
|
|
295
|
+
letter-spacing: 0.1em;
|
|
296
|
+
text-transform: uppercase;
|
|
297
|
+
fill: rgba(255,255,255,0.95);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.score-numeric {
|
|
301
|
+
display: flex;
|
|
302
|
+
align-items: baseline;
|
|
303
|
+
gap: 0.2rem;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.score-num {
|
|
307
|
+
font-size: 2.25rem;
|
|
308
|
+
font-weight: 800;
|
|
309
|
+
line-height: 1;
|
|
310
|
+
letter-spacing: -0.04em;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.panel-score-tier-1 .score-num { color: var(--tier-1); }
|
|
314
|
+
.panel-score-tier-2 .score-num { color: var(--tier-2); }
|
|
315
|
+
.panel-score-tier-3 .score-num { color: var(--tier-3); }
|
|
316
|
+
.panel-score-tier-4 .score-num { color: var(--tier-4); }
|
|
317
|
+
.panel-score-tier-5 .score-num { color: var(--tier-5); }
|
|
318
|
+
|
|
319
|
+
.score-of {
|
|
320
|
+
font-size: 0.95rem;
|
|
321
|
+
font-weight: 600;
|
|
322
|
+
color: var(--text-muted);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.panel-score .score-label {
|
|
326
|
+
margin: 0 0 0.2rem;
|
|
327
|
+
font-size: 0.95rem;
|
|
328
|
+
font-weight: 700;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.panel-score-tier-1 .score-label { color: var(--tier-1); }
|
|
332
|
+
.panel-score-tier-2 .score-label { color: var(--tier-2); }
|
|
333
|
+
.panel-score-tier-3 .score-label { color: var(--tier-3); }
|
|
334
|
+
.panel-score-tier-4 .score-label { color: var(--tier-4); }
|
|
335
|
+
.panel-score-tier-5 .score-label { color: var(--tier-5); }
|
|
336
|
+
|
|
337
|
+
.panel-score .score-desc {
|
|
338
|
+
margin: 0 0 0.4rem;
|
|
339
|
+
font-size: 12px;
|
|
340
|
+
color: var(--text-muted);
|
|
341
|
+
line-height: 1.4;
|
|
342
|
+
max-width: 260px;
|
|
343
|
+
margin-left: auto;
|
|
344
|
+
margin-right: auto;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.panel-score .score-stats {
|
|
348
|
+
margin: 0;
|
|
349
|
+
font-size: 10px;
|
|
350
|
+
color: var(--text-muted);
|
|
351
|
+
text-transform: uppercase;
|
|
352
|
+
letter-spacing: 0.04em;
|
|
353
|
+
font-weight: 600;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* ——— Description of problems panel (top-right) ——— */
|
|
357
|
+
.panel-empty {
|
|
358
|
+
margin: 0;
|
|
359
|
+
font-size: 13px;
|
|
360
|
+
color: var(--text-muted);
|
|
361
|
+
font-style: italic;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.priority-inline {
|
|
365
|
+
display: grid;
|
|
366
|
+
grid-template-columns: 1fr 1fr;
|
|
367
|
+
gap: 0.75rem;
|
|
368
|
+
margin-top: 0.75rem;
|
|
369
|
+
padding-top: 0.75rem;
|
|
370
|
+
border-top: 1px solid var(--border-subtle);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.priority-inline h4 {
|
|
374
|
+
margin: 0 0 0.35rem;
|
|
375
|
+
font-size: 10px;
|
|
376
|
+
font-weight: 700;
|
|
377
|
+
text-transform: uppercase;
|
|
378
|
+
letter-spacing: 0.05em;
|
|
379
|
+
color: var(--tier-2);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.priority-inline .priority-list { margin: 0; }
|
|
383
|
+
|
|
384
|
+
@media (max-width: 600px) {
|
|
385
|
+
.priority-inline { grid-template-columns: 1fr; }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* ——— Heatmap panel (bottom-left) ——— */
|
|
197
389
|
.panel-heatmap .panel-header-heatmap {
|
|
198
390
|
display: flex;
|
|
199
391
|
flex-wrap: wrap;
|
|
@@ -218,10 +410,11 @@ body.dashboard-page {
|
|
|
218
410
|
border-radius: var(--radius);
|
|
219
411
|
}
|
|
220
412
|
|
|
221
|
-
/*
|
|
413
|
+
/* Problems panel: blue accent */
|
|
222
414
|
.panel-llm {
|
|
223
415
|
border-left: 3px solid var(--link);
|
|
224
416
|
}
|
|
417
|
+
.panel-llm .panel-header { border-left: none; }
|
|
225
418
|
|
|
226
419
|
/* ——— Banner ——— */
|
|
227
420
|
.no-llm-banner {
|
|
@@ -267,11 +460,11 @@ body.dashboard-page {
|
|
|
267
460
|
outline-offset: 1px;
|
|
268
461
|
}
|
|
269
462
|
|
|
270
|
-
.treemap-cell[data-severity="critical"] { background:
|
|
271
|
-
.treemap-cell[data-severity="high"] { background:
|
|
272
|
-
.treemap-cell[data-severity="medium"] { background:
|
|
273
|
-
.treemap-cell[data-severity="low"] { background:
|
|
274
|
-
.treemap-cell[data-severity="none"] { background: var(--border); color: var(--text-muted); border-color: var(--border); }
|
|
463
|
+
.treemap-cell[data-severity="critical"] { background: var(--tier-1); color: #fff; border-color: rgba(0,0,0,0.2); }
|
|
464
|
+
.treemap-cell[data-severity="high"] { background: var(--tier-2); color: #fff; border-color: rgba(0,0,0,0.15); }
|
|
465
|
+
.treemap-cell[data-severity="medium"] { background: var(--tier-3); color: #1a1a1a; border-color: rgba(0,0,0,0.1); }
|
|
466
|
+
.treemap-cell[data-severity="low"] { background: var(--tier-5); color: #fff; border-color: rgba(0,0,0,0.1); }
|
|
467
|
+
.treemap-cell[data-severity="none"] { background: var(--border); color: var(--text-muted); border-color: var(--border-subtle); }
|
|
275
468
|
|
|
276
469
|
.legend {
|
|
277
470
|
display: flex;
|
|
@@ -283,12 +476,12 @@ body.dashboard-page {
|
|
|
283
476
|
color: var(--text-muted);
|
|
284
477
|
}
|
|
285
478
|
|
|
286
|
-
.legend span { display: inline-flex; align-items: center; gap: 0.
|
|
287
|
-
.legend .swatch { width:
|
|
288
|
-
.legend .swatch-crit { background:
|
|
289
|
-
.legend .swatch-high { background:
|
|
290
|
-
.legend .swatch-med { background:
|
|
291
|
-
.legend .swatch-low { background:
|
|
479
|
+
.legend span { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 11px; font-weight: 600; }
|
|
480
|
+
.legend .swatch { width: 12px; height: 12px; border-radius: 3px; }
|
|
481
|
+
.legend .swatch-crit { background: var(--tier-1); }
|
|
482
|
+
.legend .swatch-high { background: var(--tier-2); }
|
|
483
|
+
.legend .swatch-med { background: var(--tier-3); }
|
|
484
|
+
.legend .swatch-low { background: var(--tier-5); }
|
|
292
485
|
.legend .swatch-none { background: var(--border); }
|
|
293
486
|
|
|
294
487
|
/* ——— Priority lists ——— */
|
|
@@ -354,12 +547,12 @@ body.dashboard-page {
|
|
|
354
547
|
border-radius: 3px;
|
|
355
548
|
}
|
|
356
549
|
|
|
357
|
-
.badge-critical { background:
|
|
358
|
-
.badge-high { background:
|
|
359
|
-
.badge-medium { background:
|
|
360
|
-
.badge-low { background:
|
|
550
|
+
.badge-critical { background: var(--tier-1); color: #fff; font-weight: 700; }
|
|
551
|
+
.badge-high { background: var(--tier-2); color: #fff; font-weight: 700; }
|
|
552
|
+
.badge-medium { background: var(--tier-3); color: #1a1a1a; font-weight: 700; }
|
|
553
|
+
.badge-low { background: var(--tier-5); color: #fff; font-weight: 700; }
|
|
361
554
|
.badge-none { background: var(--border); color: var(--text-muted); }
|
|
362
|
-
.badge-llm { background: var(--link); color: #fff; }
|
|
555
|
+
.badge-llm { background: var(--link); color: #fff; font-weight: 700; }
|
|
363
556
|
|
|
364
557
|
/* ——— Detail modal ——— */
|
|
365
558
|
#detail {
|
package/dist/reports/html.js
CHANGED
|
@@ -14,25 +14,25 @@ export async function generateHtmlReport(run, options) {
|
|
|
14
14
|
const html = buildHtml(run, title, darkMode, css, script);
|
|
15
15
|
await writeFile(outputPath, html, "utf-8");
|
|
16
16
|
}
|
|
17
|
-
/** Inline SVG badge: shield shape with tier number and "of 5". */
|
|
17
|
+
/** Inline SVG badge: shield shape with tier number and "of 5" — clean, bold, tier-colored. */
|
|
18
18
|
function buildScoreBadgeSvg(tier, fillColor) {
|
|
19
|
-
const lighter = adjustHexBrightness(fillColor, 1.
|
|
19
|
+
const lighter = adjustHexBrightness(fillColor, 1.25);
|
|
20
20
|
const shadowId = "badge-shadow-" + tier;
|
|
21
21
|
const gradientId = "badge-shine-" + tier;
|
|
22
22
|
return `<svg class="score-badge-svg" viewBox="0 0 140 168" xmlns="http://www.w3.org/2000/svg" role="img">
|
|
23
23
|
<defs>
|
|
24
24
|
<linearGradient id="${gradientId}" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
25
|
-
<stop offset="0%" style="stop-color:${lighter};stop-opacity:0.
|
|
25
|
+
<stop offset="0%" style="stop-color:${lighter};stop-opacity:0.6" />
|
|
26
26
|
<stop offset="100%" style="stop-color:${fillColor};stop-opacity:1" />
|
|
27
27
|
</linearGradient>
|
|
28
|
-
<filter id="${shadowId}" x="-
|
|
29
|
-
<feDropShadow dx="0" dy="
|
|
28
|
+
<filter id="${shadowId}" x="-40%" y="-30%" width="180%" height="180%">
|
|
29
|
+
<feDropShadow dx="0" dy="4" stdDeviation="6" flood-color="${fillColor}" flood-opacity="0.4"/>
|
|
30
30
|
</filter>
|
|
31
31
|
</defs>
|
|
32
32
|
<path fill="url(#${gradientId})" filter="url(#${shadowId})" d="M70 12 C108 12 128 38 128 72 C128 106 70 156 70 156 C70 156 12 106 12 72 C12 38 32 12 70 12 Z"/>
|
|
33
|
-
<path fill="none" stroke="rgba(255,255,255,0.
|
|
34
|
-
<text x="70" y="
|
|
35
|
-
<text x="70" y="
|
|
33
|
+
<path fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2" stroke-linejoin="round" d="M70 12 C108 12 128 38 128 72 C128 106 70 156 70 156 C70 156 12 106 12 72 C12 38 32 12 70 12 Z"/>
|
|
34
|
+
<text x="70" y="80" text-anchor="middle" class="score-badge-num" fill="white">${tier}</text>
|
|
35
|
+
<text x="70" y="102" text-anchor="middle" class="score-badge-of" fill="rgba(255,255,255,0.95)">of 5</text>
|
|
36
36
|
</svg>`;
|
|
37
37
|
}
|
|
38
38
|
function adjustHexBrightness(hex, factor) {
|
|
@@ -78,21 +78,6 @@ function buildHtml(run, title, darkMode, css, script) {
|
|
|
78
78
|
};
|
|
79
79
|
const tierColor = tierColors[cleanliness.tier] ?? "#666";
|
|
80
80
|
const scoreBadgeSvg = buildScoreBadgeSvg(cleanliness.tier, tierColor);
|
|
81
|
-
const llmPanelHtml = run.llmOverallAssessment || run.llmOverallRaw
|
|
82
|
-
? `
|
|
83
|
-
<div class="panel panel-llm">
|
|
84
|
-
<div class="panel-header">
|
|
85
|
-
<h2 class="panel-title">LLM overall assessment</h2>
|
|
86
|
-
</div>
|
|
87
|
-
<div class="panel-body">
|
|
88
|
-
<div class="llm-output">${run.llmOverallAssessment
|
|
89
|
-
? renderLlmOutputToHtml(run.llmOverallAssessment)
|
|
90
|
-
: '<div class="llm-prose">' +
|
|
91
|
-
escapeHtml(stripTrailingSeverityAndScore(run.llmOverallRaw ?? "")).replace(/\n/g, "<br>") +
|
|
92
|
-
"</div>"}</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>`
|
|
95
|
-
: "";
|
|
96
81
|
const statsLine = `${run.fileMetrics.length} files · ${run.debtItems.length} items · ${highCriticalCount} high/crit · ${hotspotCount} hotspots`;
|
|
97
82
|
return `<!DOCTYPE html>
|
|
98
83
|
<html lang="en" data-theme="${theme}">
|
|
@@ -112,67 +97,97 @@ function buildHtml(run, title, darkMode, css, script) {
|
|
|
112
97
|
${!hasLlm ? `<div class="no-llm-banner"><p class="no-llm-cta">Analysis run without LLM — for full results, run with LLM</p></div>` : ""}
|
|
113
98
|
<header class="dashboard-header">
|
|
114
99
|
<div class="dashboard-header-left">
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
<h1 class="dashboard-title">${escapeHtml(title)}</h1>
|
|
118
|
-
<p class="dashboard-blurb">${escapeHtml(cleanliness.description)}</p>
|
|
119
|
-
<span class="dashboard-meta">${escapeHtml(run.repoPath)}</span>
|
|
120
|
-
</div>
|
|
100
|
+
<h1 class="dashboard-title">${escapeHtml(title)}</h1>
|
|
101
|
+
<span class="dashboard-meta">${escapeHtml(run.repoPath)}</span>
|
|
121
102
|
</div>
|
|
122
103
|
<div class="dashboard-header-right">
|
|
123
|
-
<
|
|
104
|
+
<div class="dashboard-score tier-${cleanliness.tier}" aria-label="Score ${cleanliness.tier} of 5">
|
|
105
|
+
<span class="dashboard-score-value">${cleanliness.tier}</span>
|
|
106
|
+
<span class="dashboard-score-of">/ 5</span>
|
|
107
|
+
<span class="dashboard-score-label">${escapeHtml(cleanliness.label)}</span>
|
|
108
|
+
</div>
|
|
124
109
|
<span class="dashboard-date">${run.completedAt ?? run.startedAt}</span>
|
|
125
110
|
</div>
|
|
126
111
|
</header>
|
|
127
112
|
|
|
128
113
|
<main class="dashboard-main">
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
114
|
+
<div class="dashboard-grid-2x2">
|
|
115
|
+
<div class="dashboard-cell dashboard-cell-score">
|
|
116
|
+
<div class="panel panel-score panel-score-tier-${cleanliness.tier}">
|
|
117
|
+
<div class="panel-header panel-header-accent">
|
|
118
|
+
<h2 class="panel-title">Technical Debt Cleanliness Score</h2>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="panel-body panel-body-score">
|
|
121
|
+
<div class="score-display">
|
|
122
|
+
<div class="score-shield-wrap" aria-hidden="true">${scoreBadgeSvg}</div>
|
|
123
|
+
<div class="score-numeric">
|
|
124
|
+
<span class="score-num">${cleanliness.tier}</span>
|
|
125
|
+
<span class="score-of">of 5</span>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<p class="score-label">${escapeHtml(cleanliness.label)}</p>
|
|
129
|
+
<p class="score-desc">${escapeHtml(cleanliness.description)}</p>
|
|
130
|
+
<p class="score-stats">${statsLine}</p>
|
|
131
|
+
</div>
|
|
141
132
|
</div>
|
|
142
133
|
</div>
|
|
143
|
-
<div class="panel-body panel-body-heatmap">
|
|
144
|
-
<div id="treemap"></div>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
134
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
135
|
+
<div class="dashboard-cell dashboard-cell-problems">
|
|
136
|
+
<div class="panel panel-llm">
|
|
137
|
+
<div class="panel-header">
|
|
138
|
+
<h2 class="panel-title">Description of problems</h2>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="panel-body">
|
|
141
|
+
${run.llmOverallAssessment || run.llmOverallRaw
|
|
142
|
+
? `<div class="llm-output">${run.llmOverallAssessment
|
|
143
|
+
? renderLlmOutputToHtml(run.llmOverallAssessment)
|
|
144
|
+
: '<div class="llm-prose">' +
|
|
145
|
+
escapeHtml(stripTrailingSeverityAndScore(run.llmOverallRaw ?? "")).replace(/\n/g, "<br>") +
|
|
146
|
+
"</div>"}</div>`
|
|
147
|
+
: '<p class="panel-empty">Run with LLM for an overall assessment of problems.</p>'}
|
|
148
|
+
<div class="priority-inline">
|
|
149
|
+
<div class="priority-inline-col">
|
|
150
|
+
<h4>High impact, easier</h4>
|
|
151
|
+
<ul id="q1" class="priority-list"></ul>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="priority-inline-col">
|
|
154
|
+
<h4>High impact, harder</h4>
|
|
155
|
+
<ul id="q2" class="priority-list"></ul>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
156
159
|
</div>
|
|
157
160
|
</div>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
|
|
162
|
+
<div class="dashboard-cell dashboard-cell-heatmap">
|
|
163
|
+
<div class="panel panel-heatmap panel-header-accent-orange">
|
|
164
|
+
<div class="panel-header panel-header-heatmap">
|
|
165
|
+
<h2 class="panel-title">Files by debt</h2>
|
|
166
|
+
<p class="panel-desc">Size = complexity + churn. Color = severity. Click for details.</p>
|
|
167
|
+
<div class="legend legend-inline">
|
|
168
|
+
<span><span class="swatch swatch-crit"></span> Critical</span>
|
|
169
|
+
<span><span class="swatch swatch-high"></span> High</span>
|
|
170
|
+
<span><span class="swatch swatch-med"></span> Medium</span>
|
|
171
|
+
<span><span class="swatch swatch-low"></span> Low</span>
|
|
172
|
+
<span><span class="swatch swatch-none"></span> None</span>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="panel-body panel-body-heatmap">
|
|
176
|
+
<div id="treemap"></div>
|
|
177
|
+
</div>
|
|
165
178
|
</div>
|
|
166
179
|
</div>
|
|
167
|
-
</div>
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
<div class="dashboard-cell dashboard-cell-list">
|
|
182
|
+
<div class="panel panel-header-accent-blue">
|
|
183
|
+
<div class="panel-header">
|
|
184
|
+
<h2 class="panel-title">Ratings & files</h2>
|
|
185
|
+
<p class="panel-desc">Files rated above none by static or LLM. Click for full details.</p>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="panel-body">
|
|
188
|
+
<ul class="debt-list" id="debtList"></ul>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
176
191
|
</div>
|
|
177
192
|
</div>
|
|
178
193
|
</main>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tech-debt-visualizer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Language-agnostic CLI that analyzes repos and generates interactive technical debt visualizations with AI-powered insights",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|