ReviewOS

also looking at this

stacks/system-cleaner

Migrate x-text/:text bindings to {⁠{ }} interpolation (stx 0.2.72)

#12
Merged glennmichael123 wants to merge chore/migrate-text-to-mustache into main
15 files +138 -147
bun.lockmodified+12-20
Changes to bun.lock
@@ -6,13 +6,13 @@
66 "name": "system-cleaner",
77 "dependencies": {
88 "@stacksjs/bun-router": "^0.0.15",
9 "@stacksjs/stx": "0.2.48",
9 "@stacksjs/stx": "^0.2.72",
1010 "@system-cleaner/clean": "workspace:*",
1111 "@system-cleaner/core": "workspace:*",
1212 "@system-cleaner/disk": "workspace:*",
1313 "@system-cleaner/monitor": "workspace:*",
1414 "@system-cleaner/uninstall": "workspace:*",
15 "bun-plugin-stx": "^0.2.47",
15 "bun-plugin-stx": "^0.2.72",
1616 "stx-router": "0.2.48",
1717 "ts-broadcasting": "^0.0.5",
1818 },
@@ -94,7 +94,7 @@
9494
9595 "@stacksjs/clarity": ["@stacksjs/clarity@0.3.28", "", { "dependencies": { "bunfig": "^0.15.6" }, "bin": { "clarity": "./dist/bin/cli.js" } }, "sha512-SElzGeDewEbp0c4C8PTfdvi/Xtr1HGAjG6b0prHvkVxyYGM+2R0BFU0otUmy+DbR7wsfZ4rNU3YN1+JK/CzoTw=="],
9696
97 "@stacksjs/desktop": ["@stacksjs/desktop@0.2.46", "", { "peerDependencies": { "craft": "*" }, "optionalPeers": ["craft"] }, "sha512-wClqZ94DPqE6dPjWMXDUObMlasghXmWnfm4t1QFGKETBJM/e0HHcNOwYWd2G1BbzcjPUWG4rdw+XOWzaJE0Z1A=="],
97 "@stacksjs/desktop": ["@stacksjs/desktop@0.2.72", "", { "peerDependencies": { "craft": "*" }, "optionalPeers": ["craft"] }, "sha512-R436Ag4EdDhzM96idRHF61R+FkhwbtRbalQzEV/TRSYCMwJpVwJju5gQA08u+5elEZgCGATjtUia4GBbnJKWCw=="],
9898
9999 "@stacksjs/dtsx": ["@stacksjs/dtsx@0.9.26", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0" }, "peerDependencies": { "typescript": ">=5.9.3" }, "bin": { "dtsx": "./dist/bin/cli.js" } }, "sha512-MOUxZn8BhXpFYM+vh7cnQLUOLjZ4G6q76V+4OypkRiu/Gvpek9ywBQLbmv8iWLjT6gXlFMpEdw33o3GKKLpMCw=="],
100100
@@ -102,9 +102,9 @@
102102
103103 "@stacksjs/logsmith": ["@stacksjs/logsmith@0.2.3", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "bunfig": "^0.15.6", "pickier": "^0.1.9" }, "bin": { "@stacksjs/logsmith": "./dist/bin/cli.js", "logsmith": "./dist/bin/cli.js" } }, "sha512-Jy2AHVdEQwDtjlOVSG4xOmIMSy/D2iZcPK7KaoDOmKfZbMmfmbhveK16w1TWKCY9duhMZigdpeFx39ZzXGARVg=="],
104104
105 "@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.35", "", {}, "sha512-DpZPnfEazZ9LcdtOExDs1EScqYm8gRZMI3GrYwLsKqjap4EKNKuk8JVF80Go/WWoslcyGEHWjiTnYAx3nxwEkA=="],
105 "@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.72", "", {}, "sha512-66a3QSfuSAgDDZJ3Z/mgqHEtkYwfag1m+9636I4X5cveTA69O92/0aEp6+f5MgGfPA+Gv4gkl3ArP8FBslR0BQ=="],
106106
107 "@stacksjs/stx": ["@stacksjs/stx@0.2.48", "", { "dependencies": { "@cwcss/crosswind": "^0.2.0", "@stacksjs/clapp": "^0.2.0", "@stacksjs/desktop": "0.2.46", "@stacksjs/sanitizer": "0.2.35", "@stacksjs/ts-craft": "^0.0.2", "bun-plugin-stx": "0.2.47", "bunfig": "^0.15.6", "stx-router": "0.2.48", "ts-broadcasting": "^0.0.4", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-S+vV0MHrKT00xQtUfdzx7iaFllJS9zHZ8csCWa1LVjISu1ITLtUmYi6F9RKf5CtIi710HCYj5aviVYLQfyO5fA=="],
107 "@stacksjs/stx": ["@stacksjs/stx@0.2.72", "", { "dependencies": { "@cwcss/crosswind": "^0.2.0", "@stacksjs/clapp": "^0.2.0", "@stacksjs/desktop": "0.2.72", "@stacksjs/sanitizer": "0.2.72", "@stacksjs/ts-craft": "^0.0.2", "@stacksjs/ts-i18n": "^0.1.11", "bun-plugin-stx": "0.2.72", "bunfig": "^0.15.6", "stx-router": "0.2.72", "ts-broadcasting": "^0.0.4", "ts-images": "^0.1.8", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-aW6w0epktzFz0Jai9vCctBXEkPcri42jYNrojHyEm0oaRxyEgq9BLn6K5GUljLoJprr6wzfbDHZQp4FCopakaw=="],
108108
109109 "@stacksjs/ts-avif": ["@stacksjs/ts-avif@0.1.0", "", {}, "sha512-ytcta6ZhZeZwXJTcWlTraNLBsqL4imOfruSkJ2PwEp5RjHb4eSoqb21W4u7HLILRcILr7B1nOkIMeQct4Pozbw=="],
110110
@@ -116,6 +116,8 @@
116116
117117 "@stacksjs/ts-css": ["@stacksjs/ts-css@0.1.0", "", { "dependencies": { "bunfig": "^0.15.6" }, "bin": { "ts-css": "./dist/bin/cli.js" } }, "sha512-373WvzZeXdqwi6lRwyfr05r3KOtbo4QXWPhmoGFI6NSa5ZcUEiyYJGL2KsV9mfQNTsBp+0q3wPnj1EQ/1zuieg=="],
118118
119 "@stacksjs/ts-i18n": ["@stacksjs/ts-i18n@0.1.11", "", { "dependencies": { "@stacksjs/clapp": "^0.2.9", "bunfig": "^0.15.6" }, "bin": { "i18n": "./dist/cli.js" } }, "sha512-33FM0gKdxBy6EUsUZLGAMe0D7QUZ4f/BQXRsQIyzkZgs2+juruUTevPuJGCjWSZsgJuiaBfEJn8Oq8ctuo1OWQ=="],
120
119121 "@stacksjs/ts-md": ["@stacksjs/ts-md@0.1.1", "", { "bin": { "md": "./bin/cli.ts" } }, "sha512-kvsSg7S3vHq65fnHIRggTLudN4n1sjkos86xLB62V6PVRa8iosYAmFKVDTGaJk+0MdsIoRwQbJ2vLWVcNQsgGw=="],
120122
121123 "@stacksjs/ts-png": ["@stacksjs/ts-png@0.1.2", "", {}, "sha512-NT9AVCAlZiOMzcBH+OlAAUAbfTzakm/6Ibp5S31JInrpTDd+Qe3arEfatPLuMasFR9tyO+NMAFsF84MT6TK1vA=="],
@@ -204,7 +206,7 @@
204206
205207 "bun-plugin-dtsx": ["bun-plugin-dtsx@0.9.26", "", { "dependencies": { "@stacksjs/dtsx": "0.9.26" } }, "sha512-dOlA+gx3mju+Be0uoZqsuQ3U+GPu08wv7QQwA1k569tw8Bv9GwVWJz0jjQw6tzJi9Rvwfl31MVXu9rHYQXSKow=="],
206208
207 "bun-plugin-stx": ["bun-plugin-stx@0.2.70", "", { "dependencies": { "@stacksjs/stx": "0.2.70", "stx-router": "0.2.70" }, "bin": { "serve": "./dist/serve.js", "stx-serve": "./dist/serve.js" } }, "sha512-7bJ6uzQLWqNM5p9Pgha9fNhVTz0gBT4LJyXEEmkMOIljevp7zKiWBa0r2F1CM0eXqSlUfqgI659mtfkhB9MiSA=="],
209 "bun-plugin-stx": ["bun-plugin-stx@0.2.72", "", { "dependencies": { "@stacksjs/stx": "0.2.72", "stx-router": "0.2.72" }, "bin": { "serve": "./dist/serve.js", "stx-serve": "./dist/serve.js" } }, "sha512-vkvFCmAm+w1YpCCBD5EImLaGFxgJmKZWDdi4mBvO9lxMFXBZiDyGcFxPnWGTdXcw2S085+lEG32BHwCV9kiqmw=="],
208210
209211 "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
210212
@@ -486,13 +488,11 @@
486488
487489 "@stacksjs/bunpress/@stacksjs/stx": ["@stacksjs/stx@0.2.70", "", { "dependencies": { "@cwcss/crosswind": "^0.2.0", "@stacksjs/clapp": "^0.2.0", "@stacksjs/desktop": "0.2.70", "@stacksjs/sanitizer": "0.2.70", "@stacksjs/ts-craft": "^0.0.2", "bun-plugin-stx": "0.2.70", "bunfig": "^0.15.6", "stx-router": "0.2.70", "ts-broadcasting": "^0.0.4", "ts-images": "^0.1.8", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-dPOj5qvaZLQGKd3PlZawH/qL9IiUFUaSIKVpjUFp4/fqeOpdA7QbPC5vWhyYCeVa+tHyQwetBndwwjCYAHPjOw=="],
488490
489 "@stacksjs/stx/bun-plugin-stx": ["bun-plugin-stx@0.2.47", "", { "dependencies": { "@stacksjs/stx": "0.2.47" }, "bin": { "serve": "./dist/serve.js", "stx-serve": "./dist/serve.js" } }, "sha512-CwMluoYHo9LFHuQVqjitTjZmo5rem2VYHimNgcW940LluHTBiVak7ri3zsIRGRDaS5xGIM/2NbJFuFOgu3hyKQ=="],
491 "@stacksjs/stx/stx-router": ["stx-router@0.2.72", "", {}, "sha512-WUr5XaZVWp4JifqqOzU7YhmxIAiEPO8iRFO81VhKaGlF+FHrTPzhh3O0AmkAN+kmHv+IajbJ1UpMIcPTa5nFEg=="],
490492
491493 "@stacksjs/stx/ts-broadcasting": ["ts-broadcasting@0.0.4", "", { "bin": { "broadcast": "./dist/bin/cli.js" } }, "sha512-dnPtNM6mTCCnJcf8S9ffnWMOLCr5LRpxz87haYw7AtqyqCkM5B3kT6tXr1jJnxjDlWPfSfhpY+n6Y6N2l9CGPQ=="],
492494
493 "bun-plugin-stx/@stacksjs/stx": ["@stacksjs/stx@0.2.70", "", { "dependencies": { "@cwcss/crosswind": "^0.2.0", "@stacksjs/clapp": "^0.2.0", "@stacksjs/desktop": "0.2.70", "@stacksjs/sanitizer": "0.2.70", "@stacksjs/ts-craft": "^0.0.2", "bun-plugin-stx": "0.2.70", "bunfig": "^0.15.6", "stx-router": "0.2.70", "ts-broadcasting": "^0.0.4", "ts-images": "^0.1.8", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-dPOj5qvaZLQGKd3PlZawH/qL9IiUFUaSIKVpjUFp4/fqeOpdA7QbPC5vWhyYCeVa+tHyQwetBndwwjCYAHPjOw=="],
494
495 "bun-plugin-stx/stx-router": ["stx-router@0.2.70", "", {}, "sha512-b0tF8pmqVsgC0I0epav9NURHJk48vVe62QfQFK0jQiVBnAYTJREgjRK9gdrCxIIX/DAmoyI39zsYoKzv/tyiAQ=="],
495 "bun-plugin-stx/stx-router": ["stx-router@0.2.72", "", {}, "sha512-WUr5XaZVWp4JifqqOzU7YhmxIAiEPO8iRFO81VhKaGlF+FHrTPzhh3O0AmkAN+kmHv+IajbJ1UpMIcPTa5nFEg=="],
496496
497497 "glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
498498
@@ -512,22 +512,14 @@
512512
513513 "@stacksjs/bunpress/@stacksjs/stx/@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.70", "", {}, "sha512-jRuRn0VyCmlqM9H2yOuChV1dkxBozW+THBAnGcraYzPjf5CD1x/tRz9PGzS8h6PlEUSBfBi2zr+wPEwUKj1GoA=="],
514514
515 "@stacksjs/bunpress/@stacksjs/stx/bun-plugin-stx": ["bun-plugin-stx@0.2.70", "", { "dependencies": { "@stacksjs/stx": "0.2.70", "stx-router": "0.2.70" }, "bin": { "serve": "./dist/serve.js", "stx-serve": "./dist/serve.js" } }, "sha512-7bJ6uzQLWqNM5p9Pgha9fNhVTz0gBT4LJyXEEmkMOIljevp7zKiWBa0r2F1CM0eXqSlUfqgI659mtfkhB9MiSA=="],
516
515517 "@stacksjs/bunpress/@stacksjs/stx/stx-router": ["stx-router@0.2.70", "", {}, "sha512-b0tF8pmqVsgC0I0epav9NURHJk48vVe62QfQFK0jQiVBnAYTJREgjRK9gdrCxIIX/DAmoyI39zsYoKzv/tyiAQ=="],
516518
517519 "@stacksjs/bunpress/@stacksjs/stx/ts-broadcasting": ["ts-broadcasting@0.0.4", "", { "bin": { "broadcast": "./dist/bin/cli.js" } }, "sha512-dnPtNM6mTCCnJcf8S9ffnWMOLCr5LRpxz87haYw7AtqyqCkM5B3kT6tXr1jJnxjDlWPfSfhpY+n6Y6N2l9CGPQ=="],
518520
519 "@stacksjs/stx/bun-plugin-stx/@stacksjs/stx": ["@stacksjs/stx@0.2.47", "", { "dependencies": { "@cwcss/crosswind": "^0.2.0", "@stacksjs/clapp": "^0.2.0", "@stacksjs/desktop": "0.2.46", "@stacksjs/sanitizer": "0.2.35", "@stacksjs/ts-craft": "^0.0.2", "bun-plugin-stx": "0.2.47", "bunfig": "^0.15.6", "stx-router": "0.2.47", "ts-broadcasting": "^0.0.4", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-BCfbS1DFHlg3Pq0dC12KvCs0IMf2JW1i0XSv4o5dHArXATb/3R6SZeEaxxbCF5WZz5aq8NmN2qAei57tfIkZrg=="],
520
521 "bun-plugin-stx/@stacksjs/stx/@stacksjs/desktop": ["@stacksjs/desktop@0.2.70", "", { "peerDependencies": { "craft": "*" }, "optionalPeers": ["craft"] }, "sha512-tBwE98HT+bajYzm4oY2NZtXz5+c9DjX6rUVXs0d8vr3Kv/4pof6tx+GTw64Z+lqvdB8wgCISRduDIVZiZjyDWQ=="],
522
523 "bun-plugin-stx/@stacksjs/stx/@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.70", "", {}, "sha512-jRuRn0VyCmlqM9H2yOuChV1dkxBozW+THBAnGcraYzPjf5CD1x/tRz9PGzS8h6PlEUSBfBi2zr+wPEwUKj1GoA=="],
524
525 "bun-plugin-stx/@stacksjs/stx/ts-broadcasting": ["ts-broadcasting@0.0.4", "", { "bin": { "broadcast": "./dist/bin/cli.js" } }, "sha512-dnPtNM6mTCCnJcf8S9ffnWMOLCr5LRpxz87haYw7AtqyqCkM5B3kT6tXr1jJnxjDlWPfSfhpY+n6Y6N2l9CGPQ=="],
526
527521 "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
528522
529523 "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
530
531 "@stacksjs/stx/bun-plugin-stx/@stacksjs/stx/stx-router": ["stx-router@0.2.47", "", {}, "sha512-nsMWqfttuPGY0kabUc4jSbsXY8zMcf+qR89xo6FAFHxz1aQflNvQwedOvUUwKsiUNbTMXcHZIojVCG0OY1X7uQ=="],
532524 }
533525}
components/CleanupPanel.stxmodified+6-6
Changes to components/CleanupPanel.stx
@@ -3,12 +3,12 @@
33 <div class='card' style='grid-column: span 2;'>
44 <div class='card-label'>Space Recoverable</div>
55 <div class='card-value' style='color: #30d158;' id='total-cleanable'>Scanning...</div>
6 <div class='card-detail'><span x-text='cleanCategories.length'></span> cleanable categories found</div>
6 <div class='card-detail'><span>{{ cleanCategories.length }}</span> cleanable categories found</div>
77 </div>
88 <div class='card'>
99 <div class='card-label'>Disk Free</div>
10 <div class='card-value' x-text='diskAvail'></div>
11 <div class='card-detail'><span x-text='diskPercent'></span>% used</div>
10 <div class='card-value'>{{ diskAvail }}</div>
11 <div class='card-detail'><span>{{ diskPercent }}</span>% used</div>
1212 </div>
1313</div>
1414
@@ -50,11 +50,11 @@
5050 <tr :data-clean-id="cat.id" :data-clean-path="cat.path">
5151 <td><input type='checkbox' class='check' :checked="isOn(cat.id)" @click="toggle(cat.id)" /></td>
5252 <td>
53 <div><span style='margin-right: 4px;' x-text='cat.icon'></span><span class='item-name' x-text='cat.name'></span></div>
54 <div class='item-sub' x-text='cat.desc'></div>
53 <div><span style='margin-right: 4px;'>{{ cat.icon }}</span><span class='item-name'>{{ cat.name }}</span></div>
54 <div class='item-sub'>{{ cat.desc }}</div>
5555 </td>
5656 <td class='clean-size' style='font-weight: 600; font-variant-numeric: tabular-nums; color: #6c6c70;'>...</td>
57 <td><div class="item-path" :title="cat.path" x-text="shortPath(cat.path)"></div></td>
57 <td><div class="item-path" :title="cat.path">{{ shortPath(cat.path) }}</div></td>
5858 <td>
5959 <button class='btn btn-danger btn-sm'
6060 :disabled="cleaning[cat.id]"
components/DashboardCards.stxmodified+11-11
Changes to components/DashboardCards.stx
@@ -12,18 +12,18 @@
1212 :stroke-dashoffset='healthDashoffset' />
1313 </svg>
1414 <div class='ring-text'>
15 <span class='ring-score' :style="healthScoreStyle()" x-text='healthScore'></span>
16 <span class='ring-label' x-text='healthLabel'></span>
15 <span class='ring-score' :style="healthScoreStyle()">{{ healthScore }}</span>
16 <span class='ring-label'>{{ healthLabel }}</span>
1717 </div>
1818 </div>
1919 <div style='flex: 1;'>
2020 <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;'>
2121 <span class='statusbar-dot' style='background: '></span>
22 Memory: {{ usedMemGB }} / {{ totalMemGB }} GB (<span x-text="stats ? stats.memPercent : "></span>%)
22 Memory: {{ usedMemGB }} / {{ totalMemGB }} GB (<span>{{ stats ? stats.memPercent : {{ sMemPercent }} }}</span>%)
2323 </div>
2424 <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='stats' x-cloak>
2525 <span class='statusbar-dot' :style="diskDotStyle(stats.dUsedPct)"></span>
26 Disk: <span x-text='stats.diskUsed'></span> / <span x-text='stats.diskTotal'></span> (<span x-text='stats.diskAvail'></span> free)
26 Disk: <span>{{ stats.diskUsed }}</span> / <span>{{ stats.diskTotal }}</span> (<span>{{ stats.diskAvail }}</span> free)
2727 </div>
2828 <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='!stats'>
2929 <span class='statusbar-dot' style='background: #6c6c70'></span>
@@ -31,7 +31,7 @@
3131 </div>
3232 <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='stats' x-cloak>
3333 <span class='statusbar-dot' :style="startupDotStyle(stats.enabledStartup)"></span>
34 <span x-text="stats.enabledStartup + ' startup items active'"></span>
34 <span>{{ stats.enabledStartup + ' startup items active' }}</span>
3535 </div>
3636 <div style='display: flex; align-items: center; gap: 6px; font-size: 12px;'>
3737 <span class='statusbar-dot' style='background: #30d158'></span>
@@ -43,7 +43,7 @@
4343 <div class='card'>
4444 <div class='card-label'>CPU</div>
4545 <div class='card-value' style='font-size: 16px;'>{{ cpuLabel }}</div>
46 <div class='card-detail'>{{ cpuCores }} cores · <span x-text="stats ? stats.cpuAvgPercent + '% avg load' : '...'"></span></div>
46 <div class='card-detail'>{{ cpuCores }} cores · <span>{{ stats ? stats.cpuAvgPercent + '% avg load' : '...' }}</span></div>
4747 </div>
4848</div>
4949
@@ -58,11 +58,11 @@
5858 </div>
5959 <div class='card' x-show='stats' x-cloak>
6060 <div class='card-label'>Disk</div>
61 <div class='card-value'><span x-text='stats.diskUsed'></span> <span style='font-size: 14px; color: #6c6c70;'>/ <span x-text='stats.diskTotal'></span></span></div>
61 <div class='card-value'><span>{{ stats.diskUsed }}</span> <span style='font-size: 14px; color: #6c6c70;'>/ <span>{{ stats.diskTotal }}</span></span></div>
6262 <div class='progress'>
6363 <div class='progress-fill' :style="diskProgressStyle(stats.dUsedPct)"></div>
6464 </div>
65 <div class='card-detail'><span x-text='stats.diskAvail'></span> available</div>
65 <div class='card-detail'><span>{{ stats.diskAvail }}</span> available</div>
6666 </div>
6767 <div class='card' x-show='!stats'>
6868 <div class='card-label'>Disk</div>
@@ -70,12 +70,12 @@
7070 </div>
7171 <div class='card'>
7272 <div class='card-label'>Startup Items</div>
73 <div class='card-value' style='color: #ff9f0a;' x-text="stats ? stats.enabledStartup : '...'"></div>
74 <div class='card-detail'><span x-text="stats ? stats.disabledStartup + ' disabled · ' + stats.totalStartup + ' total' : 'loading...'"></span></div>
73 <div class='card-value' style='color: #ff9f0a;'>{{ stats ? stats.enabledStartup : '...' }}</div>
74 <div class='card-detail'><span>{{ stats ? stats.disabledStartup + ' disabled · ' + stats.totalStartup + ' total' : 'loading...' }}</span></div>
7575 </div>
7676 <div class='card'>
7777 <div class='card-label'>Extensions</div>
78 <div class='card-value' style='color: #bf5af2;' x-text="stats ? stats.extensions : '...'"></div>
78 <div class='card-value' style='color: #bf5af2;'>{{ stats ? stats.extensions : '...' }}</div>
7979 <div class='card-detail'>browser extensions</div>
8080 </div>
8181</div>
components/DiskPanel.stxmodified+11-11
Changes to components/DiskPanel.stx
@@ -60,8 +60,8 @@
6060 @mouseover="hovered = item"
6161 @mouseleave="hovered = null">
6262 <span class="folder-dot" :style="'background:' + item.color"></span>
63 <span class="folder-name" x-text="item.name"></span>
64 <span class="folder-size" x-text="item.formattedSize"></span>
63 <span class="folder-name">{{ item.name }}</span>
64 <span class="folder-size">{{ item.formattedSize }}</span>
6565 <div class="folder-bar-track">
6666 <div class="folder-bar-fill" :style="'width:' + item.barPct + '%;background:' + item.color"></div>
6767 </div>
@@ -104,23 +104,23 @@
104104 <template x-if="hovered">
105105 <div class="info-card">
106106 <div class="info-icon-row">
107 <div class="info-type-icon" :style="'background:' + hovered.color + '20;color:' + hovered.color" x-text="hovered.isDir ? 'Dir' : 'File'"></div>
107 <div class="info-type-icon" :style="'background:' + hovered.color + '20;color:' + hovered.color">{{ hovered.isDir ? 'Dir' : 'File' }}</div>
108108 <div>
109 <div class="info-type-name" x-text="hovered.name"></div>
110 <div class="info-type-kind" x-text="(hovered.isDir ? 'Folder' : 'File') + ' · Level ' + hovered.depth"></div>
109 <div class="info-type-name">{{ hovered.name }}</div>
110 <div class="info-type-kind">{{ (hovered.isDir ? 'Folder' : 'File') + ' · Level ' + hovered.depth }}</div>
111111 </div>
112112 </div>
113 <div class="info-row"><span class="info-label">Size</span><span class="info-value" x-text="hovered.formattedSize"></span></div>
114 <div class="info-row"><span class="info-label">% of View</span><span class="info-value" x-text="hovered.percent + '%'"></span></div>
113 <div class="info-row"><span class="info-label">Size</span><span class="info-value">{{ hovered.formattedSize }}</span></div>
114 <div class="info-row"><span class="info-label">% of View</span><span class="info-value">{{ hovered.percent + '%' }}</span></div>
115115 <template x-if="hovered.isDir">
116 <div class="info-row"><span class="info-label">Items</span><span class="info-value" x-text="hovered.childCount"></span></div>
116 <div class="info-row"><span class="info-label">Items</span><span class="info-value">{{ hovered.childCount }}</span></div>
117117 </template>
118 <div class="info-row" style="border-bottom:none"><span class="info-label">Depth</span><span class="info-value" x-text="'Ring ' + hovered.depth"></span></div>
119 <div class="info-path" x-text="hovered.fullPath"></div>
118 <div class="info-row" style="border-bottom:none"><span class="info-label">Depth</span><span class="info-value">{{ 'Ring ' + hovered.depth }}</span></div>
119 <div class="info-path">{{ hovered.fullPath }}</div>
120120 <div class="info-bar">
121121 <div class="info-bar-label">Proportion</div>
122122 <div class="info-bar-track"><div class="info-bar-fill" :style="'width:' + hovered.percent + '%;background:' + hovered.color"></div></div>
123 <div class="info-bar-text" x-text="hovered.formattedSize + ' of ' + defaultSize"></div>
123 <div class="info-bar-text">{{ hovered.formattedSize + ' of ' + defaultSize }}</div>
124124 </div>
125125 <template x-if="hovered.isDir && hovered.childCount > 0">
126126 <div class="info-drill">Click segment to drill down</div>
components/ExtensionsPanel.stxmodified+10-10
Changes to components/ExtensionsPanel.stx
@@ -2,7 +2,7 @@
22<div class='card-row'>
33 <div class='card'>
44 <div class='card-label'>Total Extensions</div>
5 <div class='card-value' style='color: #bf5af2;' x-text='browserExtensions.length'></div>
5 <div class='card-value' style='color: #bf5af2;'>{{ browserExtensions.length }}</div>
66 <div class='card-detail'>Across all browsers</div>
77 </div>
88 <div class='card'>
@@ -12,12 +12,12 @@
1212 </div>
1313 <div class='card'>
1414 <div class='card-label'>Chrome</div>
15 <div class='card-value' x-text="browserExtensions.filter(function(e){ return e.browser === 'Chrome'; }).length"></div>
15 <div class='card-value'>{{ browserExtensions.filter(function(e){ return e.browser === 'Chrome'; }).length }}</div>
1616 <div class='card-detail'>extensions</div>
1717 </div>
1818 <div class='card'>
1919 <div class='card-label'>Firefox</div>
20 <div class='card-value' x-text="browserExtensions.filter(function(e){ return e.browser === 'Firefox'; }).length"></div>
20 <div class='card-value'>{{ browserExtensions.filter(function(e){ return e.browser === 'Firefox'; }).length }}</div>
2121 <div class='card-detail'>extensions</div>
2222 </div>
2323</div>
@@ -48,15 +48,15 @@
4848 <tr>
4949 <td><input type='checkbox' class='check' :checked="isOn(ext.id)" @click="toggle(ext.id)" /></td>
5050 <td>
51 <div class='item-name'><span x-text='ext.browserIcon'></span> <span x-text='ext.name'></span></div>
52 <div class='item-sub' x-show='ext.description' x-text='ext.description'></div>
51 <div class='item-name'><span>{{ ext.browserIcon }}</span> <span>{{ ext.name }}</span></div>
52 <div class='item-sub' x-show='ext.description'>{{ ext.description }}</div>
5353 </td>
54 <td><span class='badge badge-purple' x-text='ext.browser'></span></td>
55 <td class='dim mono' style='font-size: 11px;' x-text='ext.version'></td>
56 <td style='font-size: 11px;' x-text='ext.sizeStr'></td>
54 <td><span class='badge badge-purple'>{{ ext.browser }}</span></td>
55 <td class='dim mono' style='font-size: 11px;'>{{ ext.version }}</td>
56 <td style='font-size: 11px;'>{{ ext.sizeStr }}</td>
5757 <td>
58 <span class='badge badge-red' x-show="(ext.permissions + ext.hostPermissions) > 5" x-text="(ext.permissions + ext.hostPermissions) + ' perms'"></span>
59 <span class='badge badge-orange' x-show="(ext.permissions + ext.hostPermissions) > 0 && (ext.permissions + ext.hostPermissions) <= 5" x-text="(ext.permissions + ext.hostPermissions) + ' perms'"></span>
58 <span class='badge badge-red' x-show="(ext.permissions + ext.hostPermissions) > 5">{{ (ext.permissions + ext.hostPermissions) + ' perms' }}</span>
59 <span class='badge badge-orange' x-show="(ext.permissions + ext.hostPermissions) > 0 && (ext.permissions + ext.hostPermissions) <= 5">{{ (ext.permissions + ext.hostPermissions) + ' perms' }}</span>
6060 <span class='badge badge-gray' x-show="(ext.permissions + ext.hostPermissions) === 0">None</span>
6161 </td>
6262 <td>
components/ProcessesPanel.stxmodified+13-14
Changes to components/ProcessesPanel.stx
@@ -2,23 +2,23 @@
22<div class='card-row'>
33 <div class='card'>
44 <div class='card-label'>Processes</div>
5 <div class='card-value' style='color: #ff453a;' x-text='processes.length'></div>
5 <div class='card-value' style='color: #ff453a;'>{{ processes.length }}</div>
66 <div class='card-detail'>Above threshold</div>
77 </div>
88 <div class='card'>
99 <div class='card-label'>Total CPU</div>
10 <div class='card-value' x-text="totalCPU.toFixed(0) + '%'"></div>
10 <div class='card-value'>{{ totalCPU.toFixed(0) + '%' }}</div>
1111 <div class='card-detail'>All processes combined</div>
1212 </div>
1313 <div class='card'>
1414 <div class='card-label'>Process Memory</div>
15 <div class='card-value' x-text="(totalMemUsed / 1000).toFixed(1) + ' GB'"></div>
16 <div class='card-detail' x-text="processes.length + ' processes'"></div>
15 <div class='card-value'>{{ (totalMemUsed / 1000).toFixed(1) + ' GB' }}</div>
16 <div class='card-detail'>{{ processes.length + ' processes' }}</div>
1717 </div>
1818 <div class='card'>
1919 <div class='card-label'>System</div>
20 <div class='card-value' x-text='processes.filter(p => p.isSystem).length'></div>
21 <div class='card-detail' x-text="'vs ' + processes.filter(p => !p.isSystem).length + ' user'"></div>
20 <div class='card-value'>{{ processes.filter(p => p.isSystem).length }}</div>
21 <div class='card-detail'>{{ 'vs ' + processes.filter(p => !p.isSystem).length + ' user' }}</div>
2222 </div>
2323</div>
2424
@@ -29,7 +29,7 @@
2929 <span class='tbl-count'>sorted by CPU</span>
3030 <span class='live-indicator' :class="wsConnected ? 'connected' : 'disconnected'">
3131 <span class='live-dot'></span>
32 <span x-text="wsConnected ? 'Live' : 'Reconnecting'"></span>
32 <span>{{ wsConnected ? 'Live' : 'Reconnecting' }}</span>
3333 </span>
3434 </div>
3535 <!-- Bulk kill is hidden until it's wired to /api/kill-process for each
@@ -61,24 +61,23 @@
6161 @click="toggle(p.id)" />
6262 </td>
6363 <td>
64 <div class="item-name" x-text="p.name"></div>
65 <div class="item-path" :title="p.fullCommand" x-text="p.fullCommand"></div>
64 <div class="item-name">{{ p.name }}</div>
65 <div class="item-path" :title="p.fullCommand">{{ p.fullCommand }}</div>
6666 </td>
67 <td class="dim mono" style="font-size: 11px;" x-text="p.pid"></td>
67 <td class="dim mono" style="font-size: 11px;">{{ p.pid }}</td>
6868 <td>
6969 <div class="cpu-bar">
7070 <span
71 :style="'font-size:11px;font-weight:500;min-width:36px;' + (p.cpu > 50 ? 'color:#ff453a;' : p.cpu > 20 ? 'color:#ff9f0a;' : '')"
72 x-text="p.cpu.toFixed(1) + '%'"></span>
71 :style="'font-size:11px;font-weight:500;min-width:36px;' + (p.cpu > 50 ? 'color:#ff453a;' : p.cpu > 20 ? 'color:#ff9f0a;' : '')">{{ p.cpu.toFixed(1) + '%' }}</span>
7372 <div class="cpu-track">
7473 <div class="cpu-fill"
7574 :style="'width:' + Math.min(100, p.cpu) + '%;background:' + (p.cpu > 50 ? '#ff453a' : p.cpu > 20 ? '#ff9f0a' : '#30d158') + ';'"></div>
7675 </div>
7776 </div>
7877 </td>
79 <td style="font-size: 11px;" x-text="p.memMB + ' MB'"></td>
78 <td style="font-size: 11px;">{{ p.memMB + ' MB' }}</td>
8079 <td>
81 <span :class="'badge ' + (p.isSystem ? 'badge-orange' : 'badge-green')" x-text="p.user"></span>
80 <span :class="'badge ' + (p.isSystem ? 'badge-orange' : 'badge-green')">{{ p.user }}</span>
8281 </td>
8382 <td>
8483 <template x-if="p.isSystem">
components/StartupPanel.stxmodified+8-8
Changes to components/StartupPanel.stx
@@ -2,29 +2,29 @@
22<div class='card-row'>
33 <div class='card'>
44 <div class='card-label'>Active</div>
5 <div class='card-value' style='color: #ff9f0a;' x-text='enabledStartup.length'></div>
5 <div class='card-value' style='color: #ff9f0a;'>{{ enabledStartup.length }}</div>
66 <div class='card-detail'>Running at startup</div>
77 </div>
88 <div class='card'>
99 <div class='card-label'>Disabled</div>
10 <div class='card-value dim' x-text='disabledStartup.length'></div>
10 <div class='card-value dim'>{{ disabledStartup.length }}</div>
1111 <div class='card-detail'>Not running</div>
1212 </div>
1313 <div class='card'>
1414 <div class='card-label'>User Agents</div>
15 <div class='card-value' x-text="startupItems.filter(function(i){ return i.scope === 'user'; }).length"></div>
15 <div class='card-value'>{{ startupItems.filter(function(i){ return i.scope === 'user'; }).length }}</div>
1616 <div class='card-detail'>~/Library/LaunchAgents</div>
1717 </div>
1818 <div class='card'>
1919 <div class='card-label'>System Daemons</div>
20 <div class='card-value' x-text="startupItems.filter(function(i){ return i.type === 'daemon'; }).length"></div>
20 <div class='card-value'>{{ startupItems.filter(function(i){ return i.type === 'daemon'; }).length }}</div>
2121 <div class='card-detail'>/Library/LaunchDaemons</div>
2222 </div>
2323</div>
2424
2525<div class='tabs'>
26 <button class='tab' :class="{ active: startupFilter === 'all' }" @click="setFilter('all')">All (<span x-text='startupItems.length'></span>)</button>
27 <button class='tab' :class="{ active: startupFilter === 'enabled' }" @click="setFilter('enabled')">Enabled (<span x-text='enabledStartup.length'></span>)</button>
26 <button class='tab' :class="{ active: startupFilter === 'all' }" @click="setFilter('all')">All (<span>{{ startupItems.length }}</span>)</button>
27 <button class='tab' :class="{ active: startupFilter === 'enabled' }" @click="setFilter('enabled')">Enabled (<span>{{ enabledStartup.length }}</span>)</button>
2828 <button class='tab' :class="{ active: startupFilter === 'vendor' }" @click="setFilter('vendor')">Third-party</button>
2929 <button class='tab' :class="{ active: startupFilter === 'system' }" @click="setFilter('system')">Apple</button>
3030</div>
@@ -54,8 +54,8 @@
5454 <tr x-show="!isRemoved(item.id) && rowVisible(item)" :data-item-id="item.id">
5555 <td><input type="checkbox" class="check" :checked="isOn(item.id)" @click="toggle(item.id)" /></td>
5656 <td>
57 <div><span style='margin-right: 4px;' x-text='item.icon'></span><span class='item-name' x-text='item.name'></span></div>
58 <div class='item-sub' x-text='item.vendor'></div>
57 <div><span style='margin-right: 4px;'>{{ item.icon }}</span><span class='item-name'>{{ item.name }}</span></div>
58 <div class='item-sub'>{{ item.vendor }}</div>
5959 </td>
6060 <td>
6161 <span class='badge badge-green' x-show="item.scope === 'user'">User</span>
components/TopProcesses.stxmodified+5-5
Changes to components/TopProcesses.stx
@@ -33,18 +33,18 @@
3333 </tr>
3434 <template x-for='proc in (stats && stats.processes ? stats.processes.slice(0, 8) : [])' :key='proc.id'>
3535 <tr x-show='!statsLoading'>
36 <td><span class='font-medium' x-text='proc.name'></span></td>
37 <td class='font-mono text-[11px] text-text-dim' x-text='proc.pid'></td>
36 <td><span class='font-medium'>{{ proc.name }}</span></td>
37 <td class='font-mono text-[11px] text-text-dim'>{{ proc.pid }}</td>
3838 <td>
3939 <div class='flex gap-1.5 items-center'>
40 <span class='text-[11px] min-w-[36px]' :class="proc.cpu > 50 ? 'text-apple-red' : proc.cpu > 20 ? 'text-apple-orange' : ''" x-text="proc.cpu.toFixed(1) + '%'"></span>
40 <span class='text-[11px] min-w-[36px]' :class="proc.cpu > 50 ? 'text-apple-red' : proc.cpu > 20 ? 'text-apple-orange' : ''">{{ proc.cpu.toFixed(1) + '%' }}</span>
4141 <div class='overflow-hidden flex-1 h-[3px] max-w-[60px] bg-bg-track rounded-[2px]'>
4242 <div class='h-full rounded-[2px]' :class="proc.cpu > 50 ? 'bg-apple-red' : proc.cpu > 20 ? 'bg-apple-orange' : 'bg-apple-green'" :style="'width: ' + Math.min(100, proc.cpu) + '%;'"></div>
4343 </div>
4444 </div>
4545 </td>
46 <td class='text-[11px]' x-text="proc.memMB + ' MB'"></td>
47 <td class='text-[11px] text-text-dim' x-text='proc.user'></td>
46 <td class='text-[11px]'>{{ proc.memMB + ' MB' }}</td>
47 <td class='text-[11px] text-text-dim'>{{ proc.user }}</td>
4848 </tr>
4949 </template>
5050 </tbody>
package.jsonmodified+2-2
Changes to package.json
@@ -23,9 +23,9 @@
2323 },
2424 "dependencies": {
2525 "@stacksjs/bun-router": "^0.0.15",
26 "@stacksjs/stx": "0.2.48",
26 "@stacksjs/stx": "^0.2.72",
2727 "stx-router": "0.2.48",
28 "bun-plugin-stx": "^0.2.47",
28 "bun-plugin-stx": "^0.2.72",
2929 "@system-cleaner/core": "workspace:*",
3030 "@system-cleaner/clean": "workspace:*",
3131 "@system-cleaner/disk": "workspace:*",
pages/cleanup.stxmodified+1-1
Changes to pages/cleanup.stx
@@ -53,7 +53,7 @@ function esc(str) { return escapeHtml(str || '') }
5353<!-- Reactive toast container -->
5454<div class='toast-area'>
5555 @for(let i = 0; i < 5; i++)
56 <div class='toast' x-show='toasts[]' x-text="toasts[] ? (toasts[].type === 'success' ? '✓' : toasts[].type === 'error' ? '✕' : '⚠') + ' ' + toasts[].msg : ''"></div>
56 <div class='toast' x-show='toasts[]'>{{ toasts[{{ i }}] ? (toasts[{{ i }}].type === 'success' ? '✓' : toasts[{{ i }}].type === 'error' ? '✕' : '⚠') + ' ' + toasts[{{ i }}].msg : '' }}</div>
5757 @endfor
5858</div>
5959
pages/index.stxmodified+6-6
Changes to pages/index.stx
@@ -36,7 +36,7 @@ const healthDasharray = String(2 * Math.PI * 40)
3636 <a href='/updates' data-stx-link class='card' style='display: flex; align-items: center; justify-content: space-between; text-decoration: none; color: inherit; border-color: rgba(255,159,10,0.25);'>
3737 <div>
3838 <div class='card-label'>Pending Updates</div>
39 <div class='card-value' style='color: #ff9f0a;' x-text='pendingUpdates'></div>
39 <div class='card-value' style='color: #ff9f0a;'>{{ pendingUpdates }}</div>
4040 <div class='card-detail'>System, Homebrew, and app updates available</div>
4141 </div>
4242 <span style='font-size: 13px; color: #0a84ff;'>View →</span>
@@ -70,18 +70,18 @@ const healthDasharray = String(2 * Math.PI * 40)
7070 </tr>
7171 <template x-for='proc in (stats && stats.processes ? stats.processes.slice(0, 8) : [])' :key='proc.id'>
7272 <tr x-show='!statsLoading'>
73 <td><span class='font-medium' x-text='proc.name'></span></td>
74 <td class='font-mono text-[11px] text-text-dim' x-text='proc.pid'></td>
73 <td><span class='font-medium'>{{ proc.name }}</span></td>
74 <td class='font-mono text-[11px] text-text-dim'>{{ proc.pid }}</td>
7575 <td>
7676 <div class='flex gap-1.5 items-center'>
77 <span class='text-[11px] min-w-[36px]' :class="cpuTextClass(proc.cpu)" x-text="proc.cpu.toFixed(1) + '%'"></span>
77 <span class='text-[11px] min-w-[36px]' :class="cpuTextClass(proc.cpu)">{{ proc.cpu.toFixed(1) + '%' }}</span>
7878 <div class='overflow-hidden flex-1 h-[3px] max-w-[60px] bg-bg-track rounded-[2px]'>
7979 <div class='h-full rounded-[2px]' :class="cpuBarClass(proc.cpu)" :style="cpuBarStyle(proc.cpu)"></div>
8080 </div>
8181 </div>
8282 </td>
83 <td class='text-[11px]' x-text="proc.memMB + ' MB'"></td>
84 <td class='text-[11px] text-text-dim' x-text='proc.user'></td>
83 <td class='text-[11px]'>{{ proc.memMB + ' MB' }}</td>
84 <td class='text-[11px] text-text-dim'>{{ proc.user }}</td>
8585 </tr>
8686 </template>
8787 </tbody>
pages/processes.stxmodified+1-1
Changes to pages/processes.stx
@@ -86,7 +86,7 @@
8686<!-- Reactive toast container -->
8787<div class='toast-area'>
8888 @for(let i = 0; i < 5; i++)
89 <div class='toast' x-show='toasts[]' x-text="toasts[] ? (toasts[].type === 'success' ? '✓' : toasts[].type === 'error' ? '✕' : '⚠') + ' ' + toasts[].msg : ''"></div>
89 <div class='toast' x-show='toasts[]'>{{ toasts[{{ i }}] ? (toasts[{{ i }}].type === 'success' ? '✓' : toasts[{{ i }}].type === 'error' ? '✕' : '⚠') + ' ' + toasts[{{ i }}].msg : '' }}</div>
9090 @endfor
9191</div>
9292
pages/startup.stxmodified+1-1
Changes to pages/startup.stx
@@ -55,7 +55,7 @@ function esc(str) { return escapeHtml(str || '') }
5555<!-- Reactive toast container -->
5656<div class='toast-area'>
5757 @for(let i = 0; i < 5; i++)
58 <div class='toast' x-show='toasts[]' x-text="toasts[] ? (toasts[].type === 'success' ? '✓' : toasts[].type === 'error' ? '✕' : '⚠') + ' ' + toasts[].msg : ''"></div>
58 <div class='toast' x-show='toasts[]'>{{ toasts[{{ i }}] ? (toasts[{{ i }}].type === 'success' ? '✓' : toasts[{{ i }}].type === 'error' ? '✕' : '⚠') + ' ' + toasts[{{ i }}].msg : '' }}</div>
5959 @endfor
6060</div>
6161
pages/system.stxmodified+11-11
Changes to pages/system.stx
@@ -133,9 +133,9 @@
133133 <div class='main-subtitle'>
134134 <span x-show='loading'>Loading apps...</span>
135135 <span x-show='!loading' x-cloak>
136 <span x-text="apps.length + ' apps'"></span>
136 <span>{{ apps.length + ' apps' }}</span>
137137 <span x-show='sizesLoading'> · sizing...</span>
138 <span x-show='!sizesLoading' x-cloak x-text="' · ' + fmtSize(totalSize) + ' total'"></span>
138 <span x-show='!sizesLoading' x-cloak>{{ ' · ' + fmtSize(totalSize) + ' total' }}</span>
139139 </span>
140140 </div>
141141</div>
@@ -155,8 +155,8 @@
155155 <div x-show='loading' style='padding: 20px; text-align: center; color: #6c6c70; font-size: 12px;'>Scanning apps...</div>
156156 <template x-for='app in filteredApps' :key='app.name'>
157157 <div class='app-row'>
158 <span class='app-row-name' x-text='app.name'></span>
159 <span class='app-row-size' x-text='fmtSize(app.sizeBytes)'></span>
158 <span class='app-row-name'>{{ app.name }}</span>
159 <span class='app-row-size'>{{ fmtSize(app.sizeBytes) }}</span>
160160 </div>
161161 </template>
162162 </div>
@@ -169,25 +169,25 @@
169169 <div>
170170 <div class='disk-card-title'>Macintosh HD</div>
171171 </div>
172 <div class='disk-card-pct' x-text="disk ? disk.fDiskPct + '% full' : '...'"></div>
172 <div class='disk-card-pct'>{{ disk ? disk.fDiskPct + '% full' : '...' }}</div>
173173 </div>
174174 <div class='disk-card-meta'>
175175 <div class='disk-card-row'>Location: <strong>/</strong></div>
176 <div class='disk-card-row'>Available: <strong x-text="disk ? disk.fDiskFree : '...'"></strong></div>
177 <div class='disk-card-row' x-show='disk && disk.diskPurgeable > 0' x-cloak>Purgeable: <strong x-text="disk.fDiskPurgeable"></strong></div>
176 <div class='disk-card-row'>Available: <strong>{{ disk ? disk.fDiskFree : '...' }}</strong></div>
177 <div class='disk-card-row' x-show='disk && disk.diskPurgeable > 0' x-cloak>Purgeable: <strong>{{ disk.fDiskPurgeable }}</strong></div>
178178 </div>
179179 <div class='disk-bar-wrap'>
180 <span class='disk-bar-label' x-text="disk ? disk.fDiskUsed : '...'"></span>
180 <span class='disk-bar-label'>{{ disk ? disk.fDiskUsed : '...' }}</span>
181181 <div class='disk-bar-track'>
182182 <div class='disk-bar-fill' :style="disk ? disk.fDiskBarStyle : 'width: 0%'"></div>
183183 </div>
184 <span class='disk-bar-label' x-text="disk ? disk.fDiskTotal : '...'"></span>
184 <span class='disk-bar-label'>{{ disk ? disk.fDiskTotal : '...' }}</span>
185185 </div>
186186 <div class='disk-card-footer'>
187187 <div class='disk-card-stat-row'>
188188 <div class='disk-card-stat'>Apps: <span x-text="loading ? '...' : fmtSize(totalSize)">...</span></div>
189 <div class='disk-card-stat'>Free: <strong x-text="disk ? disk.fDiskFree : '...'"></strong></div>
190 <div class='disk-card-stat'>Used: <strong x-text="disk ? disk.fDiskUsed : '...'"></strong></div>
189 <div class='disk-card-stat'>Free: <strong>{{ disk ? disk.fDiskFree : '...' }}</strong></div>
190 <div class='disk-card-stat'>Used: <strong>{{ disk ? disk.fDiskUsed : '...' }}</strong></div>
191191 </div>
192192 </div>
193193 </div>
pages/updates.stxmodified+40-40
Changes to pages/updates.stx
@@ -3,7 +3,7 @@
33
44<div class='toast-area'>
55 <template x-for='t in toasts' :key='t.id'>
6 <div class='toast' x-text="(t.type === 'success' ? '\u2713' : t.type === 'error' ? '\u2715' : '\u26A0') + ' ' + t.msg"></div>
6 <div class='toast'>{{ (t.type === 'success' ? '\u2713' : t.type === 'error' ? '\u2715' : '\u26A0') + ' ' + t.msg }}</div>
77 </template>
88</div>
99
@@ -13,7 +13,7 @@
1313 <div class='main-title'>Updates</div>
1414 <div class='main-subtitle'>
1515 <span x-show='loading'>Checking for updates...</span>
16 <span x-show='!loading' x-cloak x-text="totalOutdated() + ' outdated item' + (totalOutdated() !== 1 ? 's' : '') + ' found'"></span>
16 <span x-show='!loading' x-cloak>{{ totalOutdated() + ' outdated item' + (totalOutdated() !== 1 ? 's' : '') + ' found' }}</span>
1717 </div>
1818 </div>
1919 <div x-show='!loading' x-cloak style='display: flex; gap: 6px; flex-shrink: 0;'>
@@ -33,27 +33,27 @@
3333<div class='card-row'>
3434 <div class='card'>
3535 <div class='card-label'>System</div>
36 <div class='card-value' :style="systemOutdatedCount() > 0 ? 'color: #ff9f0a' : 'color: #30d158'" x-text="systemOutdatedCount()"></div>
36 <div class='card-value' :style="systemOutdatedCount() > 0 ? 'color: #ff9f0a' : 'color: #30d158'">{{ systemOutdatedCount() }}</div>
3737 <div class='card-detail'>
38 <span x-show='macosVersion' x-text="'macOS ' + macosVersion"></span>
39 <span x-show='clToolsInfo.version' x-text="(macosVersion ? ' \u00B7 ' : '') + 'CLT ' + clToolsInfo.version"></span>
38 <span x-show='macosVersion'>{{ 'macOS ' + macosVersion }}</span>
39 <span x-show='clToolsInfo.version'>{{ (macosVersion ? ' \u00B7 ' : '') + 'CLT ' + clToolsInfo.version }}</span>
4040 <span x-show='updateScanCached' style='display: block; margin-top: 2px;'>cached scan</span>
4141 </div>
4242 </div>
4343 <div class='card'>
4444 <div class='card-label'>Homebrew</div>
45 <div class='card-value' :style="brewTotal() > 0 ? 'color: #ff9f0a' : 'color: #30d158'" x-text="brewTotal()"></div>
46 <div class='card-detail' x-text="brewFormulae.length + ' formulae \u00B7 ' + brewCasks.length + ' casks'"></div>
45 <div class='card-value' :style="brewTotal() > 0 ? 'color: #ff9f0a' : 'color: #30d158'">{{ brewTotal() }}</div>
46 <div class='card-detail'>{{ brewFormulae.length + ' formulae \u00B7 ' + brewCasks.length + ' casks' }}</div>
4747 </div>
4848 <div class='card'>
4949 <div class='card-label'>Pantry</div>
50 <div class='card-value' :style="pantryOutdated.length > 0 ? 'color: #ff9f0a' : 'color: #30d158'" x-text="pantryOutdated.length"></div>
51 <div class='card-detail' x-text="pantryTrackedCount + ' package' + (pantryTrackedCount !== 1 ? 's' : '') + ' tracked'"></div>
50 <div class='card-value' :style="pantryOutdated.length > 0 ? 'color: #ff9f0a' : 'color: #30d158'">{{ pantryOutdated.length }}</div>
51 <div class='card-detail'>{{ pantryTrackedCount + ' package' + (pantryTrackedCount !== 1 ? 's' : '') + ' tracked' }}</div>
5252 </div>
5353 <div class='card'>
5454 <div class='card-label'>Desktop Apps</div>
55 <div class='card-value' :style="desktopOutdated.length > 0 ? 'color: #ff9f0a' : 'color: #30d158'" x-text="desktopOutdated.length"></div>
56 <div class='card-detail' x-text="desktopApps.length + ' app' + (desktopApps.length !== 1 ? 's' : '') + ' scanned'"></div>
55 <div class='card-value' :style="desktopOutdated.length > 0 ? 'color: #ff9f0a' : 'color: #30d158'">{{ desktopOutdated.length }}</div>
56 <div class='card-detail'>{{ desktopApps.length + ' app' + (desktopApps.length !== 1 ? 's' : '') + ' scanned' }}</div>
5757 </div>
5858</div>
5959
@@ -61,7 +61,7 @@
6161 <div class='tbl-bar'>
6262 <div>
6363 <span class='tbl-title'>macOS &amp; System Updates</span>
64 <span class='tbl-count' x-show='systemOutdatedCount() > 0' x-text="systemOutdatedCount() + ' available'"></span>
64 <span class='tbl-count' x-show='systemOutdatedCount() > 0'>{{ systemOutdatedCount() + ' available' }}</span>
6565 <span class='tbl-count' x-show='systemOutdatedCount() === 0'>up to date</span>
6666 </div>
6767 <div style='display: flex; gap: 6px;'>
@@ -83,14 +83,14 @@
8383 <tbody>
8484 <template x-for='upd in systemUpdates' :key='upd.label'>
8585 <tr>
86 <td><span class='item-name' x-text='upd.title'></span></td>
87 <td><span class='badge' :class="kindBadgeClass(upd.kind)" x-text="kindLabel(upd.kind)"></span></td>
88 <td class='mono' style='font-size: 11px; color: #30d158;' x-text='upd.version'></td>
89 <td class='dim mono' style='font-size: 11px;' x-text='upd.sizeLabel'></td>
86 <td><span class='item-name'>{{ upd.title }}</span></td>
87 <td><span class='badge' :class="kindBadgeClass(upd.kind)">{{ kindLabel(upd.kind) }}</span></td>
88 <td class='mono' style='font-size: 11px; color: #30d158;'>{{ upd.version }}</td>
89 <td class='dim mono' style='font-size: 11px;'>{{ upd.sizeLabel }}</td>
9090 <td>
9191 <span class='badge badge-orange' style='font-size: 9px; margin-right: 4px;' x-show='upd.restartRequired'>Restart</span>
9292 <span class='badge badge-green' style='font-size: 9px;' x-show='upd.recommended'>Recommended</span>
93 <span x-show='upd.kind === "cltools" && clToolsInfo.version' class='dim' style='font-size: 10px; display: block; margin-top: 2px;' x-text="'Installed: ' + clToolsInfo.version"></span>
93 <span x-show='upd.kind === "cltools" && clToolsInfo.version' class='dim' style='font-size: 10px; display: block; margin-top: 2px;'>{{ 'Installed: ' + clToolsInfo.version }}</span>
9494 </td>
9595 <td>
9696 <button class='btn btn-sm' @click='openSystemSettings()'>Install</button>
@@ -102,7 +102,7 @@
102102 </div>
103103 <div x-show='systemOutdatedCount() === 0' class='empty-state' style='padding: 20px;'>
104104 <div style='font-size: 13px; color: #30d158; margin-bottom: 4px;'>&#10004; No pending macOS or system updates</div>
105 <div class='dim' style='font-size: 11px;' x-show='clToolsInfo.version' x-text="'Command Line Tools ' + clToolsInfo.version + ' installed'"></div>
105 <div class='dim' style='font-size: 11px;' x-show='clToolsInfo.version'>{{ 'Command Line Tools ' + clToolsInfo.version + ' installed' }}</div>
106106 <div class='dim' style='font-size: 11px; margin-top: 4px;' x-show='updateScanCached'>Use Deep Scan for a fresh Apple catalog check</div>
107107 </div>
108108</div>
@@ -111,8 +111,8 @@
111111 <div class='tbl-bar'>
112112 <div>
113113 <span class='tbl-title'>Homebrew</span>
114 <span class='tbl-count' x-text="brewTotal() + ' outdated'"></span>
115 <span class='tbl-count' x-show='selected.length > 0' x-text="' \u00B7 ' + selected.length + ' selected'"></span>
114 <span class='tbl-count'>{{ brewTotal() + ' outdated' }}</span>
115 <span class='tbl-count' x-show='selected.length > 0'>{{ ' \u00B7 ' + selected.length + ' selected' }}</span>
116116 </div>
117117 <div style='display: flex; gap: 6px;'>
118118 <button class='btn btn-sm' x-show='selected.length > 0' @click='doUpdateSelected()'>
@@ -136,10 +136,10 @@
136136 <template x-for='pkg in brewCasks' :key="'cask:' + pkg.name">
137137 <tr x-show="!isUpdated('cask:' + pkg.name)">
138138 <td><input type='checkbox' class='check' :checked="isOn('cask:' + pkg.name)" @click="toggle('cask:' + pkg.name)" /></td>
139 <td><span class='item-name' x-text='pkg.name'></span></td>
139 <td><span class='item-name'>{{ pkg.name }}</span></td>
140140 <td><span class='badge badge-purple'>Cask</span></td>
141 <td class='dim mono' style='font-size: 11px;' x-text='pkg.current'></td>
142 <td><span class='mono' style='font-size: 11px; color: #30d158;' x-text='pkg.latest'></span></td>
141 <td class='dim mono' style='font-size: 11px;'>{{ pkg.current }}</td>
142 <td><span class='mono' style='font-size: 11px; color: #30d158;'>{{ pkg.latest }}</span></td>
143143 <td class='action-cell'>
144144 <template x-if="isUpdating('cask:' + pkg.name)">
145145 <span class='updating-label'>Updating…</span>
@@ -154,12 +154,12 @@
154154 <tr x-show='!isUpdated(pkg.name)'>
155155 <td><input type='checkbox' class='check' :checked='isOn(pkg.name)' @click='toggle(pkg.name)' /></td>
156156 <td>
157 <span class='item-name' x-text='pkg.name'></span>
157 <span class='item-name'>{{ pkg.name }}</span>
158158 <span class='badge badge-gray' style='margin-left: 4px;' x-show='pkg.pinned'>pinned</span>
159159 </td>
160160 <td><span class='badge badge-green'>Formula</span></td>
161 <td class='dim mono' style='font-size: 11px;' x-text='pkg.current'></td>
162 <td><span class='mono' style='font-size: 11px; color: #30d158;' x-text='pkg.latest'></span></td>
161 <td class='dim mono' style='font-size: 11px;'>{{ pkg.current }}</td>
162 <td><span class='mono' style='font-size: 11px; color: #30d158;'>{{ pkg.latest }}</span></td>
163163 <td>
164164 <template x-if='pkg.pinned'>
165165 <span class='dim' style='font-size: 10px;'>Pinned</span>
@@ -185,7 +185,7 @@
185185 <div class='tbl-bar'>
186186 <div>
187187 <span class='tbl-title'>Pantry</span>
188 <span class='tbl-count' x-show='pantryOutdated.length > 0' x-text="pantryOutdated.length + ' outdated'"></span>
188 <span class='tbl-count' x-show='pantryOutdated.length > 0'>{{ pantryOutdated.length + ' outdated' }}</span>
189189 <span class='tbl-count' x-show='pantryOutdated.length === 0'>all up to date</span>
190190 </div>
191191 </div>
@@ -203,10 +203,10 @@
203203 <tbody>
204204 <template x-for='pkg in pantryOutdated' :key='pkg.name'>
205205 <tr x-show="!isUpdated('pantry:' + pkg.name)">
206 <td><span class='item-name' x-text='pkg.name'></span></td>
207 <td class='dim mono' style='font-size: 11px;' x-text='pkg.current'></td>
208 <td class='dim mono' style='font-size: 11px;' x-text='pkg.wanted'></td>
209 <td><span class='mono' style='font-size: 11px; color: #30d158;' x-text='pkg.latest'></span></td>
206 <td><span class='item-name'>{{ pkg.name }}</span></td>
207 <td class='dim mono' style='font-size: 11px;'>{{ pkg.current }}</td>
208 <td class='dim mono' style='font-size: 11px;'>{{ pkg.wanted }}</td>
209 <td><span class='mono' style='font-size: 11px; color: #30d158;'>{{ pkg.latest }}</span></td>
210210 <td class='action-cell'>
211211 <template x-if="isUpdating('pantry:' + pkg.name)">
212212 <span class='updating-label'>Updating…</span>
@@ -223,7 +223,7 @@
223223 <div x-show='pantryOutdated.length === 0 && pantryPackages.length > 0' style='padding: 12px 16px;'>
224224 <div style='display: flex; flex-wrap: wrap; gap: 6px;'>
225225 <template x-for='pkg in pantryPackages' :key='pkg'>
226 <span class='badge badge-green' x-text='pkg'></span>
226 <span class='badge badge-green'>{{ pkg }}</span>
227227 </template>
228228 </div>
229229 </div>
@@ -234,12 +234,12 @@
234234 <div class='tbl-bar'>
235235 <div>
236236 <span class='tbl-title'>Desktop Apps</span>
237 <span class='tbl-count' x-show='desktopOutdated.length > 0' x-text="desktopOutdated.length + ' update' + (desktopOutdated.length !== 1 ? 's' : '') + ' available'"></span>
238 <span class='tbl-count' x-show='desktopOutdated.length === 0' x-text="desktopApps.length + ' apps'"></span>
237 <span class='tbl-count' x-show='desktopOutdated.length > 0'>{{ desktopOutdated.length + ' update' + (desktopOutdated.length !== 1 ? 's' : '') + ' available' }}</span>
238 <span class='tbl-count' x-show='desktopOutdated.length === 0'>{{ desktopApps.length + ' apps' }}</span>
239239 </div>
240240 <div style='display: flex; gap: 4px;'>
241 <button class='btn btn-sm' :class="{ 'btn-active': appFilter === 'all' }" @click="appFilter = 'all'" x-text="'All (' + desktopApps.length + ')'"></button>
242 <button class='btn btn-sm' x-show='desktopOutdated.length > 0' :class="{ 'btn-active': appFilter === 'outdated' }" @click="appFilter = 'outdated'" x-text="'Outdated (' + desktopOutdated.length + ')'"></button>
241 <button class='btn btn-sm' :class="{ 'btn-active': appFilter === 'all' }" @click="appFilter = 'all'">{{ 'All (' + desktopApps.length + ')' }}</button>
242 <button class='btn btn-sm' x-show='desktopOutdated.length > 0' :class="{ 'btn-active': appFilter === 'outdated' }" @click="appFilter = 'outdated'">{{ 'Outdated (' + desktopOutdated.length + ')' }}</button>
243243 <button class='btn btn-sm' :class="{ 'btn-active': appFilter === 'uptodate' }" @click="appFilter = 'uptodate'">Up to date</button>
244244 </div>
245245 </div>
@@ -257,13 +257,13 @@
257257 <template x-for='app in filteredDesktopApps()' :key='app.name'>
258258 <tr x-show="!isUpdated('app:' + app.name)" :style="app.updateAvailable ? '' : 'opacity: 0.7;'">
259259 <td>
260 <span class='item-name' x-text='app.name'></span>
260 <span class='item-name'>{{ app.name }}</span>
261261 <span class='badge badge-gray' style='margin-left: 4px; font-size: 9px;' x-show='app.autoUpdates'>auto-updates</span>
262262 </td>
263 <td class='dim mono' style='font-size: 11px;' x-text='app.version'></td>
263 <td class='dim mono' style='font-size: 11px;'>{{ app.version }}</td>
264264 <td>
265 <span x-show='app.latestVersion && app.updateAvailable' class='mono' style='font-size: 11px; color: #30d158;' x-text='app.latestVersion'></span>
266 <span x-show='app.latestVersion && !app.updateAvailable' class='dim mono' style='font-size: 11px;' x-text='app.latestVersion'></span>
265 <span x-show='app.latestVersion && app.updateAvailable' class='mono' style='font-size: 11px; color: #30d158;'>{{ app.latestVersion }}</span>
266 <span x-show='app.latestVersion && !app.updateAvailable' class='dim mono' style='font-size: 11px;'>{{ app.latestVersion }}</span>
267267 <span x-show='!app.latestVersion' class='dim' style='font-size: 10px;'>&mdash;</span>
268268 </td>
269269 <td>