tech-debt-visualizer 0.2.5 → 0.2.6

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.
@@ -138,15 +138,17 @@ body.dashboard-page {
138
138
  padding: 0.75rem 1rem;
139
139
  width: 100%;
140
140
  overflow: hidden;
141
+ display: flex;
142
+ flex-direction: column;
141
143
  }
142
144
 
143
145
  .dashboard-grid-2x2 {
146
+ flex: 1;
147
+ min-height: 0;
144
148
  display: grid;
145
149
  grid-template-columns: 1fr 1fr;
146
150
  grid-template-rows: auto 1fr;
147
151
  gap: 0.75rem;
148
- height: 100%;
149
- min-height: 0;
150
152
  align-items: stretch;
151
153
  }
152
154
 
@@ -170,7 +172,7 @@ body.dashboard-page {
170
172
  -webkit-overflow-scrolling: touch;
171
173
  }
172
174
 
173
- .dashboard-cell-score .panel-body-score { flex: 0 1 auto; overflow: visible; min-height: 0; }
175
+ .dashboard-cell-score .panel-body-score { flex: 1 1 auto; min-height: 0; }
174
176
 
175
177
  .dashboard-cell-heatmap .panel-body-heatmap,
176
178
  .dashboard-cell-list .panel-body {
@@ -193,6 +195,109 @@ body.dashboard-page {
193
195
  .dashboard-main { padding: 0.5rem 0.75rem; }
194
196
  }
195
197
 
198
+ /* ——— Footer: AI prompts button ——— */
199
+ .dashboard-footer {
200
+ flex-shrink: 0;
201
+ padding: 0.5rem 0;
202
+ border-top: 1px solid var(--border-subtle);
203
+ margin-top: 0.5rem;
204
+ }
205
+
206
+ .btn-ai-prompts {
207
+ font: inherit;
208
+ font-size: 13px;
209
+ font-weight: 600;
210
+ padding: 0.5rem 1rem;
211
+ background: var(--surface);
212
+ color: var(--text);
213
+ border: 1px solid var(--border);
214
+ border-radius: var(--radius);
215
+ cursor: pointer;
216
+ }
217
+
218
+ .btn-ai-prompts:hover {
219
+ background: var(--surface-hover);
220
+ border-color: var(--text-muted);
221
+ }
222
+
223
+ /* ——— AI prompts overlay (blank screen) ——— */
224
+ .overlay {
225
+ position: fixed;
226
+ inset: 0;
227
+ z-index: 200;
228
+ display: none;
229
+ align-items: center;
230
+ justify-content: center;
231
+ padding: 1rem;
232
+ }
233
+
234
+ .overlay.show {
235
+ display: flex;
236
+ }
237
+
238
+ .overlay-backdrop {
239
+ position: absolute;
240
+ inset: 0;
241
+ background: rgba(0, 0, 0, 0.5);
242
+ }
243
+
244
+ .overlay-panel {
245
+ position: relative;
246
+ background: var(--surface);
247
+ border: 1px solid var(--border);
248
+ border-radius: var(--radius);
249
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
250
+ max-width: 560px;
251
+ width: 100%;
252
+ max-height: 85vh;
253
+ display: flex;
254
+ flex-direction: column;
255
+ overflow: hidden;
256
+ }
257
+
258
+ .overlay-header {
259
+ display: flex;
260
+ align-items: center;
261
+ justify-content: space-between;
262
+ padding: 0.75rem 1rem;
263
+ border-bottom: 1px solid var(--border-subtle);
264
+ flex-shrink: 0;
265
+ }
266
+
267
+ .overlay-title {
268
+ margin: 0;
269
+ font-size: 1rem;
270
+ font-weight: 600;
271
+ color: var(--text);
272
+ }
273
+
274
+ .overlay-close {
275
+ font-size: 1.5rem;
276
+ line-height: 1;
277
+ padding: 0.25rem;
278
+ background: none;
279
+ border: none;
280
+ color: var(--text-muted);
281
+ cursor: pointer;
282
+ }
283
+
284
+ .overlay-close:hover {
285
+ color: var(--text);
286
+ }
287
+
288
+ .overlay-body {
289
+ padding: 1rem;
290
+ overflow: auto;
291
+ flex: 1;
292
+ min-height: 0;
293
+ }
294
+
295
+ .overlay-placeholder {
296
+ margin: 0;
297
+ font-size: 13px;
298
+ color: var(--text-muted);
299
+ }
300
+
196
301
  /* ——— Panels: borders, colored accents ——— */
197
302
  .panel {
198
303
  background: var(--surface);
@@ -209,16 +314,6 @@ body.dashboard-page {
209
314
  flex-shrink: 0;
210
315
  }
211
316
 
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
-
222
317
  [data-theme="light"] .panel-header {
223
318
  background: rgba(0, 0, 0, 0.02);
224
319
  }
@@ -247,77 +342,30 @@ body.dashboard-page {
247
342
  text-align: center;
248
343
  }
249
344
 
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
-
345
+ /* ——— Score panel (top-left): numeric score only, scrollable ——— */
260
346
  .panel-score .panel-body-score {
261
347
  text-align: center;
262
348
  padding: 1rem 0.85rem;
263
349
  }
264
350
 
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
351
  .score-numeric {
301
352
  display: flex;
302
353
  align-items: baseline;
303
- gap: 0.2rem;
354
+ justify-content: center;
355
+ gap: 0.25rem;
356
+ margin-bottom: 0.5rem;
304
357
  }
305
358
 
306
359
  .score-num {
307
- font-size: 2.25rem;
360
+ font-size: 2rem;
308
361
  font-weight: 800;
309
362
  line-height: 1;
310
363
  letter-spacing: -0.04em;
364
+ color: var(--text);
311
365
  }
312
366
 
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
367
  .score-of {
320
- font-size: 0.95rem;
368
+ font-size: 0.9rem;
321
369
  font-weight: 600;
322
370
  color: var(--text-muted);
323
371
  }
@@ -326,14 +374,9 @@ body.dashboard-page {
326
374
  margin: 0 0 0.2rem;
327
375
  font-size: 0.95rem;
328
376
  font-weight: 700;
377
+ color: var(--text);
329
378
  }
330
379
 
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
380
  .panel-score .score-desc {
338
381
  margin: 0 0 0.4rem;
339
382
  font-size: 12px;
@@ -376,7 +419,7 @@ body.dashboard-page {
376
419
  font-weight: 700;
377
420
  text-transform: uppercase;
378
421
  letter-spacing: 0.05em;
379
- color: var(--tier-2);
422
+ color: var(--text-muted);
380
423
  }
381
424
 
382
425
  .priority-inline .priority-list { margin: 0; }
@@ -410,11 +453,6 @@ body.dashboard-page {
410
453
  border-radius: var(--radius);
411
454
  }
412
455
 
413
- /* Problems panel: blue accent */
414
- .panel-llm {
415
- border-left: 3px solid var(--link);
416
- }
417
- .panel-llm .panel-header { border-left: none; }
418
456
 
419
457
  /* ——— Banner ——— */
420
458
  .no-llm-banner {
@@ -432,27 +470,33 @@ body.dashboard-page {
432
470
  margin: 0;
433
471
  }
434
472
 
435
- /* ——— Treemap ——— */
473
+ /* ——— Treemap: square boxes per file ——— */
436
474
  #treemap {
437
475
  display: flex;
438
476
  flex-wrap: wrap;
439
- gap: 4px;
440
- min-height: 160px;
477
+ gap: 6px;
478
+ min-height: 120px;
441
479
  padding: 0.25rem 0;
442
480
  }
443
481
 
444
482
  .treemap-cell {
483
+ width: 44px;
484
+ height: 44px;
485
+ min-width: 44px;
486
+ min-height: 44px;
487
+ flex: none;
445
488
  display: flex;
446
- align-items: flex-end;
447
- min-width: 64px;
448
- padding: 6px 8px;
449
- font-size: 11px;
489
+ align-items: center;
490
+ justify-content: center;
491
+ padding: 4px;
492
+ font-size: 10px;
450
493
  cursor: pointer;
451
494
  overflow: hidden;
452
495
  text-overflow: ellipsis;
453
496
  white-space: nowrap;
454
497
  border: 1px solid rgba(0, 0, 0, 0.15);
455
- border-radius: 2px;
498
+ border-radius: 4px;
499
+ text-align: center;
456
500
  }
457
501
 
458
502
  .treemap-cell:hover {
@@ -145,8 +145,6 @@ fileScores.forEach(function (_ref) {
145
145
  var cell = document.createElement("div");
146
146
  cell.className = "treemap-cell";
147
147
  cell.dataset.severity = severity;
148
- cell.style.flex = String((score / maxScore) * 100) + " 1 80px";
149
- cell.style.minWidth = "72px";
150
148
  cell.title = file + llmScore;
151
149
  cell.textContent = file.split("/").pop() || file;
152
150
  cell.addEventListener("click", function () { showDetail(file, items); });
@@ -319,3 +317,22 @@ function showDetail(file, items) {
319
317
  if (e.target === panel) panel.classList.remove("show");
320
318
  };
321
319
  }
320
+
321
+ (function () {
322
+ var btn = document.getElementById("btnAiPrompts");
323
+ var overlay = document.getElementById("aiPromptsOverlay");
324
+ var closeBtn = document.getElementById("closeAiPrompts");
325
+ var backdrop = overlay && overlay.querySelector(".overlay-backdrop");
326
+ if (!btn || !overlay) return;
327
+ function open() {
328
+ overlay.classList.add("show");
329
+ overlay.setAttribute("aria-hidden", "false");
330
+ }
331
+ function close() {
332
+ overlay.classList.remove("show");
333
+ overlay.setAttribute("aria-hidden", "true");
334
+ }
335
+ btn.addEventListener("click", open);
336
+ if (closeBtn) closeBtn.addEventListener("click", close);
337
+ if (backdrop) backdrop.addEventListener("click", close);
338
+ })();
@@ -69,15 +69,6 @@ function buildHtml(run, title, darkMode, css, script) {
69
69
  });
70
70
  const highCriticalCount = run.debtItems.filter((d) => d.severity === "high" || d.severity === "critical").length;
71
71
  const hotspotCount = run.fileMetrics.filter((m) => (m.hotspotScore ?? 0) > 0.3).length;
72
- const tierColors = {
73
- 1: "#c00",
74
- 2: "#e85d00",
75
- 3: "#b8860b",
76
- 4: "#069",
77
- 5: "#0a6b0a",
78
- };
79
- const tierColor = tierColors[cleanliness.tier] ?? "#666";
80
- const scoreBadgeSvg = buildScoreBadgeSvg(cleanliness.tier, tierColor);
81
72
  const statsLine = `${run.fileMetrics.length} files · ${run.debtItems.length} items · ${highCriticalCount} high/crit · ${hotspotCount} hotspots`;
82
73
  return `<!DOCTYPE html>
83
74
  <html lang="en" data-theme="${theme}">
@@ -113,17 +104,14 @@ function buildHtml(run, title, darkMode, css, script) {
113
104
  <main class="dashboard-main">
114
105
  <div class="dashboard-grid-2x2">
115
106
  <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">
107
+ <div class="panel panel-score">
108
+ <div class="panel-header">
118
109
  <h2 class="panel-title">Technical Debt Cleanliness Score</h2>
119
110
  </div>
120
111
  <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>
112
+ <div class="score-numeric">
113
+ <span class="score-num">${cleanliness.tier}</span>
114
+ <span class="score-of">of 5</span>
127
115
  </div>
128
116
  <p class="score-label">${escapeHtml(cleanliness.label)}</p>
129
117
  <p class="score-desc">${escapeHtml(cleanliness.description)}</p>
@@ -132,8 +120,27 @@ function buildHtml(run, title, darkMode, css, script) {
132
120
  </div>
133
121
  </div>
134
122
 
123
+ <div class="dashboard-cell dashboard-cell-heatmap">
124
+ <div class="panel panel-heatmap">
125
+ <div class="panel-header panel-header-heatmap">
126
+ <h2 class="panel-title">Files by debt</h2>
127
+ <p class="panel-desc">Size = complexity + churn. Color = severity. Click for details.</p>
128
+ <div class="legend legend-inline">
129
+ <span><span class="swatch swatch-crit"></span> Critical</span>
130
+ <span><span class="swatch swatch-high"></span> High</span>
131
+ <span><span class="swatch swatch-med"></span> Medium</span>
132
+ <span><span class="swatch swatch-low"></span> Low</span>
133
+ <span><span class="swatch swatch-none"></span> None</span>
134
+ </div>
135
+ </div>
136
+ <div class="panel-body panel-body-heatmap">
137
+ <div id="treemap"></div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+
135
142
  <div class="dashboard-cell dashboard-cell-problems">
136
- <div class="panel panel-llm">
143
+ <div class="panel">
137
144
  <div class="panel-header">
138
145
  <h2 class="panel-title">Description of problems</h2>
139
146
  </div>
@@ -159,27 +166,8 @@ function buildHtml(run, title, darkMode, css, script) {
159
166
  </div>
160
167
  </div>
161
168
 
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>
178
- </div>
179
- </div>
180
-
181
169
  <div class="dashboard-cell dashboard-cell-list">
182
- <div class="panel panel-header-accent-blue">
170
+ <div class="panel">
183
171
  <div class="panel-header">
184
172
  <h2 class="panel-title">Ratings & files</h2>
185
173
  <p class="panel-desc">Files rated above none by static or LLM. Click for full details.</p>
@@ -190,8 +178,25 @@ function buildHtml(run, title, darkMode, css, script) {
190
178
  </div>
191
179
  </div>
192
180
  </div>
181
+
182
+ <div class="dashboard-footer">
183
+ <button type="button" class="btn-ai-prompts" id="btnAiPrompts">AI cleanup prompts</button>
184
+ </div>
193
185
  </main>
194
186
 
187
+ <div id="aiPromptsOverlay" class="overlay" aria-hidden="true">
188
+ <div class="overlay-backdrop"></div>
189
+ <div class="overlay-panel">
190
+ <div class="overlay-header">
191
+ <h2 class="overlay-title">AI cleanup prompts</h2>
192
+ <button type="button" class="overlay-close" id="closeAiPrompts" aria-label="Close">&times;</button>
193
+ </div>
194
+ <div class="overlay-body">
195
+ <p class="overlay-placeholder">Prompts to pass into AI for cleaning up the codebase will appear here.</p>
196
+ </div>
197
+ </div>
198
+ </div>
199
+
195
200
  <div id="detail">
196
201
  <div class="panel">
197
202
  <h3 id="detailTitle"></h3>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tech-debt-visualizer",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
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",