also looking at this
Migrate x-text/:text bindings to {{ }} interpolation (stx 0.2.72)
#12
15 files
+138
-147
bun.lockmodified+12-20
| @@ -6,13 +6,13 @@ | ||
| 6 | 6 | "name": "system-cleaner", |
| 7 | 7 | "dependencies": { |
| 8 | 8 | "@stacksjs/bun-router": "^0.0.15", |
| 9 | "@stacksjs/stx": "0.2.48", | |
| 9 | "@stacksjs/stx": "^0.2.72", | |
| 10 | 10 | "@system-cleaner/clean": "workspace:*", |
| 11 | 11 | "@system-cleaner/core": "workspace:*", |
| 12 | 12 | "@system-cleaner/disk": "workspace:*", |
| 13 | 13 | "@system-cleaner/monitor": "workspace:*", |
| 14 | 14 | "@system-cleaner/uninstall": "workspace:*", |
| 15 | "bun-plugin-stx": "^0.2.47", | |
| 15 | "bun-plugin-stx": "^0.2.72", | |
| 16 | 16 | "stx-router": "0.2.48", |
| 17 | 17 | "ts-broadcasting": "^0.0.5", |
| 18 | 18 | }, |
| @@ -94,7 +94,7 @@ | ||
| 94 | 94 | |
| 95 | 95 | "@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=="], |
| 96 | 96 | |
| 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=="], | |
| 98 | 98 | |
| 99 | 99 | "@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=="], |
| 100 | 100 | |
| @@ -102,9 +102,9 @@ | ||
| 102 | 102 | |
| 103 | 103 | "@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=="], |
| 104 | 104 | |
| 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=="], | |
| 106 | 106 | |
| 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=="], | |
| 108 | 108 | |
| 109 | 109 | "@stacksjs/ts-avif": ["@stacksjs/ts-avif@0.1.0", "", {}, "sha512-ytcta6ZhZeZwXJTcWlTraNLBsqL4imOfruSkJ2PwEp5RjHb4eSoqb21W4u7HLILRcILr7B1nOkIMeQct4Pozbw=="], |
| 110 | 110 | |
| @@ -116,6 +116,8 @@ | ||
| 116 | 116 | |
| 117 | 117 | "@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=="], |
| 118 | 118 | |
| 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 | ||
| 119 | 121 | "@stacksjs/ts-md": ["@stacksjs/ts-md@0.1.1", "", { "bin": { "md": "./bin/cli.ts" } }, "sha512-kvsSg7S3vHq65fnHIRggTLudN4n1sjkos86xLB62V6PVRa8iosYAmFKVDTGaJk+0MdsIoRwQbJ2vLWVcNQsgGw=="], |
| 120 | 122 | |
| 121 | 123 | "@stacksjs/ts-png": ["@stacksjs/ts-png@0.1.2", "", {}, "sha512-NT9AVCAlZiOMzcBH+OlAAUAbfTzakm/6Ibp5S31JInrpTDd+Qe3arEfatPLuMasFR9tyO+NMAFsF84MT6TK1vA=="], |
| @@ -204,7 +206,7 @@ | ||
| 204 | 206 | |
| 205 | 207 | "bun-plugin-dtsx": ["bun-plugin-dtsx@0.9.26", "", { "dependencies": { "@stacksjs/dtsx": "0.9.26" } }, "sha512-dOlA+gx3mju+Be0uoZqsuQ3U+GPu08wv7QQwA1k569tw8Bv9GwVWJz0jjQw6tzJi9Rvwfl31MVXu9rHYQXSKow=="], |
| 206 | 208 | |
| 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=="], | |
| 208 | 210 | |
| 209 | 211 | "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], |
| 210 | 212 | |
| @@ -486,13 +488,11 @@ | ||
| 486 | 488 | |
| 487 | 489 | "@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=="], |
| 488 | 490 | |
| 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=="], | |
| 490 | 492 | |
| 491 | 493 | "@stacksjs/stx/ts-broadcasting": ["ts-broadcasting@0.0.4", "", { "bin": { "broadcast": "./dist/bin/cli.js" } }, "sha512-dnPtNM6mTCCnJcf8S9ffnWMOLCr5LRpxz87haYw7AtqyqCkM5B3kT6tXr1jJnxjDlWPfSfhpY+n6Y6N2l9CGPQ=="], |
| 492 | 494 | |
| 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=="], | |
| 496 | 496 | |
| 497 | 497 | "glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], |
| 498 | 498 | |
| @@ -512,22 +512,14 @@ | ||
| 512 | 512 | |
| 513 | 513 | "@stacksjs/bunpress/@stacksjs/stx/@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.70", "", {}, "sha512-jRuRn0VyCmlqM9H2yOuChV1dkxBozW+THBAnGcraYzPjf5CD1x/tRz9PGzS8h6PlEUSBfBi2zr+wPEwUKj1GoA=="], |
| 514 | 514 | |
| 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 | ||
| 515 | 517 | "@stacksjs/bunpress/@stacksjs/stx/stx-router": ["stx-router@0.2.70", "", {}, "sha512-b0tF8pmqVsgC0I0epav9NURHJk48vVe62QfQFK0jQiVBnAYTJREgjRK9gdrCxIIX/DAmoyI39zsYoKzv/tyiAQ=="], |
| 516 | 518 | |
| 517 | 519 | "@stacksjs/bunpress/@stacksjs/stx/ts-broadcasting": ["ts-broadcasting@0.0.4", "", { "bin": { "broadcast": "./dist/bin/cli.js" } }, "sha512-dnPtNM6mTCCnJcf8S9ffnWMOLCr5LRpxz87haYw7AtqyqCkM5B3kT6tXr1jJnxjDlWPfSfhpY+n6Y6N2l9CGPQ=="], |
| 518 | 520 | |
| 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 | ||
| 527 | 521 | "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], |
| 528 | 522 | |
| 529 | 523 | "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=="], | |
| 532 | 524 | } |
| 533 | 525 | } |
| @@ -3,12 +3,12 @@ | ||
| 3 | 3 | <div class='card' style='grid-column: span 2;'> |
| 4 | 4 | <div class='card-label'>Space Recoverable</div> |
| 5 | 5 | <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> | |
| 7 | 7 | </div> |
| 8 | 8 | <div class='card'> |
| 9 | 9 | <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> | |
| 12 | 12 | </div> |
| 13 | 13 | </div> |
| 14 | 14 | |
| @@ -50,11 +50,11 @@ | ||
| 50 | 50 | <tr :data-clean-id="cat.id" :data-clean-path="cat.path"> |
| 51 | 51 | <td><input type='checkbox' class='check' :checked="isOn(cat.id)" @click="toggle(cat.id)" /></td> |
| 52 | 52 | <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> | |
| 55 | 55 | </td> |
| 56 | 56 | <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> | |
| 58 | 58 | <td> |
| 59 | 59 | <button class='btn btn-danger btn-sm' |
| 60 | 60 | :disabled="cleaning[cat.id]" |
| @@ -12,18 +12,18 @@ | ||
| 12 | 12 | :stroke-dashoffset='healthDashoffset' /> |
| 13 | 13 | </svg> |
| 14 | 14 | <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> | |
| 17 | 17 | </div> |
| 18 | 18 | </div> |
| 19 | 19 | <div style='flex: 1;'> |
| 20 | 20 | <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;'> |
| 21 | 21 | <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>%) | |
| 23 | 23 | </div> |
| 24 | 24 | <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='stats' x-cloak> |
| 25 | 25 | <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) | |
| 27 | 27 | </div> |
| 28 | 28 | <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='!stats'> |
| 29 | 29 | <span class='statusbar-dot' style='background: #6c6c70'></span> |
| @@ -31,7 +31,7 @@ | ||
| 31 | 31 | </div> |
| 32 | 32 | <div style='display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px;' x-show='stats' x-cloak> |
| 33 | 33 | <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> | |
| 35 | 35 | </div> |
| 36 | 36 | <div style='display: flex; align-items: center; gap: 6px; font-size: 12px;'> |
| 37 | 37 | <span class='statusbar-dot' style='background: #30d158'></span> |
| @@ -43,7 +43,7 @@ | ||
| 43 | 43 | <div class='card'> |
| 44 | 44 | <div class='card-label'>CPU</div> |
| 45 | 45 | <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> | |
| 47 | 47 | </div> |
| 48 | 48 | </div> |
| 49 | 49 | |
| @@ -58,11 +58,11 @@ | ||
| 58 | 58 | </div> |
| 59 | 59 | <div class='card' x-show='stats' x-cloak> |
| 60 | 60 | <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> | |
| 62 | 62 | <div class='progress'> |
| 63 | 63 | <div class='progress-fill' :style="diskProgressStyle(stats.dUsedPct)"></div> |
| 64 | 64 | </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> | |
| 66 | 66 | </div> |
| 67 | 67 | <div class='card' x-show='!stats'> |
| 68 | 68 | <div class='card-label'>Disk</div> |
| @@ -70,12 +70,12 @@ | ||
| 70 | 70 | </div> |
| 71 | 71 | <div class='card'> |
| 72 | 72 | <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> | |
| 75 | 75 | </div> |
| 76 | 76 | <div class='card'> |
| 77 | 77 | <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> | |
| 79 | 79 | <div class='card-detail'>browser extensions</div> |
| 80 | 80 | </div> |
| 81 | 81 | </div> |
| @@ -60,8 +60,8 @@ | ||
| 60 | 60 | @mouseover="hovered = item" |
| 61 | 61 | @mouseleave="hovered = null"> |
| 62 | 62 | <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> | |
| 65 | 65 | <div class="folder-bar-track"> |
| 66 | 66 | <div class="folder-bar-fill" :style="'width:' + item.barPct + '%;background:' + item.color"></div> |
| 67 | 67 | </div> |
| @@ -104,23 +104,23 @@ | ||
| 104 | 104 | <template x-if="hovered"> |
| 105 | 105 | <div class="info-card"> |
| 106 | 106 | <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> | |
| 108 | 108 | <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> | |
| 111 | 111 | </div> |
| 112 | 112 | </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> | |
| 115 | 115 | <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> | |
| 117 | 117 | </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> | |
| 120 | 120 | <div class="info-bar"> |
| 121 | 121 | <div class="info-bar-label">Proportion</div> |
| 122 | 122 | <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> | |
| 124 | 124 | </div> |
| 125 | 125 | <template x-if="hovered.isDir && hovered.childCount > 0"> |
| 126 | 126 | <div class="info-drill">Click segment to drill down</div> |
| @@ -2,7 +2,7 @@ | ||
| 2 | 2 | <div class='card-row'> |
| 3 | 3 | <div class='card'> |
| 4 | 4 | <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> | |
| 6 | 6 | <div class='card-detail'>Across all browsers</div> |
| 7 | 7 | </div> |
| 8 | 8 | <div class='card'> |
| @@ -12,12 +12,12 @@ | ||
| 12 | 12 | </div> |
| 13 | 13 | <div class='card'> |
| 14 | 14 | <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> | |
| 16 | 16 | <div class='card-detail'>extensions</div> |
| 17 | 17 | </div> |
| 18 | 18 | <div class='card'> |
| 19 | 19 | <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> | |
| 21 | 21 | <div class='card-detail'>extensions</div> |
| 22 | 22 | </div> |
| 23 | 23 | </div> |
| @@ -48,15 +48,15 @@ | ||
| 48 | 48 | <tr> |
| 49 | 49 | <td><input type='checkbox' class='check' :checked="isOn(ext.id)" @click="toggle(ext.id)" /></td> |
| 50 | 50 | <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> | |
| 53 | 53 | </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> | |
| 57 | 57 | <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> | |
| 60 | 60 | <span class='badge badge-gray' x-show="(ext.permissions + ext.hostPermissions) === 0">None</span> |
| 61 | 61 | </td> |
| 62 | 62 | <td> |
| @@ -2,23 +2,23 @@ | ||
| 2 | 2 | <div class='card-row'> |
| 3 | 3 | <div class='card'> |
| 4 | 4 | <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> | |
| 6 | 6 | <div class='card-detail'>Above threshold</div> |
| 7 | 7 | </div> |
| 8 | 8 | <div class='card'> |
| 9 | 9 | <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> | |
| 11 | 11 | <div class='card-detail'>All processes combined</div> |
| 12 | 12 | </div> |
| 13 | 13 | <div class='card'> |
| 14 | 14 | <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> | |
| 17 | 17 | </div> |
| 18 | 18 | <div class='card'> |
| 19 | 19 | <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> | |
| 22 | 22 | </div> |
| 23 | 23 | </div> |
| 24 | 24 | |
| @@ -29,7 +29,7 @@ | ||
| 29 | 29 | <span class='tbl-count'>sorted by CPU</span> |
| 30 | 30 | <span class='live-indicator' :class="wsConnected ? 'connected' : 'disconnected'"> |
| 31 | 31 | <span class='live-dot'></span> |
| 32 | <span x-text="wsConnected ? 'Live' : 'Reconnecting'"></span> | |
| 32 | <span>{{ wsConnected ? 'Live' : 'Reconnecting' }}</span> | |
| 33 | 33 | </span> |
| 34 | 34 | </div> |
| 35 | 35 | <!-- Bulk kill is hidden until it's wired to /api/kill-process for each |
| @@ -61,24 +61,23 @@ | ||
| 61 | 61 | @click="toggle(p.id)" /> |
| 62 | 62 | </td> |
| 63 | 63 | <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> | |
| 66 | 66 | </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> | |
| 68 | 68 | <td> |
| 69 | 69 | <div class="cpu-bar"> |
| 70 | 70 | <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> | |
| 73 | 72 | <div class="cpu-track"> |
| 74 | 73 | <div class="cpu-fill" |
| 75 | 74 | :style="'width:' + Math.min(100, p.cpu) + '%;background:' + (p.cpu > 50 ? '#ff453a' : p.cpu > 20 ? '#ff9f0a' : '#30d158') + ';'"></div> |
| 76 | 75 | </div> |
| 77 | 76 | </div> |
| 78 | 77 | </td> |
| 79 | <td style="font-size: 11px;" x-text="p.memMB + ' MB'"></td> | |
| 78 | <td style="font-size: 11px;">{{ p.memMB + ' MB' }}</td> | |
| 80 | 79 | <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> | |
| 82 | 81 | </td> |
| 83 | 82 | <td> |
| 84 | 83 | <template x-if="p.isSystem"> |
| @@ -2,29 +2,29 @@ | ||
| 2 | 2 | <div class='card-row'> |
| 3 | 3 | <div class='card'> |
| 4 | 4 | <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> | |
| 6 | 6 | <div class='card-detail'>Running at startup</div> |
| 7 | 7 | </div> |
| 8 | 8 | <div class='card'> |
| 9 | 9 | <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> | |
| 11 | 11 | <div class='card-detail'>Not running</div> |
| 12 | 12 | </div> |
| 13 | 13 | <div class='card'> |
| 14 | 14 | <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> | |
| 16 | 16 | <div class='card-detail'>~/Library/LaunchAgents</div> |
| 17 | 17 | </div> |
| 18 | 18 | <div class='card'> |
| 19 | 19 | <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> | |
| 21 | 21 | <div class='card-detail'>/Library/LaunchDaemons</div> |
| 22 | 22 | </div> |
| 23 | 23 | </div> |
| 24 | 24 | |
| 25 | 25 | <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> | |
| 28 | 28 | <button class='tab' :class="{ active: startupFilter === 'vendor' }" @click="setFilter('vendor')">Third-party</button> |
| 29 | 29 | <button class='tab' :class="{ active: startupFilter === 'system' }" @click="setFilter('system')">Apple</button> |
| 30 | 30 | </div> |
| @@ -54,8 +54,8 @@ | ||
| 54 | 54 | <tr x-show="!isRemoved(item.id) && rowVisible(item)" :data-item-id="item.id"> |
| 55 | 55 | <td><input type="checkbox" class="check" :checked="isOn(item.id)" @click="toggle(item.id)" /></td> |
| 56 | 56 | <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> | |
| 59 | 59 | </td> |
| 60 | 60 | <td> |
| 61 | 61 | <span class='badge badge-green' x-show="item.scope === 'user'">User</span> |
| @@ -33,18 +33,18 @@ | ||
| 33 | 33 | </tr> |
| 34 | 34 | <template x-for='proc in (stats && stats.processes ? stats.processes.slice(0, 8) : [])' :key='proc.id'> |
| 35 | 35 | <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> | |
| 38 | 38 | <td> |
| 39 | 39 | <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> | |
| 41 | 41 | <div class='overflow-hidden flex-1 h-[3px] max-w-[60px] bg-bg-track rounded-[2px]'> |
| 42 | 42 | <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> |
| 43 | 43 | </div> |
| 44 | 44 | </div> |
| 45 | 45 | </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> | |
| 48 | 48 | </tr> |
| 49 | 49 | </template> |
| 50 | 50 | </tbody> |
| @@ -23,9 +23,9 @@ | ||
| 23 | 23 | }, |
| 24 | 24 | "dependencies": { |
| 25 | 25 | "@stacksjs/bun-router": "^0.0.15", |
| 26 | "@stacksjs/stx": "0.2.48", | |
| 26 | "@stacksjs/stx": "^0.2.72", | |
| 27 | 27 | "stx-router": "0.2.48", |
| 28 | "bun-plugin-stx": "^0.2.47", | |
| 28 | "bun-plugin-stx": "^0.2.72", | |
| 29 | 29 | "@system-cleaner/core": "workspace:*", |
| 30 | 30 | "@system-cleaner/clean": "workspace:*", |
| 31 | 31 | "@system-cleaner/disk": "workspace:*", |
| @@ -53,7 +53,7 @@ function esc(str) { return escapeHtml(str || '') } | ||
| 53 | 53 | <!-- Reactive toast container --> |
| 54 | 54 | <div class='toast-area'> |
| 55 | 55 | @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> | |
| 57 | 57 | @endfor |
| 58 | 58 | </div> |
| 59 | 59 | |
| @@ -36,7 +36,7 @@ const healthDasharray = String(2 * Math.PI * 40) | ||
| 36 | 36 | <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);'> |
| 37 | 37 | <div> |
| 38 | 38 | <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> | |
| 40 | 40 | <div class='card-detail'>System, Homebrew, and app updates available</div> |
| 41 | 41 | </div> |
| 42 | 42 | <span style='font-size: 13px; color: #0a84ff;'>View →</span> |
| @@ -70,18 +70,18 @@ const healthDasharray = String(2 * Math.PI * 40) | ||
| 70 | 70 | </tr> |
| 71 | 71 | <template x-for='proc in (stats && stats.processes ? stats.processes.slice(0, 8) : [])' :key='proc.id'> |
| 72 | 72 | <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> | |
| 75 | 75 | <td> |
| 76 | 76 | <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> | |
| 78 | 78 | <div class='overflow-hidden flex-1 h-[3px] max-w-[60px] bg-bg-track rounded-[2px]'> |
| 79 | 79 | <div class='h-full rounded-[2px]' :class="cpuBarClass(proc.cpu)" :style="cpuBarStyle(proc.cpu)"></div> |
| 80 | 80 | </div> |
| 81 | 81 | </div> |
| 82 | 82 | </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> | |
| 85 | 85 | </tr> |
| 86 | 86 | </template> |
| 87 | 87 | </tbody> |
| @@ -86,7 +86,7 @@ | ||
| 86 | 86 | <!-- Reactive toast container --> |
| 87 | 87 | <div class='toast-area'> |
| 88 | 88 | @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> | |
| 90 | 90 | @endfor |
| 91 | 91 | </div> |
| 92 | 92 | |
| @@ -55,7 +55,7 @@ function esc(str) { return escapeHtml(str || '') } | ||
| 55 | 55 | <!-- Reactive toast container --> |
| 56 | 56 | <div class='toast-area'> |
| 57 | 57 | @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> | |
| 59 | 59 | @endfor |
| 60 | 60 | </div> |
| 61 | 61 | |
| @@ -133,9 +133,9 @@ | ||
| 133 | 133 | <div class='main-subtitle'> |
| 134 | 134 | <span x-show='loading'>Loading apps...</span> |
| 135 | 135 | <span x-show='!loading' x-cloak> |
| 136 | <span x-text="apps.length + ' apps'"></span> | |
| 136 | <span>{{ apps.length + ' apps' }}</span> | |
| 137 | 137 | <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> | |
| 139 | 139 | </span> |
| 140 | 140 | </div> |
| 141 | 141 | </div> |
| @@ -155,8 +155,8 @@ | ||
| 155 | 155 | <div x-show='loading' style='padding: 20px; text-align: center; color: #6c6c70; font-size: 12px;'>Scanning apps...</div> |
| 156 | 156 | <template x-for='app in filteredApps' :key='app.name'> |
| 157 | 157 | <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> | |
| 160 | 160 | </div> |
| 161 | 161 | </template> |
| 162 | 162 | </div> |
| @@ -169,25 +169,25 @@ | ||
| 169 | 169 | <div> |
| 170 | 170 | <div class='disk-card-title'>Macintosh HD</div> |
| 171 | 171 | </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> | |
| 173 | 173 | </div> |
| 174 | 174 | <div class='disk-card-meta'> |
| 175 | 175 | <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> | |
| 178 | 178 | </div> |
| 179 | 179 | <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> | |
| 181 | 181 | <div class='disk-bar-track'> |
| 182 | 182 | <div class='disk-bar-fill' :style="disk ? disk.fDiskBarStyle : 'width: 0%'"></div> |
| 183 | 183 | </div> |
| 184 | <span class='disk-bar-label' x-text="disk ? disk.fDiskTotal : '...'"></span> | |
| 184 | <span class='disk-bar-label'>{{ disk ? disk.fDiskTotal : '...' }}</span> | |
| 185 | 185 | </div> |
| 186 | 186 | <div class='disk-card-footer'> |
| 187 | 187 | <div class='disk-card-stat-row'> |
| 188 | 188 | <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> | |
| 191 | 191 | </div> |
| 192 | 192 | </div> |
| 193 | 193 | </div> |
| @@ -3,7 +3,7 @@ | ||
| 3 | 3 | |
| 4 | 4 | <div class='toast-area'> |
| 5 | 5 | <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> | |
| 7 | 7 | </template> |
| 8 | 8 | </div> |
| 9 | 9 | |
| @@ -13,7 +13,7 @@ | ||
| 13 | 13 | <div class='main-title'>Updates</div> |
| 14 | 14 | <div class='main-subtitle'> |
| 15 | 15 | <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> | |
| 17 | 17 | </div> |
| 18 | 18 | </div> |
| 19 | 19 | <div x-show='!loading' x-cloak style='display: flex; gap: 6px; flex-shrink: 0;'> |
| @@ -33,27 +33,27 @@ | ||
| 33 | 33 | <div class='card-row'> |
| 34 | 34 | <div class='card'> |
| 35 | 35 | <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> | |
| 37 | 37 | <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> | |
| 40 | 40 | <span x-show='updateScanCached' style='display: block; margin-top: 2px;'>cached scan</span> |
| 41 | 41 | </div> |
| 42 | 42 | </div> |
| 43 | 43 | <div class='card'> |
| 44 | 44 | <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> | |
| 47 | 47 | </div> |
| 48 | 48 | <div class='card'> |
| 49 | 49 | <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> | |
| 52 | 52 | </div> |
| 53 | 53 | <div class='card'> |
| 54 | 54 | <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> | |
| 57 | 57 | </div> |
| 58 | 58 | </div> |
| 59 | 59 | |
| @@ -61,7 +61,7 @@ | ||
| 61 | 61 | <div class='tbl-bar'> |
| 62 | 62 | <div> |
| 63 | 63 | <span class='tbl-title'>macOS & 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> | |
| 65 | 65 | <span class='tbl-count' x-show='systemOutdatedCount() === 0'>up to date</span> |
| 66 | 66 | </div> |
| 67 | 67 | <div style='display: flex; gap: 6px;'> |
| @@ -83,14 +83,14 @@ | ||
| 83 | 83 | <tbody> |
| 84 | 84 | <template x-for='upd in systemUpdates' :key='upd.label'> |
| 85 | 85 | <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> | |
| 90 | 90 | <td> |
| 91 | 91 | <span class='badge badge-orange' style='font-size: 9px; margin-right: 4px;' x-show='upd.restartRequired'>Restart</span> |
| 92 | 92 | <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> | |
| 94 | 94 | </td> |
| 95 | 95 | <td> |
| 96 | 96 | <button class='btn btn-sm' @click='openSystemSettings()'>Install</button> |
| @@ -102,7 +102,7 @@ | ||
| 102 | 102 | </div> |
| 103 | 103 | <div x-show='systemOutdatedCount() === 0' class='empty-state' style='padding: 20px;'> |
| 104 | 104 | <div style='font-size: 13px; color: #30d158; margin-bottom: 4px;'>✔ 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> | |
| 106 | 106 | <div class='dim' style='font-size: 11px; margin-top: 4px;' x-show='updateScanCached'>Use Deep Scan for a fresh Apple catalog check</div> |
| 107 | 107 | </div> |
| 108 | 108 | </div> |
| @@ -111,8 +111,8 @@ | ||
| 111 | 111 | <div class='tbl-bar'> |
| 112 | 112 | <div> |
| 113 | 113 | <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> | |
| 116 | 116 | </div> |
| 117 | 117 | <div style='display: flex; gap: 6px;'> |
| 118 | 118 | <button class='btn btn-sm' x-show='selected.length > 0' @click='doUpdateSelected()'> |
| @@ -136,10 +136,10 @@ | ||
| 136 | 136 | <template x-for='pkg in brewCasks' :key="'cask:' + pkg.name"> |
| 137 | 137 | <tr x-show="!isUpdated('cask:' + pkg.name)"> |
| 138 | 138 | <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> | |
| 140 | 140 | <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> | |
| 143 | 143 | <td class='action-cell'> |
| 144 | 144 | <template x-if="isUpdating('cask:' + pkg.name)"> |
| 145 | 145 | <span class='updating-label'>Updating…</span> |
| @@ -154,12 +154,12 @@ | ||
| 154 | 154 | <tr x-show='!isUpdated(pkg.name)'> |
| 155 | 155 | <td><input type='checkbox' class='check' :checked='isOn(pkg.name)' @click='toggle(pkg.name)' /></td> |
| 156 | 156 | <td> |
| 157 | <span class='item-name' x-text='pkg.name'></span> | |
| 157 | <span class='item-name'>{{ pkg.name }}</span> | |
| 158 | 158 | <span class='badge badge-gray' style='margin-left: 4px;' x-show='pkg.pinned'>pinned</span> |
| 159 | 159 | </td> |
| 160 | 160 | <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> | |
| 163 | 163 | <td> |
| 164 | 164 | <template x-if='pkg.pinned'> |
| 165 | 165 | <span class='dim' style='font-size: 10px;'>Pinned</span> |
| @@ -185,7 +185,7 @@ | ||
| 185 | 185 | <div class='tbl-bar'> |
| 186 | 186 | <div> |
| 187 | 187 | <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> | |
| 189 | 189 | <span class='tbl-count' x-show='pantryOutdated.length === 0'>all up to date</span> |
| 190 | 190 | </div> |
| 191 | 191 | </div> |
| @@ -203,10 +203,10 @@ | ||
| 203 | 203 | <tbody> |
| 204 | 204 | <template x-for='pkg in pantryOutdated' :key='pkg.name'> |
| 205 | 205 | <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> | |
| 210 | 210 | <td class='action-cell'> |
| 211 | 211 | <template x-if="isUpdating('pantry:' + pkg.name)"> |
| 212 | 212 | <span class='updating-label'>Updating…</span> |
| @@ -223,7 +223,7 @@ | ||
| 223 | 223 | <div x-show='pantryOutdated.length === 0 && pantryPackages.length > 0' style='padding: 12px 16px;'> |
| 224 | 224 | <div style='display: flex; flex-wrap: wrap; gap: 6px;'> |
| 225 | 225 | <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> | |
| 227 | 227 | </template> |
| 228 | 228 | </div> |
| 229 | 229 | </div> |
| @@ -234,12 +234,12 @@ | ||
| 234 | 234 | <div class='tbl-bar'> |
| 235 | 235 | <div> |
| 236 | 236 | <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> | |
| 239 | 239 | </div> |
| 240 | 240 | <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> | |
| 243 | 243 | <button class='btn btn-sm' :class="{ 'btn-active': appFilter === 'uptodate' }" @click="appFilter = 'uptodate'">Up to date</button> |
| 244 | 244 | </div> |
| 245 | 245 | </div> |
| @@ -257,13 +257,13 @@ | ||
| 257 | 257 | <template x-for='app in filteredDesktopApps()' :key='app.name'> |
| 258 | 258 | <tr x-show="!isUpdated('app:' + app.name)" :style="app.updateAvailable ? '' : 'opacity: 0.7;'"> |
| 259 | 259 | <td> |
| 260 | <span class='item-name' x-text='app.name'></span> | |
| 260 | <span class='item-name'>{{ app.name }}</span> | |
| 261 | 261 | <span class='badge badge-gray' style='margin-left: 4px; font-size: 9px;' x-show='app.autoUpdates'>auto-updates</span> |
| 262 | 262 | </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> | |
| 264 | 264 | <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> | |
| 267 | 267 | <span x-show='!app.latestVersion' class='dim' style='font-size: 10px;'>—</span> |
| 268 | 268 | </td> |
| 269 | 269 | <td> |