@ingcrea/aumic-tailwind-killer 3.1.6 → 4.1.3
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/README.md +116 -102
- package/aumic-lexicon.duckdb +0 -0
- package/dist/index.js +891 -685
- package/dist/worker.js +1 -1
- package/package.json +11 -9
package/dist/index.js
CHANGED
|
@@ -21,9 +21,10 @@ const parser_1 = require("./ast/parser");
|
|
|
21
21
|
const provider_1 = require("./ai/provider");
|
|
22
22
|
const scraper_1 = require("./core/scraper");
|
|
23
23
|
// Versión dinámica
|
|
24
|
-
let
|
|
24
|
+
let userConfig = {};
|
|
25
|
+
let pkgVersion = '4.1.3';
|
|
25
26
|
try {
|
|
26
|
-
pkgVersion = JSON.parse(fs_extra_1.default.readFileSync(path_1.default.join(__dirname, '../package.json'), 'utf-8')).version;
|
|
27
|
+
pkgVersion = JSON.parse(fs_extra_1.default.readFileSync(path_1.default.join(__dirname, '../package.json'), 'utf-8').replace(/^\uFEFF/, '')).version;
|
|
27
28
|
}
|
|
28
29
|
catch (e) { }
|
|
29
30
|
async function runConcurrent(items, concurrency, task) {
|
|
@@ -117,11 +118,11 @@ function generateReport(mapping, targetDir, isSimulate = true) {
|
|
|
117
118
|
if (counts[cat] !== undefined)
|
|
118
119
|
counts[cat]++;
|
|
119
120
|
const c = categoryMeta[cat] || categoryMeta.molecules;
|
|
120
|
-
rows.push(`<tr data-cat="${cat}">
|
|
121
|
-
<td class="tw-cell copyable" onclick="copyText(this)">${orig}</td>
|
|
122
|
-
<td class="aumic-cell copyable" onclick="copyText(this)">${map.aumicClass}</td>
|
|
123
|
-
<td class="occ-cell" data-occ="${occ}"><div class="occ-bar" style="width: ${Math.min(100, occ * 2)}%; background: ${c.text}"></div><span>${occ}</span></td>
|
|
124
|
-
<td><span class="badge" style="border-color:${c.border};color:${c.text};background:${c.bg}">${c.label}</span></td>
|
|
121
|
+
rows.push(`<tr data-cat="${cat}">
|
|
122
|
+
<td class="tw-cell copyable" onclick="copyText(this)">${orig}</td>
|
|
123
|
+
<td class="aumic-cell copyable" onclick="copyText(this)">${map.aumicClass}</td>
|
|
124
|
+
<td class="occ-cell" data-occ="${occ}"><div class="occ-bar" style="width: ${Math.min(100, occ * 2)}%; background: ${c.text}"></div><span>${occ}</span></td>
|
|
125
|
+
<td><span class="badge" style="border-color:${c.border};color:${c.text};background:${c.bg}">${c.label}</span></td>
|
|
125
126
|
</tr>`);
|
|
126
127
|
}
|
|
127
128
|
const savedBytes = originalBytes - aumicBytes;
|
|
@@ -155,675 +156,675 @@ function generateReport(mapping, targetDir, isSimulate = true) {
|
|
|
155
156
|
{ label: 'Galaxias', value: counts.galaxies, color: '#facc15' }
|
|
156
157
|
];
|
|
157
158
|
// Top 5 Criminals
|
|
158
|
-
const top5 = sortedMappings.slice(0, 5).map((m, i) => `
|
|
159
|
-
<div class="criminal">
|
|
160
|
-
<div class="c-rank">#${i + 1}</div>
|
|
161
|
-
<div class="c-info">
|
|
162
|
-
<div class="c-class">${m[0]}</div>
|
|
163
|
-
<div class="c-stats">Repeticiones: <strong>${m[1].occurrences || 1}</strong> | Categoría: ${m[1].category}</div>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
159
|
+
const top5 = sortedMappings.slice(0, 5).map((m, i) => `
|
|
160
|
+
<div class="criminal">
|
|
161
|
+
<div class="c-rank">#${i + 1}</div>
|
|
162
|
+
<div class="c-info">
|
|
163
|
+
<div class="c-class">${m[0]}</div>
|
|
164
|
+
<div class="c-stats">Repeticiones: <strong>${m[1].occurrences || 1}</strong> | Categoría: ${m[1].category}</div>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
166
167
|
`).join('');
|
|
167
|
-
const html = `<!DOCTYPE html>
|
|
168
|
-
<html lang="es"><head><meta charset="UTF-8"><title>AUM-IC · Dashboard C4I</title><style>
|
|
169
|
-
:root { --bg: #030712; --panel: rgba(15, 23, 42, 0.7); --panel-hover: #1e293b; --text: #e2e8f0; --muted: #64748b; --border: rgba(51, 65, 85, 0.6); --accent: #00e5ff; }
|
|
170
|
-
*{box-sizing:border-box;margin:0;padding:0}
|
|
171
|
-
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;padding:2rem 3rem;position:relative;overflow-x:hidden;}
|
|
172
|
-
#bgCanvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
|
|
173
|
-
.content-wrapper { position: relative; z-index: 10; }
|
|
174
|
-
header{display:flex;align-items:center;justify-content:space-between;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border)}
|
|
175
|
-
header h1{font-size:1.8rem;font-weight:900;color:#fff;letter-spacing:-0.5px}header h1 span{color:var(--accent);text-shadow:0 0 10px rgba(0,229,255,0.4)}
|
|
176
|
-
.subtitle{font-size:0.85rem;color:var(--muted);margin-top:6px}.safe-tag{background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.3);color:var(--accent);font-size:0.75rem;padding:6px 16px;border-radius:999px;font-weight:700;box-shadow:0 0 15px rgba(0,229,255,0.1)}
|
|
177
|
-
.dashboard-grid { display: grid; grid-template-columns: 320px 1fr; gap: 2rem; }
|
|
178
|
-
.sidebar { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
179
|
-
.main-view { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
180
|
-
|
|
181
|
-
/* Panels */
|
|
182
|
-
.panel { background: var(--panel); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); padding: 1.5rem; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
|
|
183
|
-
.panel h2 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 1rem; }
|
|
184
|
-
|
|
185
|
-
/* Canvas Chart */
|
|
186
|
-
.chart-container { display: flex; justify-content: center; align-items: center; margin-bottom: 1rem; position: relative; height: 200px; }
|
|
187
|
-
.chart-center-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; pointer-events: none; }
|
|
188
|
-
.chart-center-overlay .score { font-size: 2.5rem; font-weight: 900; color: ${gradeColor}; line-height: 1; text-shadow: 0 0 15px ${gradeColor}44; }
|
|
189
|
-
.chart-center-overlay .score-lbl { font-size: 0.6rem; color: var(--muted); text-transform: uppercase; letter-spacing: 1px; margin-top: 4px; }
|
|
190
|
-
.legend { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 0.75rem; }
|
|
191
|
-
.leg-item { display: flex; align-items: center; gap: 6px; }
|
|
192
|
-
.leg-color { width: 10px; height: 10px; border-radius: 50%; }
|
|
193
|
-
|
|
194
|
-
/* Hero Metrics */
|
|
195
|
-
.metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
|
|
196
|
-
.metric { background: rgba(0,0,0,0.3); padding: 1.2rem; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05); backdrop-filter: blur(5px); }
|
|
197
|
-
.metric h3 { font-size: 1.8rem; font-weight: 900; color: #fff; line-height: 1; margin-bottom: 4px; }
|
|
198
|
-
.metric p { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
|
|
199
|
-
.highlight { color: #34d399 !important; text-shadow: 0 0 10px rgba(52,211,153,0.4); }
|
|
200
|
-
.highlight-psi { color: #facc15 !important; }
|
|
201
|
-
|
|
202
|
-
/* Criminals */
|
|
203
|
-
.criminal { display: flex; gap: 1rem; align-items: center; padding: 10px; background: rgba(0,0,0,0.2); border-radius: 8px; margin-bottom: 8px; }
|
|
204
|
-
.c-rank { font-size: 1.2rem; font-weight: 900; color: #ef4444; width: 30px; text-align: center; }
|
|
205
|
-
.c-info { flex: 1; min-width: 0; }
|
|
206
|
-
.c-class { font-family: 'Fira Code', monospace; font-size: 0.75rem; color: #f472b6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 4px; }
|
|
207
|
-
.c-stats { font-size: 0.65rem; color: var(--muted); }
|
|
208
|
-
|
|
209
|
-
/* Table Controls */
|
|
210
|
-
.toolbar{display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap; margin-bottom: 1.5rem;}
|
|
211
|
-
.fbtn{background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#94a3b8;font-size:0.75rem;padding:8px 16px;border-radius:8px;cursor:pointer;transition:all 0.2s;font-weight:500}
|
|
212
|
-
.fbtn:hover,.fbtn.active{color:#fff;border-color:var(--accent);background:rgba(0,229,255,0.1);box-shadow:0 0 10px rgba(0,229,255,0.2)}
|
|
213
|
-
.search{margin-left:auto;background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#fff;font-size:0.8rem;padding:8px 16px;border-radius:8px;outline:none;width:220px;transition:all 0.2s}
|
|
214
|
-
.search:focus{border-color:var(--accent);box-shadow:0 0 0 2px rgba(0,229,255,0.2)}
|
|
215
|
-
.page-size-sel { background: rgba(15, 23, 42, 0.9); color: #fff; background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#fff;font-size:0.75rem;padding:8px;border-radius:8px;outline:none; cursor:pointer;}
|
|
216
|
-
|
|
217
|
-
/* Table */
|
|
218
|
-
.table-container{border-radius:12px;border:1px solid var(--border);overflow:hidden;background:rgba(0,0,0,0.2);}
|
|
219
|
-
table{width:100%;border-collapse:collapse;font-size:0.8rem}
|
|
220
|
-
th{background:rgba(0,0,0,0.3);color:var(--muted);text-align:left;padding:12px 16px;border-bottom:1px solid var(--border);font-weight:600;text-transform:uppercase;letter-spacing:1px;font-size:0.7rem;cursor:pointer;user-select:none}
|
|
221
|
-
th:hover{color:#fff}
|
|
222
|
-
td{padding:12px 16px;border-bottom:1px solid rgba(255,255,255,0.02);vertical-align:middle;transition:background 0.15s}
|
|
223
|
-
tr:hover td{background:rgba(255,255,255,0.05)}
|
|
224
|
-
.tw-cell{font-family:'Fira Code',Consolas,monospace;color:#f472b6;font-size:0.75rem;max-width:300px;word-break:break-all}
|
|
225
|
-
.aumic-cell{font-family:'Fira Code',Consolas,monospace;color:#38bdf8;font-size:0.75rem;white-space:nowrap;font-weight:600}
|
|
226
|
-
.occ-cell{display:flex;align-items:center;gap:10px;font-family:'Fira Code',monospace;font-weight:bold;color:#fff}
|
|
227
|
-
.occ-bar{height:6px;border-radius:3px;opacity:0.8}
|
|
228
|
-
.badge{font-size:0.65rem;padding:4px 10px;border-radius:999px;border:1px solid;font-weight:800;white-space:nowrap;text-transform:uppercase;letter-spacing:0.5px}
|
|
229
|
-
|
|
230
|
-
/* Pagination */
|
|
231
|
-
.pagination { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; background: rgba(0,0,0,0.3); border-top: 1px solid var(--border); }
|
|
232
|
-
.pag-controls { display: flex; gap: 6px; align-items: center; background: rgba(15,23,42,0.6); padding: 4px; border-radius: 8px; border: 1px solid var(--border); }
|
|
233
|
-
.pag-btn { background: transparent; border: none; color: var(--muted); padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 0.75rem; transition: 0.2s; min-width: 32px; text-align: center; font-weight: 600; }
|
|
234
|
-
.pag-btn:hover:not(:disabled) { background: rgba(255,255,255,0.05); color: #fff; }
|
|
235
|
-
.pag-btn.active { background: rgba(0,229,255,0.15); color: var(--accent); box-shadow: inset 0 0 0 1px rgba(0,229,255,0.3); }
|
|
236
|
-
.pag-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
|
237
|
-
.pag-info { font-size: 0.75rem; color: var(--muted); }
|
|
238
|
-
.pag-dots { color: var(--muted); font-size: 0.75rem; font-weight: bold; padding: 0 4px; }
|
|
239
|
-
|
|
240
|
-
/* Footer */
|
|
241
|
-
.footer { position: relative; bottom: 0; left: 0; width: 100%; text-align: center; padding: 20px; font-size: 0.75rem; color: var(--muted); border-top: 1px solid rgba(255,255,255,0.05); background: rgba(0,0,0,0.3); backdrop-filter: blur(5px); margin-top: auto; }
|
|
242
|
-
.footer a { color: var(--accent); text-decoration: none; font-weight: 600; transition: color 0.2s; }
|
|
243
|
-
.footer a:hover { color: #fff; text-shadow: 0 0 10px var(--accent); }
|
|
244
|
-
.page-size-sel option { background: #0f172a; color: #fff; }
|
|
245
|
-
/* Export & Toast */
|
|
246
|
-
.export-group-top { display: flex; gap: 8px; margin-left: auto; align-items: center; } .export-group-top .fbtn { background: rgba(0,229,255,0.05); }
|
|
247
|
-
.toast { position: fixed; bottom: 20px; right: 20px; background: rgba(0, 229, 255, 0.15); border: 1px solid var(--accent); color: #fff; padding: 10px 20px; border-radius: 8px; font-size: 0.8rem; font-weight: 600; box-shadow: 0 5px 15px rgba(0,229,255,0.2); backdrop-filter: blur(5px); transform: translateY(100px); opacity: 0; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 9999; }
|
|
248
|
-
.toast.show { transform: translateY(0); opacity: 1; }
|
|
249
|
-
.copyable { cursor: pointer; transition: color 0.2s; position: relative; }
|
|
250
|
-
.copyable:hover { color: #fff; text-shadow: 0 0 8px rgba(255,255,255,0.5); }
|
|
251
|
-
.copyable::after { content: 'Copiar'; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: #fff; font-size: 0.6rem; padding: 2px 6px; border-radius: 4px; opacity: 0; pointer-events: none; transition: opacity 0.2s; }
|
|
252
|
-
.copyable:hover::after { opacity: 1; }
|
|
253
|
-
|
|
254
|
-
/* Sticky Header */
|
|
255
|
-
.table-container { overflow-x: auto; }
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
/* Print PDF (Mesa Directiva) */
|
|
259
|
-
@media print {
|
|
260
|
-
body { background: #fff !important; color: #000 !important; padding: 0 !important; font-size: 10pt; }
|
|
261
|
-
#bgCanvas, .toolbar, .pagination, .safe-tag, .export-group-top, .footer, .toast { display: none !important; }
|
|
262
|
-
.content-wrapper { padding: 0 !important; max-width: 100% !important; }
|
|
263
|
-
header { border-bottom: 2px solid #000; padding-bottom: 10px; margin-bottom: 20px; flex-direction: column !important; align-items: flex-start !important; }
|
|
264
|
-
header h1 { color: #000 !important; text-shadow: none !important; margin: 0; }
|
|
265
|
-
header h1 span { color: #000 !important; }
|
|
266
|
-
|
|
267
|
-
.dashboard-grid { display: block !important; }
|
|
268
|
-
.sidebar { display: flex !important; flex-direction: row !important; gap: 20px !important; margin-bottom: 20px !important; page-break-inside: avoid; }
|
|
269
|
-
.sidebar .panel { flex: 1; border: 1px solid #cbd5e1 !important; padding: 15px !important; border-radius: 8px !important; }
|
|
270
|
-
|
|
271
|
-
.panel { background: none !important; border: none !important; box-shadow: none !important; padding: 0 !important; }
|
|
272
|
-
|
|
273
|
-
.metrics-grid { display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 10px !important; margin-bottom: 20px !important; page-break-inside: avoid; }
|
|
274
|
-
.metric { background: #f8fafc !important; border: 1px solid #cbd5e1 !important; padding: 10px !important; border-radius: 8px !important; }
|
|
275
|
-
.metric h3 { color: #000 !important; text-shadow: none !important; font-size: 1.2rem; margin-bottom: 5px; }
|
|
276
|
-
.metric p { color: #333 !important; font-size: 0.8rem; }
|
|
277
|
-
|
|
278
|
-
.criteria-box { background: #f8fafc !important; border: 1px solid #cbd5e1 !important; color: #000 !important; }
|
|
279
|
-
.criteria-box strong { color: #000 !important; }
|
|
280
|
-
.criteria-box span { color: #000 !important; font-weight: bold; }
|
|
281
|
-
|
|
282
|
-
.chart-center-overlay .score { color: #000 !important; text-shadow: none !important; }
|
|
283
|
-
.chart-center-overlay .score-lbl { color: #333 !important; }
|
|
284
|
-
|
|
285
|
-
.leg-item { color: #000 !important; }
|
|
286
|
-
|
|
287
|
-
.table-container { max-height: none !important; border: none !important; overflow: visible !important; }
|
|
288
|
-
table { border-collapse: collapse !important; width: 100% !important; page-break-inside: auto; }
|
|
289
|
-
tr { page-break-inside: avoid; page-break-after: auto; }
|
|
290
|
-
th, td { border: 1px solid #cbd5e1 !important; color: #000 !important; padding: 6px !important; font-size: 9pt !important; }
|
|
291
|
-
th { background: #f1f5f9 !important; color: #000 !important; font-weight: bold; }
|
|
292
|
-
.tw-cell, .aumic-cell { color: #000 !important; font-weight: normal; }
|
|
293
|
-
.occ-bar { background: #94a3b8 !important; }
|
|
294
|
-
|
|
295
|
-
@page { margin: 1cm; size: auto; }
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
</style></head><body style="display: flex; flex-direction: column;">
|
|
299
|
-
|
|
300
|
-
<canvas id="bgCanvas"></canvas>
|
|
301
|
-
|
|
302
|
-
<div class="content-wrapper">
|
|
303
|
-
<header>
|
|
304
|
-
<div><h1>⚔️ <span>AUM-IC</span> · Centro de Inteligencia</h1>
|
|
305
|
-
<p class="subtitle">Análisis Forense completado exitosamente sin mutación en disco.</p></div>
|
|
306
|
-
<div class="export-group-top" style="display:flex; gap:8px; margin-left: 20px;">
|
|
307
|
-
<button class="fbtn" onclick="exportCSV()">⬇️ CSV</button><button class="fbtn" onclick="exportMD()">⬇️ MD</button><button class="fbtn" onclick="window.print()">🖨️ PDF</button>
|
|
308
|
-
</div>
|
|
309
|
-
<div class="safe-tag" style="align-items: flex-end; display: flex; flex-direction: column;">
|
|
310
|
-
<span>${isSimulate ? 'MODO DRY-RUN ACTIVO' : 'MUTACIÓN AUM-IC COMPLETADA'}</span>
|
|
311
|
-
<span style="font-size: 0.65rem; opacity: 0.8; margin-top: 2px;">v${pkgVersion}</span>
|
|
312
|
-
</div>
|
|
313
|
-
</header>
|
|
314
|
-
|
|
315
|
-
<main class="dashboard-grid">
|
|
316
|
-
<aside class="sidebar">
|
|
317
|
-
<article class="panel">
|
|
318
|
-
<h2>Mapeo Estructural</h2>
|
|
319
|
-
<div class="chart-container">
|
|
320
|
-
<canvas id="donutCanvas" width="220" height="220"></canvas>
|
|
321
|
-
<div class="chart-center-overlay">
|
|
322
|
-
<div class="score">${grade}</div>
|
|
323
|
-
<div class="score-lbl">Rank</div>
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
<div class="legend">
|
|
327
|
-
<div class="leg-item"><div class="leg-color" style="background:#22d3ee"></div>Átomos (${counts.atoms})</div>
|
|
328
|
-
<div class="leg-item"><div class="leg-color" style="background:#a78bfa"></div>Moléculas (${counts.molecules})</div>
|
|
329
|
-
<div class="leg-item"><div class="leg-color" style="background:#34d399"></div>Organismos (${counts.organisms})</div>
|
|
330
|
-
<div class="leg-item"><div class="leg-color" style="background:#fb923c"></div>Ecosistemas (${counts.ecosystems})</div>
|
|
331
|
-
<div class="leg-item"><div class="leg-color" style="background:#facc15"></div>Galaxias (${counts.galaxies})</div>
|
|
332
|
-
</div>
|
|
333
|
-
<div class="criteria-box" style="margin-top: 1.5rem; padding: 1rem; background: rgba(0,0,0,0.2); border-radius: 8px; border: 1px solid var(--border); font-size: 0.75rem; color: var(--muted); line-height: 1.5;">
|
|
334
|
-
<strong style="color: #fff; margin-bottom: 0.5rem; display: block;">Criterio de Evaluación AUM-IC</strong>
|
|
335
|
-
<ul style="margin: 0; padding-left: 1rem; list-style: square;">
|
|
336
|
-
<li><span style="color:#22d3ee">Átomos:</span> Utilidades base simples (p-4, m-2, flex).</li>
|
|
337
|
-
<li><span style="color:#a78bfa">Moléculas:</span> Estilos condicionales y variantes (hover:, focus:).</li>
|
|
338
|
-
<li><span style="color:#34d399">Organismos:</span> Cadenas largas y componentes estructurales.</li>
|
|
339
|
-
<li><span style="color:#fb923c">Ecosistemas:</span> Combinaciones de Layouts complejos (Grid/Flex).</li>
|
|
340
|
-
<li><span style="color:#facc15">Galaxias:</span> Declaraciones globales masivas o de alta densidad.</li>
|
|
341
|
-
</ul>
|
|
342
|
-
<div style="margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid rgba(255,255,255,0.1);">
|
|
343
|
-
<strong style="color: #fff; display:block; margin-bottom: 0.3rem;">🏆 Rank (Score) & Eficiencia</strong>
|
|
344
|
-
<div style="margin-bottom: 0.6rem; color: #94a3b8;">La <b>Eficiencia de Refactorización</b> mide el porcentaje exacto de peso (bytes) que AUM-IC logró purgar del DOM frente al HTML inflado original.</div>
|
|
345
|
-
<div style="display: flex; gap: 6px; flex-wrap: wrap; font-size: 0.7rem;">
|
|
346
|
-
<span style="background: rgba(250,204,21,0.15); color:#facc15; padding: 3px 6px; border-radius: 4px; border: 1px solid #facc1544;"><b>S</b> ≥ 70%</span>
|
|
347
|
-
<span style="background: rgba(52,211,153,0.15); color:#34d399; padding: 3px 6px; border-radius: 4px; border: 1px solid #34d39944;"><b>A</b> ≥ 50%</span>
|
|
348
|
-
<span style="background: rgba(34,211,238,0.15); color:#22d3ee; padding: 3px 6px; border-radius: 4px; border: 1px solid #22d3ee44;"><b>B</b> ≥ 30%</span>
|
|
349
|
-
<span style="background: rgba(167,139,250,0.15); color:#a78bfa; padding: 3px 6px; border-radius: 4px; border: 1px solid #a78bfa44;"><b>C</b> ≥ 15%</span>
|
|
350
|
-
<span style="background: rgba(239,68,68,0.15); color:#ef4444; padding: 3px 6px; border-radius: 4px; border: 1px solid #ef444444;"><b>D</b> < 15%</span>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
</div>
|
|
354
|
-
</article>
|
|
355
|
-
|
|
356
|
-
<article class="panel">
|
|
357
|
-
<h2>☠️ Top 5 Ofensores del DOM</h2>
|
|
358
|
-
${top5}
|
|
359
|
-
</article>
|
|
360
|
-
</aside>
|
|
361
|
-
|
|
362
|
-
<section class="main-view">
|
|
363
|
-
<div class="metrics-grid">
|
|
364
|
-
<div class="metric">
|
|
365
|
-
<h3 class="highlight">🔥 ${savedKB} KB</h3>
|
|
366
|
-
<p>Peso/Tamaño Estimado Salvado</p>
|
|
367
|
-
</div>
|
|
368
|
-
<div class="metric">
|
|
369
|
-
<h3 class="highlight-psi">🚀 +${psiImpact} pts</h3>
|
|
370
|
-
<p>Impacto Estimado Google PSI</p>
|
|
371
|
-
</div>
|
|
372
|
-
<div class="metric">
|
|
373
|
-
<h3>${efficiency}%</h3>
|
|
374
|
-
<p>Eficiencia de Refactorización</p>
|
|
375
|
-
</div>
|
|
376
|
-
<div class="metric">
|
|
377
|
-
<h3>${mapping.size}</h3>
|
|
378
|
-
<p>Clases Únicas Tailwind</p>
|
|
379
|
-
</div>
|
|
380
|
-
<div class="metric">
|
|
381
|
-
<h3>${totalOccurrences}</h3>
|
|
382
|
-
<p>Instancias Totales Detectadas</p>
|
|
383
|
-
</div>
|
|
384
|
-
<div class="metric">
|
|
385
|
-
<h3>${totalOccurrences - mapping.size}</h3>
|
|
386
|
-
<p>Redundancia Estructural (Repetidas)</p>
|
|
387
|
-
</div>
|
|
388
|
-
</div>
|
|
389
|
-
|
|
390
|
-
<article class="panel">
|
|
391
|
-
<nav class="toolbar">
|
|
392
|
-
<button class="fbtn active" onclick="filter('all',this)">Todos</button>
|
|
393
|
-
<button class="fbtn" onclick="filter('atoms',this)">Átomos</button>
|
|
394
|
-
<button class="fbtn" onclick="filter('molecules',this)">Moléculas</button>
|
|
395
|
-
<button class="fbtn" onclick="filter('organisms',this)">Organismos</button>
|
|
396
|
-
<button class="fbtn" onclick="filter('ecosystems',this)">Ecosistemas</button>
|
|
397
|
-
<button class="fbtn" onclick="filter('galaxies',this)">Galaxias</button>
|
|
398
|
-
|
|
399
|
-
<input class="search" type="text" id="searchInput" placeholder="Buscar clase (Regex)..." oninput="search(this.value)">
|
|
400
|
-
<select class="page-size-sel" id="pageSizeSelect" onchange="changePageSize(this.value)">
|
|
401
|
-
<option value="20">20 por pág</option>
|
|
402
|
-
<option value="50">50 por pág</option>
|
|
403
|
-
<option value="100">100 por pág</option>
|
|
404
|
-
<option value="all">TODOS</option>
|
|
405
|
-
</select>
|
|
406
|
-
</nav>
|
|
407
|
-
<section class="table-container">
|
|
408
|
-
<table id="table">
|
|
409
|
-
<thead><tr>
|
|
410
|
-
<th onclick="sortTable(0, 'str')">Clase Original (Tailwind) ↕</th>
|
|
411
|
-
<th onclick="sortTable(1, 'str')">Clase AUM-IC Transmutada ↕</th>
|
|
412
|
-
<th onclick="sortTable(2, 'num')">Frecuencia ↕</th>
|
|
413
|
-
<th onclick="sortTable(3, 'str')">Nivel ↕</th>
|
|
414
|
-
</tr></thead>
|
|
415
|
-
<tbody id="tbody">${rows.join('')}</tbody>
|
|
416
|
-
</table>
|
|
417
|
-
<div class="pagination">
|
|
418
|
-
<span class="pag-info" id="page-info"></span>
|
|
419
|
-
<div class="pag-controls" id="pag-controls"></div>
|
|
420
|
-
</div>
|
|
421
|
-
</section>
|
|
422
|
-
</article>
|
|
423
|
-
</section>
|
|
424
|
-
</main>
|
|
425
|
-
</div>
|
|
426
|
-
|
|
427
|
-
<div id="toast" class="toast">✔ Copiado al portapapeles</div>
|
|
428
|
-
<footer class="footer">
|
|
429
|
-
Forged by <a href="https://ingcrea.com" target="_blank">INGENIERÍA CREATIVA Y DESARROLLOS TECNOLÓGICOS S.A.S.</a> |
|
|
430
|
-
<a href="https://github.com/ingcrea/aumic-tailwind-killer" target="_blank">View on GitHub</a>
|
|
431
|
-
</footer>
|
|
432
|
-
|
|
433
|
-
<script>
|
|
434
|
-
// --- MOTOR CANVAS: DONUT CHART ANIMADO ---
|
|
435
|
-
const chartData = ${JSON.stringify(chartData)};
|
|
436
|
-
const ctxChart = document.getElementById('donutCanvas').getContext('2d');
|
|
437
|
-
let totalVal = chartData.reduce((acc, d) => acc + d.value, 0);
|
|
438
|
-
if(totalVal === 0) totalVal = 1;
|
|
439
|
-
let animationProgress = 0;
|
|
440
|
-
let hoveredIndex = -1;
|
|
441
|
-
let mousePos = {x: 0, y: 0};
|
|
442
|
-
|
|
443
|
-
function drawDonut() {
|
|
444
|
-
ctxChart.clearRect(0, 0, 220, 220);
|
|
445
|
-
const cx = 110, cy = 110;
|
|
446
|
-
const baseRadius = 80;
|
|
447
|
-
const innerRadius = 55;
|
|
448
|
-
let currentAngle = -Math.PI / 2;
|
|
449
|
-
|
|
450
|
-
for (let i = 0; i < chartData.length; i++) {
|
|
451
|
-
const d = chartData[i];
|
|
452
|
-
if(d.value === 0) continue;
|
|
453
|
-
const sliceAngle = (d.value / totalVal) * (Math.PI * 2) * animationProgress;
|
|
454
|
-
const isHovered = (i === hoveredIndex);
|
|
455
|
-
const outerRadius = isHovered ? baseRadius + 10 : baseRadius;
|
|
456
|
-
|
|
457
|
-
ctxChart.beginPath();
|
|
458
|
-
ctxChart.arc(cx, cy, outerRadius, currentAngle, currentAngle + sliceAngle);
|
|
459
|
-
ctxChart.arc(cx, cy, innerRadius, currentAngle + sliceAngle, currentAngle, true);
|
|
460
|
-
ctxChart.closePath();
|
|
461
|
-
|
|
462
|
-
ctxChart.fillStyle = d.color;
|
|
463
|
-
// Hover glow effect
|
|
464
|
-
if (isHovered) {
|
|
465
|
-
ctxChart.shadowBlur = 15;
|
|
466
|
-
ctxChart.shadowColor = d.color;
|
|
467
|
-
} else {
|
|
468
|
-
ctxChart.shadowBlur = 0;
|
|
469
|
-
}
|
|
470
|
-
ctxChart.fill();
|
|
471
|
-
ctxChart.shadowBlur = 0; // reset
|
|
472
|
-
|
|
473
|
-
// Store angles for hit detection
|
|
474
|
-
d.startAngle = currentAngle;
|
|
475
|
-
d.endAngle = currentAngle + sliceAngle;
|
|
476
|
-
currentAngle += sliceAngle;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Draw tooltip
|
|
480
|
-
if (hoveredIndex > -1 && animationProgress > 0.9) {
|
|
481
|
-
const d = chartData[hoveredIndex];
|
|
482
|
-
const pct = ((d.value / totalVal) * 100).toFixed(1) + '%';
|
|
483
|
-
|
|
484
|
-
ctxChart.fillStyle = 'rgba(15, 23, 42, 0.9)';
|
|
485
|
-
ctxChart.strokeStyle = d.color;
|
|
486
|
-
ctxChart.lineWidth = 1;
|
|
487
|
-
ctxChart.beginPath();
|
|
488
|
-
ctxChart.roundRect(mousePos.x + 15, mousePos.y - 30, 90, 45, 6);
|
|
489
|
-
ctxChart.fill();
|
|
490
|
-
ctxChart.stroke();
|
|
491
|
-
|
|
492
|
-
ctxChart.fillStyle = '#fff';
|
|
493
|
-
ctxChart.font = 'bold 12px Inter';
|
|
494
|
-
ctxChart.fillText(pct, mousePos.x + 25, mousePos.y - 10);
|
|
495
|
-
ctxChart.fillStyle = '#cbd5e1';
|
|
496
|
-
ctxChart.font = '10px Inter';
|
|
497
|
-
ctxChart.fillText(d.value + ' items', mousePos.x + 25, mousePos.y + 5);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
function animateDonut() {
|
|
502
|
-
if (animationProgress < 1) {
|
|
503
|
-
animationProgress += 0.04;
|
|
504
|
-
drawDonut();
|
|
505
|
-
requestAnimationFrame(animateDonut);
|
|
506
|
-
} else {
|
|
507
|
-
drawDonut();
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
animateDonut();
|
|
511
|
-
|
|
512
|
-
document.getElementById('donutCanvas').addEventListener('mousemove', (e) => {
|
|
513
|
-
const rect = e.target.getBoundingClientRect();
|
|
514
|
-
const x = e.clientX - rect.left;
|
|
515
|
-
const y = e.clientY - rect.top;
|
|
516
|
-
mousePos = {x, y};
|
|
517
|
-
|
|
518
|
-
const cx = 110, cy = 110;
|
|
519
|
-
const dx = x - cx;
|
|
520
|
-
const dy = y - cy;
|
|
521
|
-
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
522
|
-
let angle = Math.atan2(dy, dx);
|
|
523
|
-
if (angle < -Math.PI / 2) angle += Math.PI * 2;
|
|
524
|
-
|
|
525
|
-
let found = -1;
|
|
526
|
-
if (dist >= 55 && dist <= 90) {
|
|
527
|
-
for (let i = 0; i < chartData.length; i++) {
|
|
528
|
-
if (chartData[i].value === 0) continue;
|
|
529
|
-
let start = chartData[i].startAngle;
|
|
530
|
-
let end = chartData[i].endAngle;
|
|
531
|
-
// Normalize angles relative to -PI/2
|
|
532
|
-
let nAngle = angle;
|
|
533
|
-
if (start > Math.PI && nAngle < 0) nAngle += Math.PI * 2;
|
|
534
|
-
if (nAngle >= start && nAngle <= end) {
|
|
535
|
-
found = i; break;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (found !== hoveredIndex) {
|
|
541
|
-
hoveredIndex = found;
|
|
542
|
-
document.getElementById('donutCanvas').style.cursor = found > -1 ? 'pointer' : 'default';
|
|
543
|
-
drawDonut();
|
|
544
|
-
} else if (found > -1) {
|
|
545
|
-
drawDonut(); // redraw tooltip position
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
document.getElementById('donutCanvas').addEventListener('mouseout', () => {
|
|
549
|
-
hoveredIndex = -1;
|
|
550
|
-
drawDonut();
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
// --- MOTOR CANVAS: FONDO DE NODOS AUM-IC ---
|
|
555
|
-
const canvas = document.getElementById('bgCanvas');
|
|
556
|
-
const ctx = canvas.getContext('2d');
|
|
557
|
-
let width, height;
|
|
558
|
-
let particles = [];
|
|
559
|
-
const mouse = { x: null, y: null };
|
|
560
|
-
|
|
561
|
-
function initBackground() {
|
|
562
|
-
width = canvas.width = window.innerWidth;
|
|
563
|
-
height = canvas.height = window.innerHeight;
|
|
564
|
-
particles = [];
|
|
565
|
-
const numParticles = Math.min(100, Math.floor((width * height) / 15000));
|
|
566
|
-
|
|
567
|
-
const colors = ['#22d3ee', '#a78bfa', '#34d399'];
|
|
568
|
-
for (let i = 0; i < numParticles; i++) {
|
|
569
|
-
particles.push({
|
|
570
|
-
x: Math.random() * width,
|
|
571
|
-
y: Math.random() * height,
|
|
572
|
-
vx: (Math.random() - 0.5) * 1.5,
|
|
573
|
-
vy: (Math.random() - 0.5) * 1.5,
|
|
574
|
-
radius: Math.random() * 2 + 1,
|
|
575
|
-
color: colors[Math.floor(Math.random() * colors.length)]
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
window.addEventListener('resize', initBackground);
|
|
580
|
-
window.addEventListener('mousemove', (e) => { mouse.x = e.clientX; mouse.y = e.clientY; });
|
|
581
|
-
window.addEventListener('mouseout', () => { mouse.x = null; mouse.y = null; });
|
|
582
|
-
|
|
583
|
-
function animateBackground() {
|
|
584
|
-
ctx.clearRect(0, 0, width, height);
|
|
585
|
-
|
|
586
|
-
// Update and draw particles
|
|
587
|
-
for (let i = 0; i < particles.length; i++) {
|
|
588
|
-
const p = particles[i];
|
|
589
|
-
p.x += p.vx;
|
|
590
|
-
p.y += p.vy;
|
|
591
|
-
if (p.x < 0 || p.x > width) p.vx *= -1;
|
|
592
|
-
if (p.y < 0 || p.y > height) p.vy *= -1;
|
|
593
|
-
|
|
594
|
-
ctx.beginPath();
|
|
595
|
-
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
|
|
596
|
-
ctx.fillStyle = p.color;
|
|
597
|
-
ctx.fill();
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// Connect particles
|
|
601
|
-
for (let i = 0; i < particles.length; i++) {
|
|
602
|
-
for (let j = i + 1; j < particles.length; j++) {
|
|
603
|
-
const p1 = particles[i], p2 = particles[j];
|
|
604
|
-
const dx = p1.x - p2.x, dy = p1.y - p2.y;
|
|
605
|
-
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
606
|
-
if (dist < 120) {
|
|
607
|
-
ctx.beginPath();
|
|
608
|
-
ctx.strokeStyle = \`rgba(0, 229, 255, \${0.15 - dist/120 * 0.15})\`;
|
|
609
|
-
ctx.lineWidth = 1.2;
|
|
610
|
-
ctx.moveTo(p1.x, p1.y);
|
|
611
|
-
ctx.lineTo(p2.x, p2.y);
|
|
612
|
-
ctx.stroke();
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Connect to mouse
|
|
617
|
-
if (mouse.x != null) {
|
|
618
|
-
const dx = particles[i].x - mouse.x, dy = particles[i].y - mouse.y;
|
|
619
|
-
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
620
|
-
if (dist < 150) {
|
|
621
|
-
ctx.beginPath();
|
|
622
|
-
ctx.strokeStyle = \`rgba(167, 139, 250, \${0.2 - dist/150 * 0.2})\`;
|
|
623
|
-
ctx.lineWidth = 2.0;
|
|
624
|
-
ctx.moveTo(particles[i].x, particles[i].y);
|
|
625
|
-
ctx.lineTo(mouse.x, mouse.y);
|
|
626
|
-
ctx.stroke();
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
requestAnimationFrame(animateBackground);
|
|
631
|
-
}
|
|
632
|
-
initBackground();
|
|
633
|
-
animateBackground();
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
// --- LOGICA DE TABLA (PAGINADOR & ORDEN) ---
|
|
637
|
-
let sortAsc = false;
|
|
638
|
-
let currentPage = 1;
|
|
639
|
-
let pageSize = 20;
|
|
640
|
-
let filteredRows = [];
|
|
641
|
-
let allRows = [];
|
|
642
|
-
|
|
643
|
-
window.onload = () => {
|
|
644
|
-
allRows = Array.from(document.querySelectorAll('#tbody tr'));
|
|
645
|
-
filteredRows = [...allRows];
|
|
646
|
-
sortAsc = true;
|
|
647
|
-
sortTable(2, 'num');
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
function changePageSize(val) {
|
|
651
|
-
if (val === 'all') {
|
|
652
|
-
pageSize = filteredRows.length > 0 ? filteredRows.length : 10000;
|
|
653
|
-
} else {
|
|
654
|
-
pageSize = parseInt(val);
|
|
655
|
-
}
|
|
656
|
-
currentPage = 1;
|
|
657
|
-
renderTable();
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
function renderTable() {
|
|
661
|
-
const tbody = document.getElementById('tbody');
|
|
662
|
-
tbody.innerHTML = '';
|
|
663
|
-
const start = (currentPage - 1) * pageSize;
|
|
664
|
-
const end = start + pageSize;
|
|
665
|
-
const pageRows = filteredRows.slice(start, end);
|
|
666
|
-
pageRows.forEach(r => tbody.appendChild(r));
|
|
667
|
-
|
|
668
|
-
const totalPages = Math.ceil(filteredRows.length / pageSize) || 1;
|
|
669
|
-
document.getElementById('page-info').textContent = \`Mostrando \${start+1} - \${Math.min(end, filteredRows.length)} de \${filteredRows.length} registros\`;
|
|
670
|
-
|
|
671
|
-
renderPaginationControls(totalPages);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
function renderPaginationControls(totalPages) {
|
|
675
|
-
const cont = document.getElementById('pag-controls');
|
|
676
|
-
cont.innerHTML = '';
|
|
677
|
-
if (totalPages <= 1) return;
|
|
678
|
-
|
|
679
|
-
// Prev Button
|
|
680
|
-
const btnPrev = document.createElement('button');
|
|
681
|
-
btnPrev.className = 'pag-btn';
|
|
682
|
-
btnPrev.textContent = '«';
|
|
683
|
-
btnPrev.disabled = currentPage === 1;
|
|
684
|
-
btnPrev.onclick = () => { currentPage--; renderTable(); };
|
|
685
|
-
cont.appendChild(btnPrev);
|
|
686
|
-
|
|
687
|
-
// Page Numbers
|
|
688
|
-
let startPage = Math.max(1, currentPage - 2);
|
|
689
|
-
let endPage = Math.min(totalPages, currentPage + 2);
|
|
690
|
-
|
|
691
|
-
if (startPage > 1) {
|
|
692
|
-
cont.appendChild(createPageBtn(1));
|
|
693
|
-
if (startPage > 2) { const d = document.createElement('span'); d.className='pag-dots'; d.textContent='...'; cont.appendChild(d); }
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
for (let i = startPage; i <= endPage; i++) {
|
|
697
|
-
cont.appendChild(createPageBtn(i));
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
if (endPage < totalPages) {
|
|
701
|
-
if (endPage < totalPages - 1) { const d = document.createElement('span'); d.className='pag-dots'; d.textContent='...'; cont.appendChild(d); }
|
|
702
|
-
cont.appendChild(createPageBtn(totalPages));
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// Next Button
|
|
706
|
-
const btnNext = document.createElement('button');
|
|
707
|
-
btnNext.className = 'pag-btn';
|
|
708
|
-
btnNext.textContent = '»';
|
|
709
|
-
btnNext.disabled = currentPage === totalPages;
|
|
710
|
-
btnNext.onclick = () => { currentPage++; renderTable(); };
|
|
711
|
-
cont.appendChild(btnNext);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
function createPageBtn(num) {
|
|
715
|
-
const btn = document.createElement('button');
|
|
716
|
-
btn.className = 'pag-btn' + (num === currentPage ? ' active' : '');
|
|
717
|
-
btn.textContent = num;
|
|
718
|
-
btn.onclick = () => { currentPage = num; renderTable(); };
|
|
719
|
-
return btn;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
function sortTable(colIdx, type) {
|
|
723
|
-
sortAsc = !sortAsc;
|
|
724
|
-
filteredRows.sort((a, b) => {
|
|
725
|
-
let valA, valB;
|
|
726
|
-
if (type === 'num') {
|
|
727
|
-
valA = parseInt(a.children[colIdx].getAttribute('data-occ') || '0');
|
|
728
|
-
valB = parseInt(b.children[colIdx].getAttribute('data-occ') || '0');
|
|
729
|
-
} else {
|
|
730
|
-
valA = a.children[colIdx].textContent.trim();
|
|
731
|
-
valB = b.children[colIdx].textContent.trim();
|
|
732
|
-
}
|
|
733
|
-
if (valA < valB) return sortAsc ? -1 : 1;
|
|
734
|
-
if (valA > valB) return sortAsc ? 1 : -1;
|
|
735
|
-
return 0;
|
|
736
|
-
});
|
|
737
|
-
currentPage = 1;
|
|
738
|
-
renderTable();
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
let activeCat = 'all';
|
|
742
|
-
let searchQuery = '';
|
|
743
|
-
|
|
744
|
-
function filter(cat, btn) {
|
|
745
|
-
document.querySelectorAll('.fbtn').forEach(b=>b.classList.remove('active'));
|
|
746
|
-
if(btn) btn.classList.add('active');
|
|
747
|
-
activeCat = cat;
|
|
748
|
-
applyFilters();
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
function search(q) {
|
|
752
|
-
searchQuery = q;
|
|
753
|
-
applyFilters();
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
function applyFilters() {
|
|
757
|
-
let regex = null;
|
|
758
|
-
let lq = searchQuery.toLowerCase();
|
|
759
|
-
try { if (searchQuery) regex = new RegExp(searchQuery, 'i'); } catch(e) {}
|
|
760
|
-
|
|
761
|
-
filteredRows = allRows.filter(r => {
|
|
762
|
-
const catMatch = (activeCat === 'all' || r.getAttribute('data-cat') === activeCat);
|
|
763
|
-
if (!catMatch) return false;
|
|
764
|
-
|
|
765
|
-
const txt = r.textContent;
|
|
766
|
-
if (!searchQuery) return true;
|
|
767
|
-
if (regex && regex.test(txt)) return true;
|
|
768
|
-
return txt.toLowerCase().includes(lq);
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
currentPage = 1;
|
|
772
|
-
renderTable();
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
function copyText(el) {
|
|
776
|
-
const text = el.innerText;
|
|
777
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
778
|
-
const toast = document.getElementById('toast');
|
|
779
|
-
toast.classList.add('show');
|
|
780
|
-
setTimeout(() => toast.classList.remove('show'), 2000);
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
function exportCSV() {
|
|
785
|
-
let csv = "Tailwind Original,AUM-IC Transmutada,Frecuencia,Nivel\\n";
|
|
786
|
-
filteredRows.forEach(r => {
|
|
787
|
-
const cols = r.querySelectorAll('td');
|
|
788
|
-
const orig = cols[0].innerText;
|
|
789
|
-
const aumic = cols[1].innerText;
|
|
790
|
-
const occ = cols[2].querySelector('span').innerText;
|
|
791
|
-
const lvl = cols[3].innerText;
|
|
792
|
-
csv += String.fromCharCode(34) + orig + String.fromCharCode(34) + "," + String.fromCharCode(34) + aumic + String.fromCharCode(34) + "," + occ + "," + String.fromCharCode(34) + lvl + String.fromCharCode(34) + "\\n";
|
|
793
|
-
});
|
|
794
|
-
const blob = new Blob([csv], { type: 'text/csv' });
|
|
795
|
-
const url = window.URL.createObjectURL(blob);
|
|
796
|
-
const a = document.createElement('a');
|
|
797
|
-
a.href = url;
|
|
798
|
-
a.download = 'aumic-report.csv';
|
|
799
|
-
a.click();
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function exportMD() {
|
|
803
|
-
let md = "| Tailwind Original | AUM-IC Transmutada | Frecuencia | Nivel |\\n|---|---|---|---|\\n";
|
|
804
|
-
filteredRows.forEach(r => {
|
|
805
|
-
const cols = r.querySelectorAll('td');
|
|
806
|
-
const orig = cols[0].innerText.replace(/\|/g, '|');
|
|
807
|
-
const aumic = cols[1].innerText.replace(/\|/g, '|');
|
|
808
|
-
const occ = cols[2].querySelector('span').innerText;
|
|
809
|
-
const lvl = cols[3].innerText;
|
|
810
|
-
md += "| " + orig + " | " + aumic + " | " + occ + " | " + lvl + " |\\n";
|
|
811
|
-
});
|
|
812
|
-
const blob = new Blob([md], { type: 'text/markdown' });
|
|
813
|
-
const url = window.URL.createObjectURL(blob);
|
|
814
|
-
const a = document.createElement('a');
|
|
815
|
-
a.href = url;
|
|
816
|
-
a.download = 'aumic-report.md';
|
|
817
|
-
a.click();
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
document.addEventListener('keydown', (e) => {
|
|
821
|
-
if (e.key === '/' && document.activeElement.id !== 'searchInput') {
|
|
822
|
-
e.preventDefault();
|
|
823
|
-
document.getElementById('searchInput').focus();
|
|
824
|
-
}
|
|
825
|
-
});
|
|
826
|
-
|
|
168
|
+
const html = `<!DOCTYPE html>
|
|
169
|
+
<html lang="es"><head><meta charset="UTF-8"><title>AUM-IC · Dashboard C4I</title><style>
|
|
170
|
+
:root { --bg: #030712; --panel: rgba(15, 23, 42, 0.7); --panel-hover: #1e293b; --text: #e2e8f0; --muted: #64748b; --border: rgba(51, 65, 85, 0.6); --accent: #00e5ff; }
|
|
171
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
172
|
+
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;padding:2rem 3rem;position:relative;overflow-x:hidden;}
|
|
173
|
+
#bgCanvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
|
|
174
|
+
.content-wrapper { position: relative; z-index: 10; }
|
|
175
|
+
header{display:flex;align-items:center;justify-content:space-between;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border)}
|
|
176
|
+
header h1{font-size:1.8rem;font-weight:900;color:#fff;letter-spacing:-0.5px}header h1 span{color:var(--accent);text-shadow:0 0 10px rgba(0,229,255,0.4)}
|
|
177
|
+
.subtitle{font-size:0.85rem;color:var(--muted);margin-top:6px}.safe-tag{background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.3);color:var(--accent);font-size:0.75rem;padding:6px 16px;border-radius:999px;font-weight:700;box-shadow:0 0 15px rgba(0,229,255,0.1)}
|
|
178
|
+
.dashboard-grid { display: grid; grid-template-columns: 320px 1fr; gap: 2rem; }
|
|
179
|
+
.sidebar { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
180
|
+
.main-view { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
181
|
+
|
|
182
|
+
/* Panels */
|
|
183
|
+
.panel { background: var(--panel); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); padding: 1.5rem; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
|
|
184
|
+
.panel h2 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 1rem; }
|
|
185
|
+
|
|
186
|
+
/* Canvas Chart */
|
|
187
|
+
.chart-container { display: flex; justify-content: center; align-items: center; margin-bottom: 1rem; position: relative; height: 200px; }
|
|
188
|
+
.chart-center-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; pointer-events: none; }
|
|
189
|
+
.chart-center-overlay .score { font-size: 2.5rem; font-weight: 900; color: ${gradeColor}; line-height: 1; text-shadow: 0 0 15px ${gradeColor}44; }
|
|
190
|
+
.chart-center-overlay .score-lbl { font-size: 0.6rem; color: var(--muted); text-transform: uppercase; letter-spacing: 1px; margin-top: 4px; }
|
|
191
|
+
.legend { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 0.75rem; }
|
|
192
|
+
.leg-item { display: flex; align-items: center; gap: 6px; }
|
|
193
|
+
.leg-color { width: 10px; height: 10px; border-radius: 50%; }
|
|
194
|
+
|
|
195
|
+
/* Hero Metrics */
|
|
196
|
+
.metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
|
|
197
|
+
.metric { background: rgba(0,0,0,0.3); padding: 1.2rem; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05); backdrop-filter: blur(5px); }
|
|
198
|
+
.metric h3 { font-size: 1.8rem; font-weight: 900; color: #fff; line-height: 1; margin-bottom: 4px; }
|
|
199
|
+
.metric p { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
|
|
200
|
+
.highlight { color: #34d399 !important; text-shadow: 0 0 10px rgba(52,211,153,0.4); }
|
|
201
|
+
.highlight-psi { color: #facc15 !important; }
|
|
202
|
+
|
|
203
|
+
/* Criminals */
|
|
204
|
+
.criminal { display: flex; gap: 1rem; align-items: center; padding: 10px; background: rgba(0,0,0,0.2); border-radius: 8px; margin-bottom: 8px; }
|
|
205
|
+
.c-rank { font-size: 1.2rem; font-weight: 900; color: #ef4444; width: 30px; text-align: center; }
|
|
206
|
+
.c-info { flex: 1; min-width: 0; }
|
|
207
|
+
.c-class { font-family: 'Fira Code', monospace; font-size: 0.75rem; color: #f472b6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 4px; }
|
|
208
|
+
.c-stats { font-size: 0.65rem; color: var(--muted); }
|
|
209
|
+
|
|
210
|
+
/* Table Controls */
|
|
211
|
+
.toolbar{display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap; margin-bottom: 1.5rem;}
|
|
212
|
+
.fbtn{background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#94a3b8;font-size:0.75rem;padding:8px 16px;border-radius:8px;cursor:pointer;transition:all 0.2s;font-weight:500}
|
|
213
|
+
.fbtn:hover,.fbtn.active{color:#fff;border-color:var(--accent);background:rgba(0,229,255,0.1);box-shadow:0 0 10px rgba(0,229,255,0.2)}
|
|
214
|
+
.search{margin-left:auto;background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#fff;font-size:0.8rem;padding:8px 16px;border-radius:8px;outline:none;width:220px;transition:all 0.2s}
|
|
215
|
+
.search:focus{border-color:var(--accent);box-shadow:0 0 0 2px rgba(0,229,255,0.2)}
|
|
216
|
+
.page-size-sel { background: rgba(15, 23, 42, 0.9); color: #fff; background:rgba(0,0,0,0.2);border:1px solid var(--border);color:#fff;font-size:0.75rem;padding:8px;border-radius:8px;outline:none; cursor:pointer;}
|
|
217
|
+
|
|
218
|
+
/* Table */
|
|
219
|
+
.table-container{border-radius:12px;border:1px solid var(--border);overflow:hidden;background:rgba(0,0,0,0.2);}
|
|
220
|
+
table{width:100%;border-collapse:collapse;font-size:0.8rem}
|
|
221
|
+
th{background:rgba(0,0,0,0.3);color:var(--muted);text-align:left;padding:12px 16px;border-bottom:1px solid var(--border);font-weight:600;text-transform:uppercase;letter-spacing:1px;font-size:0.7rem;cursor:pointer;user-select:none}
|
|
222
|
+
th:hover{color:#fff}
|
|
223
|
+
td{padding:12px 16px;border-bottom:1px solid rgba(255,255,255,0.02);vertical-align:middle;transition:background 0.15s}
|
|
224
|
+
tr:hover td{background:rgba(255,255,255,0.05)}
|
|
225
|
+
.tw-cell{font-family:'Fira Code',Consolas,monospace;color:#f472b6;font-size:0.75rem;max-width:300px;word-break:break-all}
|
|
226
|
+
.aumic-cell{font-family:'Fira Code',Consolas,monospace;color:#38bdf8;font-size:0.75rem;white-space:nowrap;font-weight:600}
|
|
227
|
+
.occ-cell{display:flex;align-items:center;gap:10px;font-family:'Fira Code',monospace;font-weight:bold;color:#fff}
|
|
228
|
+
.occ-bar{height:6px;border-radius:3px;opacity:0.8}
|
|
229
|
+
.badge{font-size:0.65rem;padding:4px 10px;border-radius:999px;border:1px solid;font-weight:800;white-space:nowrap;text-transform:uppercase;letter-spacing:0.5px}
|
|
230
|
+
|
|
231
|
+
/* Pagination */
|
|
232
|
+
.pagination { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; background: rgba(0,0,0,0.3); border-top: 1px solid var(--border); }
|
|
233
|
+
.pag-controls { display: flex; gap: 6px; align-items: center; background: rgba(15,23,42,0.6); padding: 4px; border-radius: 8px; border: 1px solid var(--border); }
|
|
234
|
+
.pag-btn { background: transparent; border: none; color: var(--muted); padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 0.75rem; transition: 0.2s; min-width: 32px; text-align: center; font-weight: 600; }
|
|
235
|
+
.pag-btn:hover:not(:disabled) { background: rgba(255,255,255,0.05); color: #fff; }
|
|
236
|
+
.pag-btn.active { background: rgba(0,229,255,0.15); color: var(--accent); box-shadow: inset 0 0 0 1px rgba(0,229,255,0.3); }
|
|
237
|
+
.pag-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
|
238
|
+
.pag-info { font-size: 0.75rem; color: var(--muted); }
|
|
239
|
+
.pag-dots { color: var(--muted); font-size: 0.75rem; font-weight: bold; padding: 0 4px; }
|
|
240
|
+
|
|
241
|
+
/* Footer */
|
|
242
|
+
.footer { position: relative; bottom: 0; left: 0; width: 100%; text-align: center; padding: 20px; font-size: 0.75rem; color: var(--muted); border-top: 1px solid rgba(255,255,255,0.05); background: rgba(0,0,0,0.3); backdrop-filter: blur(5px); margin-top: auto; }
|
|
243
|
+
.footer a { color: var(--accent); text-decoration: none; font-weight: 600; transition: color 0.2s; }
|
|
244
|
+
.footer a:hover { color: #fff; text-shadow: 0 0 10px var(--accent); }
|
|
245
|
+
.page-size-sel option { background: #0f172a; color: #fff; }
|
|
246
|
+
/* Export & Toast */
|
|
247
|
+
.export-group-top { display: flex; gap: 8px; margin-left: auto; align-items: center; } .export-group-top .fbtn { background: rgba(0,229,255,0.05); }
|
|
248
|
+
.toast { position: fixed; bottom: 20px; right: 20px; background: rgba(0, 229, 255, 0.15); border: 1px solid var(--accent); color: #fff; padding: 10px 20px; border-radius: 8px; font-size: 0.8rem; font-weight: 600; box-shadow: 0 5px 15px rgba(0,229,255,0.2); backdrop-filter: blur(5px); transform: translateY(100px); opacity: 0; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 9999; }
|
|
249
|
+
.toast.show { transform: translateY(0); opacity: 1; }
|
|
250
|
+
.copyable { cursor: pointer; transition: color 0.2s; position: relative; }
|
|
251
|
+
.copyable:hover { color: #fff; text-shadow: 0 0 8px rgba(255,255,255,0.5); }
|
|
252
|
+
.copyable::after { content: 'Copiar'; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: #fff; font-size: 0.6rem; padding: 2px 6px; border-radius: 4px; opacity: 0; pointer-events: none; transition: opacity 0.2s; }
|
|
253
|
+
.copyable:hover::after { opacity: 1; }
|
|
254
|
+
|
|
255
|
+
/* Sticky Header */
|
|
256
|
+
.table-container { overflow-x: auto; }
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
/* Print PDF (Mesa Directiva) */
|
|
260
|
+
@media print {
|
|
261
|
+
body { background: #fff !important; color: #000 !important; padding: 0 !important; font-size: 10pt; }
|
|
262
|
+
#bgCanvas, .toolbar, .pagination, .safe-tag, .export-group-top, .footer, .toast { display: none !important; }
|
|
263
|
+
.content-wrapper { padding: 0 !important; max-width: 100% !important; }
|
|
264
|
+
header { border-bottom: 2px solid #000; padding-bottom: 10px; margin-bottom: 20px; flex-direction: column !important; align-items: flex-start !important; }
|
|
265
|
+
header h1 { color: #000 !important; text-shadow: none !important; margin: 0; }
|
|
266
|
+
header h1 span { color: #000 !important; }
|
|
267
|
+
|
|
268
|
+
.dashboard-grid { display: block !important; }
|
|
269
|
+
.sidebar { display: flex !important; flex-direction: row !important; gap: 20px !important; margin-bottom: 20px !important; page-break-inside: avoid; }
|
|
270
|
+
.sidebar .panel { flex: 1; border: 1px solid #cbd5e1 !important; padding: 15px !important; border-radius: 8px !important; }
|
|
271
|
+
|
|
272
|
+
.panel { background: none !important; border: none !important; box-shadow: none !important; padding: 0 !important; }
|
|
273
|
+
|
|
274
|
+
.metrics-grid { display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 10px !important; margin-bottom: 20px !important; page-break-inside: avoid; }
|
|
275
|
+
.metric { background: #f8fafc !important; border: 1px solid #cbd5e1 !important; padding: 10px !important; border-radius: 8px !important; }
|
|
276
|
+
.metric h3 { color: #000 !important; text-shadow: none !important; font-size: 1.2rem; margin-bottom: 5px; }
|
|
277
|
+
.metric p { color: #333 !important; font-size: 0.8rem; }
|
|
278
|
+
|
|
279
|
+
.criteria-box { background: #f8fafc !important; border: 1px solid #cbd5e1 !important; color: #000 !important; }
|
|
280
|
+
.criteria-box strong { color: #000 !important; }
|
|
281
|
+
.criteria-box span { color: #000 !important; font-weight: bold; }
|
|
282
|
+
|
|
283
|
+
.chart-center-overlay .score { color: #000 !important; text-shadow: none !important; }
|
|
284
|
+
.chart-center-overlay .score-lbl { color: #333 !important; }
|
|
285
|
+
|
|
286
|
+
.leg-item { color: #000 !important; }
|
|
287
|
+
|
|
288
|
+
.table-container { max-height: none !important; border: none !important; overflow: visible !important; }
|
|
289
|
+
table { border-collapse: collapse !important; width: 100% !important; page-break-inside: auto; }
|
|
290
|
+
tr { page-break-inside: avoid; page-break-after: auto; }
|
|
291
|
+
th, td { border: 1px solid #cbd5e1 !important; color: #000 !important; padding: 6px !important; font-size: 9pt !important; }
|
|
292
|
+
th { background: #f1f5f9 !important; color: #000 !important; font-weight: bold; }
|
|
293
|
+
.tw-cell, .aumic-cell { color: #000 !important; font-weight: normal; }
|
|
294
|
+
.occ-bar { background: #94a3b8 !important; }
|
|
295
|
+
|
|
296
|
+
@page { margin: 1cm; size: auto; }
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
</style></head><body style="display: flex; flex-direction: column;">
|
|
300
|
+
|
|
301
|
+
<canvas id="bgCanvas"></canvas>
|
|
302
|
+
|
|
303
|
+
<div class="content-wrapper">
|
|
304
|
+
<header>
|
|
305
|
+
<div><h1>⚔️ <span>AUM-IC</span> · Centro de Inteligencia</h1>
|
|
306
|
+
<p class="subtitle">Análisis Forense completado exitosamente sin mutación en disco.</p></div>
|
|
307
|
+
<div class="export-group-top" style="display:flex; gap:8px; margin-left: 20px;">
|
|
308
|
+
<button class="fbtn" onclick="exportCSV()">⬇️ CSV</button><button class="fbtn" onclick="exportMD()">⬇️ MD</button><button class="fbtn" onclick="window.print()">🖨️ PDF</button>
|
|
309
|
+
</div>
|
|
310
|
+
<div class="safe-tag" style="align-items: flex-end; display: flex; flex-direction: column;">
|
|
311
|
+
<span>${isSimulate ? 'MODO DRY-RUN ACTIVO' : 'MUTACIÓN AUM-IC COMPLETADA'}</span>
|
|
312
|
+
<span style="font-size: 0.65rem; opacity: 0.8; margin-top: 2px;">v${pkgVersion}</span>
|
|
313
|
+
</div>
|
|
314
|
+
</header>
|
|
315
|
+
|
|
316
|
+
<main class="dashboard-grid">
|
|
317
|
+
<aside class="sidebar">
|
|
318
|
+
<article class="panel">
|
|
319
|
+
<h2>Mapeo Estructural</h2>
|
|
320
|
+
<div class="chart-container">
|
|
321
|
+
<canvas id="donutCanvas" width="220" height="220"></canvas>
|
|
322
|
+
<div class="chart-center-overlay">
|
|
323
|
+
<div class="score">${grade}</div>
|
|
324
|
+
<div class="score-lbl">Rank</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
<div class="legend">
|
|
328
|
+
<div class="leg-item"><div class="leg-color" style="background:#22d3ee"></div>Átomos (${counts.atoms})</div>
|
|
329
|
+
<div class="leg-item"><div class="leg-color" style="background:#a78bfa"></div>Moléculas (${counts.molecules})</div>
|
|
330
|
+
<div class="leg-item"><div class="leg-color" style="background:#34d399"></div>Organismos (${counts.organisms})</div>
|
|
331
|
+
<div class="leg-item"><div class="leg-color" style="background:#fb923c"></div>Ecosistemas (${counts.ecosystems})</div>
|
|
332
|
+
<div class="leg-item"><div class="leg-color" style="background:#facc15"></div>Galaxias (${counts.galaxies})</div>
|
|
333
|
+
</div>
|
|
334
|
+
<div class="criteria-box" style="margin-top: 1.5rem; padding: 1rem; background: rgba(0,0,0,0.2); border-radius: 8px; border: 1px solid var(--border); font-size: 0.75rem; color: var(--muted); line-height: 1.5;">
|
|
335
|
+
<strong style="color: #fff; margin-bottom: 0.5rem; display: block;">Criterio de Evaluación AUM-IC</strong>
|
|
336
|
+
<ul style="margin: 0; padding-left: 1rem; list-style: square;">
|
|
337
|
+
<li><span style="color:#22d3ee">Átomos:</span> Utilidades base simples (p-4, m-2, flex).</li>
|
|
338
|
+
<li><span style="color:#a78bfa">Moléculas:</span> Estilos condicionales y variantes (hover:, focus:).</li>
|
|
339
|
+
<li><span style="color:#34d399">Organismos:</span> Cadenas largas y componentes estructurales.</li>
|
|
340
|
+
<li><span style="color:#fb923c">Ecosistemas:</span> Combinaciones de Layouts complejos (Grid/Flex).</li>
|
|
341
|
+
<li><span style="color:#facc15">Galaxias:</span> Declaraciones globales masivas o de alta densidad.</li>
|
|
342
|
+
</ul>
|
|
343
|
+
<div style="margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid rgba(255,255,255,0.1);">
|
|
344
|
+
<strong style="color: #fff; display:block; margin-bottom: 0.3rem;">🏆 Rank (Score) & Eficiencia</strong>
|
|
345
|
+
<div style="margin-bottom: 0.6rem; color: #94a3b8;">La <b>Eficiencia de Refactorización</b> mide el porcentaje exacto de peso (bytes) que AUM-IC logró purgar del DOM frente al HTML inflado original.</div>
|
|
346
|
+
<div style="display: flex; gap: 6px; flex-wrap: wrap; font-size: 0.7rem;">
|
|
347
|
+
<span style="background: rgba(250,204,21,0.15); color:#facc15; padding: 3px 6px; border-radius: 4px; border: 1px solid #facc1544;"><b>S</b> ≥ 70%</span>
|
|
348
|
+
<span style="background: rgba(52,211,153,0.15); color:#34d399; padding: 3px 6px; border-radius: 4px; border: 1px solid #34d39944;"><b>A</b> ≥ 50%</span>
|
|
349
|
+
<span style="background: rgba(34,211,238,0.15); color:#22d3ee; padding: 3px 6px; border-radius: 4px; border: 1px solid #22d3ee44;"><b>B</b> ≥ 30%</span>
|
|
350
|
+
<span style="background: rgba(167,139,250,0.15); color:#a78bfa; padding: 3px 6px; border-radius: 4px; border: 1px solid #a78bfa44;"><b>C</b> ≥ 15%</span>
|
|
351
|
+
<span style="background: rgba(239,68,68,0.15); color:#ef4444; padding: 3px 6px; border-radius: 4px; border: 1px solid #ef444444;"><b>D</b> < 15%</span>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
</article>
|
|
356
|
+
|
|
357
|
+
<article class="panel">
|
|
358
|
+
<h2>☠️ Top 5 Ofensores del DOM</h2>
|
|
359
|
+
${top5}
|
|
360
|
+
</article>
|
|
361
|
+
</aside>
|
|
362
|
+
|
|
363
|
+
<section class="main-view">
|
|
364
|
+
<div class="metrics-grid">
|
|
365
|
+
<div class="metric">
|
|
366
|
+
<h3 class="highlight">🔥 ${savedKB} KB</h3>
|
|
367
|
+
<p>Peso/Tamaño Estimado Salvado</p>
|
|
368
|
+
</div>
|
|
369
|
+
<div class="metric">
|
|
370
|
+
<h3 class="highlight-psi">🚀 +${psiImpact} pts</h3>
|
|
371
|
+
<p>Impacto Estimado Google PSI</p>
|
|
372
|
+
</div>
|
|
373
|
+
<div class="metric">
|
|
374
|
+
<h3>${efficiency}%</h3>
|
|
375
|
+
<p>Eficiencia de Refactorización</p>
|
|
376
|
+
</div>
|
|
377
|
+
<div class="metric">
|
|
378
|
+
<h3>${mapping.size}</h3>
|
|
379
|
+
<p>Clases Únicas Tailwind</p>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="metric">
|
|
382
|
+
<h3>${totalOccurrences}</h3>
|
|
383
|
+
<p>Instancias Totales Detectadas</p>
|
|
384
|
+
</div>
|
|
385
|
+
<div class="metric">
|
|
386
|
+
<h3>${totalOccurrences - mapping.size}</h3>
|
|
387
|
+
<p>Redundancia Estructural (Repetidas)</p>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
<article class="panel">
|
|
392
|
+
<nav class="toolbar">
|
|
393
|
+
<button class="fbtn active" onclick="filter('all',this)">Todos</button>
|
|
394
|
+
<button class="fbtn" onclick="filter('atoms',this)">Átomos</button>
|
|
395
|
+
<button class="fbtn" onclick="filter('molecules',this)">Moléculas</button>
|
|
396
|
+
<button class="fbtn" onclick="filter('organisms',this)">Organismos</button>
|
|
397
|
+
<button class="fbtn" onclick="filter('ecosystems',this)">Ecosistemas</button>
|
|
398
|
+
<button class="fbtn" onclick="filter('galaxies',this)">Galaxias</button>
|
|
399
|
+
|
|
400
|
+
<input class="search" type="text" id="searchInput" placeholder="Buscar clase (Regex)..." oninput="search(this.value)">
|
|
401
|
+
<select class="page-size-sel" id="pageSizeSelect" onchange="changePageSize(this.value)">
|
|
402
|
+
<option value="20">20 por pág</option>
|
|
403
|
+
<option value="50">50 por pág</option>
|
|
404
|
+
<option value="100">100 por pág</option>
|
|
405
|
+
<option value="all">TODOS</option>
|
|
406
|
+
</select>
|
|
407
|
+
</nav>
|
|
408
|
+
<section class="table-container">
|
|
409
|
+
<table id="table">
|
|
410
|
+
<thead><tr>
|
|
411
|
+
<th onclick="sortTable(0, 'str')">Clase Original (Tailwind) ↕</th>
|
|
412
|
+
<th onclick="sortTable(1, 'str')">Clase AUM-IC Transmutada ↕</th>
|
|
413
|
+
<th onclick="sortTable(2, 'num')">Frecuencia ↕</th>
|
|
414
|
+
<th onclick="sortTable(3, 'str')">Nivel ↕</th>
|
|
415
|
+
</tr></thead>
|
|
416
|
+
<tbody id="tbody">${rows.join('')}</tbody>
|
|
417
|
+
</table>
|
|
418
|
+
<div class="pagination">
|
|
419
|
+
<span class="pag-info" id="page-info"></span>
|
|
420
|
+
<div class="pag-controls" id="pag-controls"></div>
|
|
421
|
+
</div>
|
|
422
|
+
</section>
|
|
423
|
+
</article>
|
|
424
|
+
</section>
|
|
425
|
+
</main>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<div id="toast" class="toast">✔ Copiado al portapapeles</div>
|
|
429
|
+
<footer class="footer">
|
|
430
|
+
Forged by <a href="https://ingcrea.com" target="_blank">INGENIERÍA CREATIVA Y DESARROLLOS TECNOLÓGICOS S.A.S.</a> |
|
|
431
|
+
<a href="https://github.com/ingcrea/aumic-tailwind-killer" target="_blank">View on GitHub</a>
|
|
432
|
+
</footer>
|
|
433
|
+
|
|
434
|
+
<script>
|
|
435
|
+
// --- MOTOR CANVAS: DONUT CHART ANIMADO ---
|
|
436
|
+
const chartData = ${JSON.stringify(chartData)};
|
|
437
|
+
const ctxChart = document.getElementById('donutCanvas').getContext('2d');
|
|
438
|
+
let totalVal = chartData.reduce((acc, d) => acc + d.value, 0);
|
|
439
|
+
if(totalVal === 0) totalVal = 1;
|
|
440
|
+
let animationProgress = 0;
|
|
441
|
+
let hoveredIndex = -1;
|
|
442
|
+
let mousePos = {x: 0, y: 0};
|
|
443
|
+
|
|
444
|
+
function drawDonut() {
|
|
445
|
+
ctxChart.clearRect(0, 0, 220, 220);
|
|
446
|
+
const cx = 110, cy = 110;
|
|
447
|
+
const baseRadius = 80;
|
|
448
|
+
const innerRadius = 55;
|
|
449
|
+
let currentAngle = -Math.PI / 2;
|
|
450
|
+
|
|
451
|
+
for (let i = 0; i < chartData.length; i++) {
|
|
452
|
+
const d = chartData[i];
|
|
453
|
+
if(d.value === 0) continue;
|
|
454
|
+
const sliceAngle = (d.value / totalVal) * (Math.PI * 2) * animationProgress;
|
|
455
|
+
const isHovered = (i === hoveredIndex);
|
|
456
|
+
const outerRadius = isHovered ? baseRadius + 10 : baseRadius;
|
|
457
|
+
|
|
458
|
+
ctxChart.beginPath();
|
|
459
|
+
ctxChart.arc(cx, cy, outerRadius, currentAngle, currentAngle + sliceAngle);
|
|
460
|
+
ctxChart.arc(cx, cy, innerRadius, currentAngle + sliceAngle, currentAngle, true);
|
|
461
|
+
ctxChart.closePath();
|
|
462
|
+
|
|
463
|
+
ctxChart.fillStyle = d.color;
|
|
464
|
+
// Hover glow effect
|
|
465
|
+
if (isHovered) {
|
|
466
|
+
ctxChart.shadowBlur = 15;
|
|
467
|
+
ctxChart.shadowColor = d.color;
|
|
468
|
+
} else {
|
|
469
|
+
ctxChart.shadowBlur = 0;
|
|
470
|
+
}
|
|
471
|
+
ctxChart.fill();
|
|
472
|
+
ctxChart.shadowBlur = 0; // reset
|
|
473
|
+
|
|
474
|
+
// Store angles for hit detection
|
|
475
|
+
d.startAngle = currentAngle;
|
|
476
|
+
d.endAngle = currentAngle + sliceAngle;
|
|
477
|
+
currentAngle += sliceAngle;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Draw tooltip
|
|
481
|
+
if (hoveredIndex > -1 && animationProgress > 0.9) {
|
|
482
|
+
const d = chartData[hoveredIndex];
|
|
483
|
+
const pct = ((d.value / totalVal) * 100).toFixed(1) + '%';
|
|
484
|
+
|
|
485
|
+
ctxChart.fillStyle = 'rgba(15, 23, 42, 0.9)';
|
|
486
|
+
ctxChart.strokeStyle = d.color;
|
|
487
|
+
ctxChart.lineWidth = 1;
|
|
488
|
+
ctxChart.beginPath();
|
|
489
|
+
ctxChart.roundRect(mousePos.x + 15, mousePos.y - 30, 90, 45, 6);
|
|
490
|
+
ctxChart.fill();
|
|
491
|
+
ctxChart.stroke();
|
|
492
|
+
|
|
493
|
+
ctxChart.fillStyle = '#fff';
|
|
494
|
+
ctxChart.font = 'bold 12px Inter';
|
|
495
|
+
ctxChart.fillText(pct, mousePos.x + 25, mousePos.y - 10);
|
|
496
|
+
ctxChart.fillStyle = '#cbd5e1';
|
|
497
|
+
ctxChart.font = '10px Inter';
|
|
498
|
+
ctxChart.fillText(d.value + ' items', mousePos.x + 25, mousePos.y + 5);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function animateDonut() {
|
|
503
|
+
if (animationProgress < 1) {
|
|
504
|
+
animationProgress += 0.04;
|
|
505
|
+
drawDonut();
|
|
506
|
+
requestAnimationFrame(animateDonut);
|
|
507
|
+
} else {
|
|
508
|
+
drawDonut();
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
animateDonut();
|
|
512
|
+
|
|
513
|
+
document.getElementById('donutCanvas').addEventListener('mousemove', (e) => {
|
|
514
|
+
const rect = e.target.getBoundingClientRect();
|
|
515
|
+
const x = e.clientX - rect.left;
|
|
516
|
+
const y = e.clientY - rect.top;
|
|
517
|
+
mousePos = {x, y};
|
|
518
|
+
|
|
519
|
+
const cx = 110, cy = 110;
|
|
520
|
+
const dx = x - cx;
|
|
521
|
+
const dy = y - cy;
|
|
522
|
+
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
523
|
+
let angle = Math.atan2(dy, dx);
|
|
524
|
+
if (angle < -Math.PI / 2) angle += Math.PI * 2;
|
|
525
|
+
|
|
526
|
+
let found = -1;
|
|
527
|
+
if (dist >= 55 && dist <= 90) {
|
|
528
|
+
for (let i = 0; i < chartData.length; i++) {
|
|
529
|
+
if (chartData[i].value === 0) continue;
|
|
530
|
+
let start = chartData[i].startAngle;
|
|
531
|
+
let end = chartData[i].endAngle;
|
|
532
|
+
// Normalize angles relative to -PI/2
|
|
533
|
+
let nAngle = angle;
|
|
534
|
+
if (start > Math.PI && nAngle < 0) nAngle += Math.PI * 2;
|
|
535
|
+
if (nAngle >= start && nAngle <= end) {
|
|
536
|
+
found = i; break;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (found !== hoveredIndex) {
|
|
542
|
+
hoveredIndex = found;
|
|
543
|
+
document.getElementById('donutCanvas').style.cursor = found > -1 ? 'pointer' : 'default';
|
|
544
|
+
drawDonut();
|
|
545
|
+
} else if (found > -1) {
|
|
546
|
+
drawDonut(); // redraw tooltip position
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
document.getElementById('donutCanvas').addEventListener('mouseout', () => {
|
|
550
|
+
hoveredIndex = -1;
|
|
551
|
+
drawDonut();
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
// --- MOTOR CANVAS: FONDO DE NODOS AUM-IC ---
|
|
556
|
+
const canvas = document.getElementById('bgCanvas');
|
|
557
|
+
const ctx = canvas.getContext('2d');
|
|
558
|
+
let width, height;
|
|
559
|
+
let particles = [];
|
|
560
|
+
const mouse = { x: null, y: null };
|
|
561
|
+
|
|
562
|
+
function initBackground() {
|
|
563
|
+
width = canvas.width = window.innerWidth;
|
|
564
|
+
height = canvas.height = window.innerHeight;
|
|
565
|
+
particles = [];
|
|
566
|
+
const numParticles = Math.min(100, Math.floor((width * height) / 15000));
|
|
567
|
+
|
|
568
|
+
const colors = ['#22d3ee', '#a78bfa', '#34d399'];
|
|
569
|
+
for (let i = 0; i < numParticles; i++) {
|
|
570
|
+
particles.push({
|
|
571
|
+
x: Math.random() * width,
|
|
572
|
+
y: Math.random() * height,
|
|
573
|
+
vx: (Math.random() - 0.5) * 1.5,
|
|
574
|
+
vy: (Math.random() - 0.5) * 1.5,
|
|
575
|
+
radius: Math.random() * 2 + 1,
|
|
576
|
+
color: colors[Math.floor(Math.random() * colors.length)]
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
window.addEventListener('resize', initBackground);
|
|
581
|
+
window.addEventListener('mousemove', (e) => { mouse.x = e.clientX; mouse.y = e.clientY; });
|
|
582
|
+
window.addEventListener('mouseout', () => { mouse.x = null; mouse.y = null; });
|
|
583
|
+
|
|
584
|
+
function animateBackground() {
|
|
585
|
+
ctx.clearRect(0, 0, width, height);
|
|
586
|
+
|
|
587
|
+
// Update and draw particles
|
|
588
|
+
for (let i = 0; i < particles.length; i++) {
|
|
589
|
+
const p = particles[i];
|
|
590
|
+
p.x += p.vx;
|
|
591
|
+
p.y += p.vy;
|
|
592
|
+
if (p.x < 0 || p.x > width) p.vx *= -1;
|
|
593
|
+
if (p.y < 0 || p.y > height) p.vy *= -1;
|
|
594
|
+
|
|
595
|
+
ctx.beginPath();
|
|
596
|
+
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
|
|
597
|
+
ctx.fillStyle = p.color;
|
|
598
|
+
ctx.fill();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Connect particles
|
|
602
|
+
for (let i = 0; i < particles.length; i++) {
|
|
603
|
+
for (let j = i + 1; j < particles.length; j++) {
|
|
604
|
+
const p1 = particles[i], p2 = particles[j];
|
|
605
|
+
const dx = p1.x - p2.x, dy = p1.y - p2.y;
|
|
606
|
+
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
607
|
+
if (dist < 120) {
|
|
608
|
+
ctx.beginPath();
|
|
609
|
+
ctx.strokeStyle = \`rgba(0, 229, 255, \${0.15 - dist/120 * 0.15})\`;
|
|
610
|
+
ctx.lineWidth = 1.2;
|
|
611
|
+
ctx.moveTo(p1.x, p1.y);
|
|
612
|
+
ctx.lineTo(p2.x, p2.y);
|
|
613
|
+
ctx.stroke();
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Connect to mouse
|
|
618
|
+
if (mouse.x != null) {
|
|
619
|
+
const dx = particles[i].x - mouse.x, dy = particles[i].y - mouse.y;
|
|
620
|
+
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
621
|
+
if (dist < 150) {
|
|
622
|
+
ctx.beginPath();
|
|
623
|
+
ctx.strokeStyle = \`rgba(167, 139, 250, \${0.2 - dist/150 * 0.2})\`;
|
|
624
|
+
ctx.lineWidth = 2.0;
|
|
625
|
+
ctx.moveTo(particles[i].x, particles[i].y);
|
|
626
|
+
ctx.lineTo(mouse.x, mouse.y);
|
|
627
|
+
ctx.stroke();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
requestAnimationFrame(animateBackground);
|
|
632
|
+
}
|
|
633
|
+
initBackground();
|
|
634
|
+
animateBackground();
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
// --- LOGICA DE TABLA (PAGINADOR & ORDEN) ---
|
|
638
|
+
let sortAsc = false;
|
|
639
|
+
let currentPage = 1;
|
|
640
|
+
let pageSize = 20;
|
|
641
|
+
let filteredRows = [];
|
|
642
|
+
let allRows = [];
|
|
643
|
+
|
|
644
|
+
window.onload = () => {
|
|
645
|
+
allRows = Array.from(document.querySelectorAll('#tbody tr'));
|
|
646
|
+
filteredRows = [...allRows];
|
|
647
|
+
sortAsc = true;
|
|
648
|
+
sortTable(2, 'num');
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
function changePageSize(val) {
|
|
652
|
+
if (val === 'all') {
|
|
653
|
+
pageSize = filteredRows.length > 0 ? filteredRows.length : 10000;
|
|
654
|
+
} else {
|
|
655
|
+
pageSize = parseInt(val);
|
|
656
|
+
}
|
|
657
|
+
currentPage = 1;
|
|
658
|
+
renderTable();
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function renderTable() {
|
|
662
|
+
const tbody = document.getElementById('tbody');
|
|
663
|
+
tbody.innerHTML = '';
|
|
664
|
+
const start = (currentPage - 1) * pageSize;
|
|
665
|
+
const end = start + pageSize;
|
|
666
|
+
const pageRows = filteredRows.slice(start, end);
|
|
667
|
+
pageRows.forEach(r => tbody.appendChild(r));
|
|
668
|
+
|
|
669
|
+
const totalPages = Math.ceil(filteredRows.length / pageSize) || 1;
|
|
670
|
+
document.getElementById('page-info').textContent = \`Mostrando \${start+1} - \${Math.min(end, filteredRows.length)} de \${filteredRows.length} registros\`;
|
|
671
|
+
|
|
672
|
+
renderPaginationControls(totalPages);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function renderPaginationControls(totalPages) {
|
|
676
|
+
const cont = document.getElementById('pag-controls');
|
|
677
|
+
cont.innerHTML = '';
|
|
678
|
+
if (totalPages <= 1) return;
|
|
679
|
+
|
|
680
|
+
// Prev Button
|
|
681
|
+
const btnPrev = document.createElement('button');
|
|
682
|
+
btnPrev.className = 'pag-btn';
|
|
683
|
+
btnPrev.textContent = '«';
|
|
684
|
+
btnPrev.disabled = currentPage === 1;
|
|
685
|
+
btnPrev.onclick = () => { currentPage--; renderTable(); };
|
|
686
|
+
cont.appendChild(btnPrev);
|
|
687
|
+
|
|
688
|
+
// Page Numbers
|
|
689
|
+
let startPage = Math.max(1, currentPage - 2);
|
|
690
|
+
let endPage = Math.min(totalPages, currentPage + 2);
|
|
691
|
+
|
|
692
|
+
if (startPage > 1) {
|
|
693
|
+
cont.appendChild(createPageBtn(1));
|
|
694
|
+
if (startPage > 2) { const d = document.createElement('span'); d.className='pag-dots'; d.textContent='...'; cont.appendChild(d); }
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
698
|
+
cont.appendChild(createPageBtn(i));
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (endPage < totalPages) {
|
|
702
|
+
if (endPage < totalPages - 1) { const d = document.createElement('span'); d.className='pag-dots'; d.textContent='...'; cont.appendChild(d); }
|
|
703
|
+
cont.appendChild(createPageBtn(totalPages));
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Next Button
|
|
707
|
+
const btnNext = document.createElement('button');
|
|
708
|
+
btnNext.className = 'pag-btn';
|
|
709
|
+
btnNext.textContent = '»';
|
|
710
|
+
btnNext.disabled = currentPage === totalPages;
|
|
711
|
+
btnNext.onclick = () => { currentPage++; renderTable(); };
|
|
712
|
+
cont.appendChild(btnNext);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function createPageBtn(num) {
|
|
716
|
+
const btn = document.createElement('button');
|
|
717
|
+
btn.className = 'pag-btn' + (num === currentPage ? ' active' : '');
|
|
718
|
+
btn.textContent = num;
|
|
719
|
+
btn.onclick = () => { currentPage = num; renderTable(); };
|
|
720
|
+
return btn;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function sortTable(colIdx, type) {
|
|
724
|
+
sortAsc = !sortAsc;
|
|
725
|
+
filteredRows.sort((a, b) => {
|
|
726
|
+
let valA, valB;
|
|
727
|
+
if (type === 'num') {
|
|
728
|
+
valA = parseInt(a.children[colIdx].getAttribute('data-occ') || '0');
|
|
729
|
+
valB = parseInt(b.children[colIdx].getAttribute('data-occ') || '0');
|
|
730
|
+
} else {
|
|
731
|
+
valA = a.children[colIdx].textContent.trim();
|
|
732
|
+
valB = b.children[colIdx].textContent.trim();
|
|
733
|
+
}
|
|
734
|
+
if (valA < valB) return sortAsc ? -1 : 1;
|
|
735
|
+
if (valA > valB) return sortAsc ? 1 : -1;
|
|
736
|
+
return 0;
|
|
737
|
+
});
|
|
738
|
+
currentPage = 1;
|
|
739
|
+
renderTable();
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
let activeCat = 'all';
|
|
743
|
+
let searchQuery = '';
|
|
744
|
+
|
|
745
|
+
function filter(cat, btn) {
|
|
746
|
+
document.querySelectorAll('.fbtn').forEach(b=>b.classList.remove('active'));
|
|
747
|
+
if(btn) btn.classList.add('active');
|
|
748
|
+
activeCat = cat;
|
|
749
|
+
applyFilters();
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
function search(q) {
|
|
753
|
+
searchQuery = q;
|
|
754
|
+
applyFilters();
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function applyFilters() {
|
|
758
|
+
let regex = null;
|
|
759
|
+
let lq = searchQuery.toLowerCase();
|
|
760
|
+
try { if (searchQuery) regex = new RegExp(searchQuery, 'i'); } catch(e) {}
|
|
761
|
+
|
|
762
|
+
filteredRows = allRows.filter(r => {
|
|
763
|
+
const catMatch = (activeCat === 'all' || r.getAttribute('data-cat') === activeCat);
|
|
764
|
+
if (!catMatch) return false;
|
|
765
|
+
|
|
766
|
+
const txt = r.textContent;
|
|
767
|
+
if (!searchQuery) return true;
|
|
768
|
+
if (regex && regex.test(txt)) return true;
|
|
769
|
+
return txt.toLowerCase().includes(lq);
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
currentPage = 1;
|
|
773
|
+
renderTable();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function copyText(el) {
|
|
777
|
+
const text = el.innerText;
|
|
778
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
779
|
+
const toast = document.getElementById('toast');
|
|
780
|
+
toast.classList.add('show');
|
|
781
|
+
setTimeout(() => toast.classList.remove('show'), 2000);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
function exportCSV() {
|
|
786
|
+
let csv = "Tailwind Original,AUM-IC Transmutada,Frecuencia,Nivel\\n";
|
|
787
|
+
filteredRows.forEach(r => {
|
|
788
|
+
const cols = r.querySelectorAll('td');
|
|
789
|
+
const orig = cols[0].innerText;
|
|
790
|
+
const aumic = cols[1].innerText;
|
|
791
|
+
const occ = cols[2].querySelector('span').innerText;
|
|
792
|
+
const lvl = cols[3].innerText;
|
|
793
|
+
csv += String.fromCharCode(34) + orig + String.fromCharCode(34) + "," + String.fromCharCode(34) + aumic + String.fromCharCode(34) + "," + occ + "," + String.fromCharCode(34) + lvl + String.fromCharCode(34) + "\\n";
|
|
794
|
+
});
|
|
795
|
+
const blob = new Blob([csv], { type: 'text/csv' });
|
|
796
|
+
const url = window.URL.createObjectURL(blob);
|
|
797
|
+
const a = document.createElement('a');
|
|
798
|
+
a.href = url;
|
|
799
|
+
a.download = 'aumic-report.csv';
|
|
800
|
+
a.click();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function exportMD() {
|
|
804
|
+
let md = "| Tailwind Original | AUM-IC Transmutada | Frecuencia | Nivel |\\n|---|---|---|---|\\n";
|
|
805
|
+
filteredRows.forEach(r => {
|
|
806
|
+
const cols = r.querySelectorAll('td');
|
|
807
|
+
const orig = cols[0].innerText.replace(/\|/g, '|');
|
|
808
|
+
const aumic = cols[1].innerText.replace(/\|/g, '|');
|
|
809
|
+
const occ = cols[2].querySelector('span').innerText;
|
|
810
|
+
const lvl = cols[3].innerText;
|
|
811
|
+
md += "| " + orig + " | " + aumic + " | " + occ + " | " + lvl + " |\\n";
|
|
812
|
+
});
|
|
813
|
+
const blob = new Blob([md], { type: 'text/markdown' });
|
|
814
|
+
const url = window.URL.createObjectURL(blob);
|
|
815
|
+
const a = document.createElement('a');
|
|
816
|
+
a.href = url;
|
|
817
|
+
a.download = 'aumic-report.md';
|
|
818
|
+
a.click();
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
document.addEventListener('keydown', (e) => {
|
|
822
|
+
if (e.key === '/' && document.activeElement.id !== 'searchInput') {
|
|
823
|
+
e.preventDefault();
|
|
824
|
+
document.getElementById('searchInput').focus();
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
|
|
827
828
|
</script></body></html>`;
|
|
828
829
|
fs_extra_1.default.writeFileSync(reportPath, html);
|
|
829
830
|
return reportPath;
|
|
@@ -1154,6 +1155,92 @@ async function run() {
|
|
|
1154
1155
|
return;
|
|
1155
1156
|
}
|
|
1156
1157
|
spinner.succeed(`Se extrajeron ${globalExtracted.size} bloques únicos de Tailwind.`);
|
|
1158
|
+
// --- NUEVO: JIT VALIDATOR PASS (Zero-Bloat Seguro) ---
|
|
1159
|
+
spinner.start('Verificando clases nativas de Tailwind vs Custom CSS (JIT Validator)...');
|
|
1160
|
+
const allUniqueTokens = new Set();
|
|
1161
|
+
for (const orig of globalExtracted.keys()) {
|
|
1162
|
+
orig.split(' ').forEach(t => { if (t.trim() && !t.includes('aumic-'))
|
|
1163
|
+
allUniqueTokens.add(t.trim()); });
|
|
1164
|
+
}
|
|
1165
|
+
const testHtml = Array.from(allUniqueTokens).map(t => `<div class="${t}"></div>`).join('\n');
|
|
1166
|
+
const configPath = require('fs').existsSync(require('path').resolve(TARGET_DIR, 'tailwind.config.js')) ? require('path').resolve(TARGET_DIR, 'tailwind.config.js') : (require('fs').existsSync(require('path').resolve(TARGET_DIR, 'tailwind.config.mjs')) ? require('path').resolve(TARGET_DIR, 'tailwind.config.mjs') : null);
|
|
1167
|
+
if (configPath) {
|
|
1168
|
+
try {
|
|
1169
|
+
const dynamicImport = new Function('modulePath', 'return import(modulePath)');
|
|
1170
|
+
userConfig = (await dynamicImport(require('url').pathToFileURL(configPath).href)).default || require(configPath);
|
|
1171
|
+
}
|
|
1172
|
+
catch (e) {
|
|
1173
|
+
try {
|
|
1174
|
+
userConfig = require(configPath);
|
|
1175
|
+
}
|
|
1176
|
+
catch (err) {
|
|
1177
|
+
try {
|
|
1178
|
+
const fsExt = require('fs');
|
|
1179
|
+
const tempPath = configPath + '.mjs';
|
|
1180
|
+
let raw = fsExt.readFileSync(configPath, 'utf8');
|
|
1181
|
+
raw = raw.replace(/module\.exports\s*=\s*/, 'export default ');
|
|
1182
|
+
fsExt.writeFileSync(tempPath, raw, 'utf8');
|
|
1183
|
+
const dynamicImport = new Function('modulePath', 'return import(modulePath)');
|
|
1184
|
+
userConfig = (await dynamicImport(require('url').pathToFileURL(tempPath).href)).default;
|
|
1185
|
+
fsExt.unlinkSync(tempPath);
|
|
1186
|
+
}
|
|
1187
|
+
catch (fatal) {
|
|
1188
|
+
console.log('[AUM-IC] Fallo al cargar Tailwind Config:', fatal.message);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
let mergedConfig = { content: [{ raw: testHtml, extension: 'html' }], corePlugins: { preflight: false }, theme: userConfig.theme || {} };
|
|
1194
|
+
let testPlugin;
|
|
1195
|
+
try {
|
|
1196
|
+
testPlugin = require('tailwindcss')(mergedConfig);
|
|
1197
|
+
}
|
|
1198
|
+
catch (e) {
|
|
1199
|
+
testPlugin = require('tailwindcss');
|
|
1200
|
+
}
|
|
1201
|
+
const testJit = await (0, postcss_1.default)([testPlugin]).process(`@tailwind utilities;`, { from: undefined });
|
|
1202
|
+
const testRoot = postcss_1.default.parse(testJit.css);
|
|
1203
|
+
const validTwClasses = new Set();
|
|
1204
|
+
testRoot.walkRules((rule) => {
|
|
1205
|
+
const allTokensArr = Array.from(allUniqueTokens);
|
|
1206
|
+
for (const token of allTokensArr) {
|
|
1207
|
+
const escaped = '.' + escapeCssSelector(token);
|
|
1208
|
+
if (rule.selector.includes(escaped)) {
|
|
1209
|
+
validTwClasses.add(token);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
spinner.succeed(`Filtro JIT completado: ${validTwClasses.size} utilidades nativas reconocidas.`);
|
|
1214
|
+
spinner.start('Analizando entorno y dependencias de Tailwind...');
|
|
1215
|
+
const envStatus = { version: 3, usesAstro: false, usesVite: false, usesPostcss: false, importsPreflight: false, importsUtilities: false, cssEntrypoint: '' };
|
|
1216
|
+
try {
|
|
1217
|
+
const p = require(path_1.default.join(TARGET_DIR, 'package.json'));
|
|
1218
|
+
const deps = { ...(p.dependencies || {}), ...(p.devDependencies || {}) };
|
|
1219
|
+
if (deps['tailwindcss'])
|
|
1220
|
+
envStatus.version = deps['tailwindcss'].startsWith('^4') || deps['tailwindcss'].startsWith('4') ? 4 : 3;
|
|
1221
|
+
else if (deps['@tailwindcss/vite'] || deps['@tailwindcss/postcss'])
|
|
1222
|
+
envStatus.version = 4;
|
|
1223
|
+
envStatus.usesAstro = !!deps['@astrojs/tailwind'];
|
|
1224
|
+
envStatus.usesVite = !!deps['@tailwindcss/vite'];
|
|
1225
|
+
envStatus.usesPostcss = !!deps['@tailwindcss/postcss'];
|
|
1226
|
+
}
|
|
1227
|
+
catch (e) { }
|
|
1228
|
+
const rootCssFiles = await (0, glob_1.glob)('**/*.{css,scss,sass,less,pcss}', { cwd: TARGET_DIR, absolute: true, ignore: ['node_modules/**', 'dist/**', 'public/**'] });
|
|
1229
|
+
for (const file of rootCssFiles) {
|
|
1230
|
+
const c = await fs_extra_1.default.readFile(file, 'utf-8');
|
|
1231
|
+
if (c.includes('@tailwind') || c.includes('tailwindcss')) {
|
|
1232
|
+
envStatus.cssEntrypoint = file;
|
|
1233
|
+
if (c.includes('@tailwind base') || c.includes('tailwindcss/preflight') || c.includes('@import "tailwindcss"'))
|
|
1234
|
+
envStatus.importsPreflight = true;
|
|
1235
|
+
if (c.includes('@tailwind utilities') || c.includes('tailwindcss/utilities') || c.includes('@import "tailwindcss"'))
|
|
1236
|
+
envStatus.importsUtilities = true;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
if (envStatus.usesAstro) {
|
|
1240
|
+
envStatus.importsPreflight = true;
|
|
1241
|
+
envStatus.importsUtilities = true;
|
|
1242
|
+
}
|
|
1243
|
+
spinner.succeed(picocolors_1.default.cyan(`Entorno JIT Dinámico: Tailwind v${envStatus.version} | Preflight: ${envStatus.importsPreflight ? 'Activo' : 'Inactivo'} | Integración: ${envStatus.usesVite ? 'Vite' : envStatus.usesAstro ? 'Astro' : 'PostCSS'}`));
|
|
1157
1244
|
const classMapping = new Map();
|
|
1158
1245
|
let customRules = '';
|
|
1159
1246
|
const rcPath = path_1.default.join(TARGET_DIR, '.aumicrc.json');
|
|
@@ -1193,7 +1280,13 @@ async function run() {
|
|
|
1193
1280
|
await fs_extra_1.default.writeJson(memoryPath, finalMapping, { spaces: 2 });
|
|
1194
1281
|
for (const [orig, { category, component, occurrences }] of globalExtracted) {
|
|
1195
1282
|
const cleanAumic = finalMapping[orig] || `aumic-ai-${component}-${getHash(orig)}`;
|
|
1196
|
-
|
|
1283
|
+
const fullArray = orig.split(' ');
|
|
1284
|
+
const twArray = fullArray.filter(c => validTwClasses.has(c));
|
|
1285
|
+
const customArray = fullArray.filter(c => !validTwClasses.has(c));
|
|
1286
|
+
const repString = customArray.length > 0 ? (twArray.length > 0 ? cleanAumic + ' ' + customArray.join(' ') : customArray.join(' ')) : cleanAumic;
|
|
1287
|
+
if (twArray.length > 0) {
|
|
1288
|
+
classMapping.set(orig, { original: orig, array: fullArray, tailwindOnlyArray: twArray, customArray, aumicClass: cleanAumic, replacementString: repString, category, component, occurrences });
|
|
1289
|
+
}
|
|
1197
1290
|
}
|
|
1198
1291
|
}
|
|
1199
1292
|
else {
|
|
@@ -1207,7 +1300,14 @@ async function run() {
|
|
|
1207
1300
|
};
|
|
1208
1301
|
for (const [orig, { category, component, occurrences }] of globalExtracted) {
|
|
1209
1302
|
const prefix = levelPrefix[category] || 'molecule';
|
|
1210
|
-
|
|
1303
|
+
const fullArray = orig.split(' ');
|
|
1304
|
+
const twArray = fullArray.filter(c => validTwClasses.has(c));
|
|
1305
|
+
const customArray = fullArray.filter(c => !validTwClasses.has(c));
|
|
1306
|
+
const hashAumic = `aumic-${prefix}-${component}-${getHash(orig)}`;
|
|
1307
|
+
const repString = customArray.length > 0 ? (twArray.length > 0 ? hashAumic + ' ' + customArray.join(' ') : customArray.join(' ')) : hashAumic;
|
|
1308
|
+
if (twArray.length > 0) {
|
|
1309
|
+
classMapping.set(orig, { original: orig, array: fullArray, tailwindOnlyArray: twArray, customArray, aumicClass: hashAumic, replacementString: repString, category, component, occurrences });
|
|
1310
|
+
}
|
|
1211
1311
|
}
|
|
1212
1312
|
spinner.succeed('Hashes generados.');
|
|
1213
1313
|
}
|
|
@@ -1280,7 +1380,7 @@ async function run() {
|
|
|
1280
1380
|
const utilityToAumic = new Map();
|
|
1281
1381
|
for (const [_, mapping] of classMapping) {
|
|
1282
1382
|
const cat = mapping.category || 'molecules';
|
|
1283
|
-
for (const util of mapping.
|
|
1383
|
+
for (const util of mapping.tailwindOnlyArray) {
|
|
1284
1384
|
const escaped = '.' + escapeCssSelector(util);
|
|
1285
1385
|
const list = utilityToAumic.get(escaped) || [];
|
|
1286
1386
|
list.push({ aumicClass: mapping.aumicClass, category: cat });
|
|
@@ -1327,13 +1427,70 @@ async function run() {
|
|
|
1327
1427
|
spinner.succeed(`CSS extranjero hackeado y reescrito a la doctrina ${aumicLink}.`);
|
|
1328
1428
|
}
|
|
1329
1429
|
else {
|
|
1330
|
-
spinner.start(`Fase 4:
|
|
1331
|
-
|
|
1430
|
+
spinner.start(`Fase 4: Ejecutando L1 Cache (DuckDB) y delegando L2 (JIT v${twVersion})...`);
|
|
1431
|
+
// --- L1 DUCKDB CACHE ---
|
|
1432
|
+
const duckdb = require('duckdb');
|
|
1433
|
+
const dbPath = path_1.default.join(__dirname, '../aumic-lexicon.duckdb');
|
|
1434
|
+
const db = new duckdb.Database(dbPath);
|
|
1435
|
+
let l1Css = '';
|
|
1436
|
+
let unresolvedClasses = new Set();
|
|
1437
|
+
const allTwClasses = new Set();
|
|
1438
|
+
for (const map of classMapping.values()) {
|
|
1439
|
+
map.tailwindOnlyArray.forEach(cls => allTwClasses.add(cls));
|
|
1440
|
+
}
|
|
1441
|
+
const classArray = Array.from(allTwClasses);
|
|
1442
|
+
const l1Promises = classArray.map(cls => {
|
|
1443
|
+
return new Promise((resolve) => {
|
|
1444
|
+
db.all("SELECT css FROM tw_lexicon WHERE version = ? AND class = ?", [twVersion, cls], (err, rows) => {
|
|
1445
|
+
if (err || rows.length === 0) {
|
|
1446
|
+
unresolvedClasses.add(cls);
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
l1Css += `\n/* tw: ${cls} (L1) */\n.${escapeCssSelector(cls)} { ${rows[0].css} }\n`;
|
|
1450
|
+
}
|
|
1451
|
+
resolve();
|
|
1452
|
+
});
|
|
1453
|
+
});
|
|
1454
|
+
});
|
|
1455
|
+
await Promise.all(l1Promises);
|
|
1456
|
+
db.close();
|
|
1457
|
+
// --- L2 DYNAMIC JIT ---
|
|
1458
|
+
const virtualHtml = Array.from(unresolvedClasses).map(cls => `<div class="${cls}"></div>`).join('\n');
|
|
1459
|
+
const projectTwPath = path_1.default.join(TARGET_DIR, 'node_modules', 'tailwindcss');
|
|
1332
1460
|
let twPlugin;
|
|
1333
|
-
|
|
1461
|
+
if (fs_extra_1.default.existsSync(projectTwPath)) {
|
|
1462
|
+
twPlugin = require(projectTwPath)({ content: [{ raw: virtualHtml, extension: 'html' }], corePlugins: { preflight: false }, theme: userConfig.theme || {} });
|
|
1463
|
+
}
|
|
1464
|
+
else {
|
|
1465
|
+
twPlugin = require('tailwindcss')({ content: [{ raw: virtualHtml, extension: 'html' }], corePlugins: { preflight: false }, theme: userConfig.theme || {} });
|
|
1466
|
+
}
|
|
1334
1467
|
await piscinaPool.destroy();
|
|
1335
1468
|
const jitResult = await (0, postcss_1.default)([twPlugin]).process(`@tailwind utilities;`, { from: undefined });
|
|
1336
|
-
const root = postcss_1.default.parse(jitResult.css);
|
|
1469
|
+
const root = postcss_1.default.parse(l1Css + '\n' + jitResult.css);
|
|
1470
|
+
// =======================================
|
|
1471
|
+
// AUM-IC PREFLIGHT INJECTOR
|
|
1472
|
+
// =======================================
|
|
1473
|
+
let preflightCss = '';
|
|
1474
|
+
if (envStatus.importsPreflight) {
|
|
1475
|
+
try {
|
|
1476
|
+
let pfPlugin;
|
|
1477
|
+
if (fs_extra_1.default.existsSync(projectTwPath)) {
|
|
1478
|
+
pfPlugin = require(projectTwPath)({ content: [{ raw: '<div class="a"></div>', extension: 'html' }], theme: userConfig.theme || {} });
|
|
1479
|
+
}
|
|
1480
|
+
else {
|
|
1481
|
+
pfPlugin = require('tailwindcss')({ content: [{ raw: '<div class="a"></div>', extension: 'html' }], theme: userConfig.theme || {} });
|
|
1482
|
+
}
|
|
1483
|
+
const pfRes = await (0, postcss_1.default)([pfPlugin]).process('@tailwind base;', { from: undefined });
|
|
1484
|
+
preflightCss = pfRes.css;
|
|
1485
|
+
}
|
|
1486
|
+
catch (e) {
|
|
1487
|
+
console.warn("No se pudo extraer Preflight.");
|
|
1488
|
+
}
|
|
1489
|
+
} // end if importsPreflight
|
|
1490
|
+
if (preflightCss) {
|
|
1491
|
+
const pfAst = postcss_1.default.parse(preflightCss);
|
|
1492
|
+
globalRoot.prepend(pfAst);
|
|
1493
|
+
}
|
|
1337
1494
|
root.walkRules((rule) => {
|
|
1338
1495
|
for (const [escapedUtil, targets] of utilityToAumic) {
|
|
1339
1496
|
if (rule.selector.includes(escapedUtil)) {
|
|
@@ -1355,7 +1512,16 @@ async function run() {
|
|
|
1355
1512
|
}
|
|
1356
1513
|
});
|
|
1357
1514
|
if (answers.outputMode === 'global') {
|
|
1358
|
-
|
|
1515
|
+
const outPath = path_1.default.join(TARGET_DIR, 'src', 'styles');
|
|
1516
|
+
require('fs-extra').ensureDirSync(outPath);
|
|
1517
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outPath, 'aumic-styles.css'), themeVars + globalRoot.toString(), 'utf-8');
|
|
1518
|
+
const globalScss = path_1.default.join(outPath, 'global.scss');
|
|
1519
|
+
if (fs_extra_1.default.existsSync(globalScss)) {
|
|
1520
|
+
let scss = fs_extra_1.default.readFileSync(globalScss, 'utf8');
|
|
1521
|
+
if (!scss.includes('aumic-styles')) {
|
|
1522
|
+
fs_extra_1.default.writeFileSync(globalScss, scss + '\n@import "./aumic-styles.css";\n', 'utf8');
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1359
1525
|
}
|
|
1360
1526
|
else {
|
|
1361
1527
|
for (const [cat, cssRoot] of Object.entries(categoryRoots)) {
|
|
@@ -1389,7 +1555,47 @@ async function run() {
|
|
|
1389
1555
|
fs_extra_1.default.renameSync(confPath, `${confPath}.aumic-bak`);
|
|
1390
1556
|
}
|
|
1391
1557
|
});
|
|
1392
|
-
|
|
1558
|
+
// ==========================================
|
|
1559
|
+
// UNIVERSAL TAILWIND ERADICATOR (v1 - v4)
|
|
1560
|
+
// ==========================================
|
|
1561
|
+
// 1. Respaldar y neutralizar archivos de configuración (v1, v2, v3)
|
|
1562
|
+
const twConfigFiles = ['tailwind.config.js', 'tailwind.config.ts', 'tailwind.config.cjs', 'tailwind.config.mjs', 'tailwind.js'];
|
|
1563
|
+
twConfigFiles.forEach(conf => {
|
|
1564
|
+
const confPath = require('path').join(TARGET_DIR, conf);
|
|
1565
|
+
if (fs_extra_1.default.existsSync(confPath))
|
|
1566
|
+
fs_extra_1.default.renameSync(confPath, `${confPath}.aumic-bak`);
|
|
1567
|
+
});
|
|
1568
|
+
// 2. Limpieza de Integradores (v4 Vite, Astro, PostCSS)
|
|
1569
|
+
const integrations = [
|
|
1570
|
+
{ file: 'astro.config.mjs', regex: /import\s+tailwind\s+from\s+['"]@astrojs\/tailwind['"];?\n?/, regex2: /tailwind\(\)\s*,?/ },
|
|
1571
|
+
{ file: 'astro.config.ts', regex: /import\s+tailwind\s+from\s+['"]@astrojs\/tailwind['"];?\n?/, regex2: /tailwind\(\)\s*,?/ },
|
|
1572
|
+
{ file: 'vite.config.js', regex: /import\s+tailwindcss\s+from\s+['"]@tailwindcss\/vite['"];?\n?/, regex2: /tailwindcss\(\)\s*,?/ },
|
|
1573
|
+
{ file: 'vite.config.ts', regex: /import\s+tailwindcss\s+from\s+['"]@tailwindcss\/vite['"];?\n?/, regex2: /tailwindcss\(\)\s*,?/ }
|
|
1574
|
+
];
|
|
1575
|
+
integrations.forEach(intg => {
|
|
1576
|
+
const intgPath = require('path').join(TARGET_DIR, intg.file);
|
|
1577
|
+
if (fs_extra_1.default.existsSync(intgPath)) {
|
|
1578
|
+
let c = fs_extra_1.default.readFileSync(intgPath, 'utf8');
|
|
1579
|
+
c = c.replace(intg.regex, '');
|
|
1580
|
+
c = c.replace(intg.regex2, '');
|
|
1581
|
+
fs_extra_1.default.writeFileSync(intgPath, c, 'utf8');
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
// 3. Desinstalación Dinámica Universal (Identifica dependencias exactas en package.json)
|
|
1585
|
+
try {
|
|
1586
|
+
const pkg = require(require('path').join(TARGET_DIR, 'package.json'));
|
|
1587
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
1588
|
+
const targets = ['tailwindcss', '@tailwindcss/vite', '@tailwindcss/postcss', '@tailwindcss/cli', '@astrojs/tailwind'];
|
|
1589
|
+
// Si encontramos tailwind v1 o v2, muchas veces se usaba autoprefixer a la par estrictamente.
|
|
1590
|
+
if (allDeps['tailwindcss'] && (allDeps['tailwindcss'].startsWith('^1') || allDeps['tailwindcss'].startsWith('^2'))) {
|
|
1591
|
+
// Solo como heurÃstica
|
|
1592
|
+
}
|
|
1593
|
+
const toUninstall = targets.filter(t => allDeps[t]);
|
|
1594
|
+
if (toUninstall.length > 0) {
|
|
1595
|
+
require('child_process').execSync(`npm uninstall ${toUninstall.join(' ')}`, { cwd: TARGET_DIR, stdio: 'ignore' });
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
catch (e) { }
|
|
1393
1599
|
spinner.succeed(picocolors_1.default.green('Tailwind ha sido purgado completamente. (Configuraciones y package.json respaldados en .aumic-bak)'));
|
|
1394
1600
|
}
|
|
1395
1601
|
catch (e) {
|
|
@@ -1398,7 +1604,7 @@ async function run() {
|
|
|
1398
1604
|
}
|
|
1399
1605
|
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
1400
1606
|
logAudit(`[EJECUCIÓN] Operación completada exitosamente en ${duration} segundos.`);
|
|
1401
|
-
console.log(picocolors_1.default.green(picocolors_1.default.bold(`\n[✔] PROYECTO TRANSMUTADO A LA DOCTRINA ${aumicLink}. (
|
|
1607
|
+
console.log(picocolors_1.default.green(picocolors_1.default.bold(`\n[✔] PROYECTO TRANSMUTADO A LA DOCTRINA ${aumicLink}. (v${pkgVersion})\n`)));
|
|
1402
1608
|
// Generate Final Report
|
|
1403
1609
|
spinner.start('Generando reporte post-mortem...');
|
|
1404
1610
|
const postReportPath = generateReport(classMapping, TARGET_DIR, false);
|