From c3117e90fabc64218a68b847be05a354c6dda2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 28 Sep 2026 23:38:06 +0300 Subject: [PATCH] fix: rebuilt stylesheet + visible explorer rows (v3.6.30) The compiled Tailwind stylesheet (frontend/style.css) had been stale since 2026-09-22: classes introduced later were missing from it, so the Install / Make selectable chips had no background or text colour in light mode (dark mode only looked green because an older dark:text-emerald-400 rule matched) and the new w-28 action column did not apply. - Rebuilt with `npm run build` (Tailwind + appended src/contrast.css); verified the previously missing classes (bg-emerald-100, text-emerald-700, hover:bg-emerald-200, bg-red-100, bg-blue-100, w-28, ...). - Explorer rows are visible chips now: rounded bg-gray-50 dark:bg-slate-800/60 with a hover:bg-gray-100 highlight and the colored left accent kept (module rows a subtler variant), so a right-column button is unambiguously tied to its row; ISD/app/ELF/module rows all use the same treatment. - AGENTS working conventions: an index.html change that introduces new utility classes also requires `npm run build` in frontend/. 660 frontend / 504 Python green; version 3.6.30; sw simple-v303. --- frontend/index.html | 10 +- frontend/style.css | 186 ++++++++++++++++++++++++++++++++++ frontend/sw.js | 2 +- frontend/tests/ram.test.js | 3 + pyproject.toml | 2 +- pysim_simple_server/server.py | 2 +- 6 files changed, 197 insertions(+), 8 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 09835b3..dc6ea9e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1713,7 +1713,7 @@ // ===== Version ===== // Single source of truth for the PWA version: shown in the header and used // by the server version check in pysimConnect(). -const SIMPLE_VERSION = '3.6.29'; +const SIMPLE_VERSION = '3.6.30'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== Tab switching ===== @@ -8840,7 +8840,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) { html += '
'; html += '
' + esc(t('ISD (Issuer Security Domain)')) + '
'; isd.forEach(o => { - html += '
'; + html += '
'; html += '
' + esc(t('AID:')) + ' ' + (o.aid ? jcAidHtml(o.aid) : '?') + '
'; html += '
' + esc(t('Lifecycle:')) + ' ' + ramFmtLifecycle(o.lifecycle || '') + '
'; if (o.privileges) html += '
' + esc(t('Privileges:')) + ' ' + ramFmtPrivileges(o.privileges) + ' (' + o.privileges + ')
'; @@ -8853,7 +8853,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) { html += '
'; html += '
' + esc(t('Applications / Applet Instances')) + '
'; apps.forEach(o => { - html += '
'; + html += '
'; html += '
'; html += '
' + esc(t('Application / Instance AID:')) + ' ' + (o.aid ? jcAidHtml(o.aid) : '?') + '
'; html += '
' + esc(t('Lifecycle:')) + ' ' + ramFmtLifecycle(o.lifecycle || '') + '
'; @@ -8877,7 +8877,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) { html += '
'; html += '
' + esc(t('Executable Load Files (ELFs) / Packages')) + '
'; elfs.forEach(o => { - html += '
'; + html += '
'; html += '
'; html += '
' + esc(t('Load File AID / Package AID:')) + ' ' + (o.aid ? jcAidHtml(o.aid) : '?') + '
'; html += '
' + esc(t('Lifecycle:')) + ' ' + ramFmtLifecycle(o.lifecycle || '') + '
'; @@ -8896,7 +8896,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) { // Module rows: emitted as sibling rows so their Install buttons share // the same action column as the entry buttons. (o.moduleAids || []).forEach(m => { - html += '
'; + html += '
'; html += '
- ' + jcAidHtml(m) + '
'; html += '
'; // A loaded applet class with no instance yet: one click to the diff --git a/frontend/style.css b/frontend/style.css index 63be6ee..f54efca 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -672,6 +672,14 @@ video { z-index: 50; } +.col-span-2 { + grid-column: span 2 / span 2; +} + +.col-span-4 { + grid-column: span 4 / span 4; +} + .mx-3 { margin-left: 0.75rem; margin-right: 0.75rem; @@ -743,6 +751,10 @@ video { margin-left: 1rem; } +.ml-7 { + margin-left: 1.75rem; +} + .ml-8 { margin-left: 2rem; } @@ -891,6 +903,10 @@ video { width: 6rem; } +.w-28 { + width: 7rem; +} + .w-32 { width: 8rem; } @@ -956,10 +972,18 @@ video { min-width: 14rem; } +.min-w-\[16rem\] { + min-width: 16rem; +} + .min-w-\[180px\] { min-width: 180px; } +.max-w-2xl { + max-width: 42rem; +} + .max-w-3xl { max-width: 48rem; } @@ -1173,6 +1197,17 @@ video { margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } +.divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} + +.divide-gray-100 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-divide-opacity, 1)); +} + .overflow-auto { overflow: auto; } @@ -1256,6 +1291,11 @@ video { border-top-width: 1px; } +.border-amber-400 { + --tw-border-opacity: 1; + border-color: rgb(251 191 36 / var(--tw-border-opacity, 1)); +} + .border-blue-400 { --tw-border-opacity: 1; border-color: rgb(96 165 250 / var(--tw-border-opacity, 1)); @@ -1291,10 +1331,20 @@ video { border-color: rgb(192 132 252 / var(--tw-border-opacity, 1)); } +.border-red-300 { + --tw-border-opacity: 1; + border-color: rgb(252 165 165 / var(--tw-border-opacity, 1)); +} + .border-t-transparent { border-top-color: transparent; } +.bg-amber-50 { + --tw-bg-opacity: 1; + background-color: rgb(255 251 235 / var(--tw-bg-opacity, 1)); +} + .bg-amber-600 { --tw-bg-opacity: 1; background-color: rgb(217 119 6 / var(--tw-bg-opacity, 1)); @@ -1304,11 +1354,21 @@ video { background-color: rgb(0 0 0 / 0.5); } +.bg-blue-100 { + --tw-bg-opacity: 1; + background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1)); +} + .bg-blue-600 { --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1)); } +.bg-emerald-100 { + --tw-bg-opacity: 1; + background-color: rgb(209 250 229 / var(--tw-bg-opacity, 1)); +} + .bg-emerald-600 { --tw-bg-opacity: 1; background-color: rgb(5 150 105 / var(--tw-bg-opacity, 1)); @@ -1324,6 +1384,10 @@ video { background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1)); } +.bg-gray-100\/60 { + background-color: rgb(243 244 246 / 0.6); +} + .bg-gray-200 { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1)); @@ -1497,6 +1561,14 @@ video { padding-left: 1.25rem; } +.pl-6 { + padding-left: 1.5rem; +} + +.pr-2 { + padding-right: 0.5rem; +} + .pt-1 { padding-top: 0.25rem; } @@ -1575,10 +1647,19 @@ video { font-weight: 600; } +.uppercase { + text-transform: uppercase; +} + .italic { font-style: italic; } +.ordinal { + --tw-ordinal: ordinal; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction); +} + .leading-relaxed { line-height: 1.625; } @@ -1597,16 +1678,31 @@ video { color: rgb(217 119 6 / var(--tw-text-opacity, 1)); } +.text-amber-700 { + --tw-text-opacity: 1; + color: rgb(180 83 9 / var(--tw-text-opacity, 1)); +} + .text-blue-600 { --tw-text-opacity: 1; color: rgb(37 99 235 / var(--tw-text-opacity, 1)); } +.text-blue-700 { + --tw-text-opacity: 1; + color: rgb(29 78 216 / var(--tw-text-opacity, 1)); +} + .text-emerald-600 { --tw-text-opacity: 1; color: rgb(5 150 105 / var(--tw-text-opacity, 1)); } +.text-emerald-700 { + --tw-text-opacity: 1; + color: rgb(4 120 87 / var(--tw-text-opacity, 1)); +} + .text-gray-300 { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity, 1)); @@ -1687,6 +1783,11 @@ video { color: rgb(148 163 184 / var(--tw-text-opacity, 1)); } +.text-slate-500 { + --tw-text-opacity: 1; + color: rgb(100 116 139 / var(--tw-text-opacity, 1)); +} + .text-white { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity, 1)); @@ -1738,6 +1839,11 @@ video { background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1)); } +.hover\:bg-emerald-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(167 243 208 / var(--tw-bg-opacity, 1)); +} + .hover\:bg-emerald-700:hover { --tw-bg-opacity: 1; background-color: rgb(4 120 87 / var(--tw-bg-opacity, 1)); @@ -1753,6 +1859,10 @@ video { background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1)); } +.hover\:bg-gray-200\/60:hover { + background-color: rgb(229 231 235 / 0.6); +} + .hover\:bg-gray-300:hover { --tw-bg-opacity: 1; background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1)); @@ -1793,6 +1903,16 @@ video { color: rgb(75 85 99 / var(--tw-text-opacity, 1)); } +.hover\:text-gray-700:hover { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity, 1)); +} + +.hover\:text-gray-800:hover { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity, 1)); +} + .hover\:text-red-500:hover { --tw-text-opacity: 1; color: rgb(239 68 68 / var(--tw-text-opacity, 1)); @@ -1816,10 +1936,29 @@ video { cursor: not-allowed; } +.disabled\:opacity-30:disabled { + opacity: 0.3; +} + .disabled\:opacity-40:disabled { opacity: 0.4; } +.dark\:divide-slate-700:is(.dark *) > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(51 65 85 / var(--tw-divide-opacity, 1)); +} + +.dark\:border-amber-600:is(.dark *) { + --tw-border-opacity: 1; + border-color: rgb(217 119 6 / var(--tw-border-opacity, 1)); +} + +.dark\:border-red-800:is(.dark *) { + --tw-border-opacity: 1; + border-color: rgb(153 27 27 / var(--tw-border-opacity, 1)); +} + .dark\:border-slate-600:is(.dark *) { --tw-border-opacity: 1; border-color: rgb(71 85 105 / var(--tw-border-opacity, 1)); @@ -1839,11 +1978,27 @@ video { border-color: rgb(30 41 59 / var(--tw-border-opacity, 1)); } +.dark\:bg-amber-900\/20:is(.dark *) { + background-color: rgb(120 53 15 / 0.2); +} + .dark\:bg-blue-500:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1)); } +.dark\:bg-blue-900\/40:is(.dark *) { + background-color: rgb(30 58 138 / 0.4); +} + +.dark\:bg-emerald-900\/30:is(.dark *) { + background-color: rgb(6 78 59 / 0.3); +} + +.dark\:bg-emerald-900\/40:is(.dark *) { + background-color: rgb(6 78 59 / 0.4); +} + .dark\:bg-red-900\/30:is(.dark *) { background-color: rgb(127 29 29 / 0.3); } @@ -1858,11 +2013,24 @@ video { background-color: rgb(30 41 59 / var(--tw-bg-opacity, 1)); } +.dark\:bg-slate-800\/40:is(.dark *) { + background-color: rgb(30 41 59 / 0.4); +} + +.dark\:bg-slate-800\/60:is(.dark *) { + background-color: rgb(30 41 59 / 0.6); +} + .dark\:bg-slate-900:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(15 23 42 / var(--tw-bg-opacity, 1)); } +.dark\:text-amber-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(252 211 77 / var(--tw-text-opacity, 1)); +} + .dark\:text-amber-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(251 191 36 / var(--tw-text-opacity, 1)); @@ -1873,11 +2041,21 @@ video { color: rgb(245 158 11 / var(--tw-text-opacity, 1)); } +.dark\:text-blue-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(147 197 253 / var(--tw-text-opacity, 1)); +} + .dark\:text-blue-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(96 165 250 / var(--tw-text-opacity, 1)); } +.dark\:text-emerald-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(110 231 183 / var(--tw-text-opacity, 1)); +} + .dark\:text-emerald-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(52 211 153 / var(--tw-text-opacity, 1)); @@ -1967,6 +2145,14 @@ video { background-color: rgb(51 65 85 / var(--tw-bg-opacity, 1)); } +.dark\:hover\:bg-slate-700\/40:hover:is(.dark *) { + background-color: rgb(51 65 85 / 0.4); +} + +.dark\:hover\:bg-slate-700\/50:hover:is(.dark *) { + background-color: rgb(51 65 85 / 0.5); +} + .dark\:hover\:text-gray-300:hover:is(.dark *) { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity, 1)); diff --git a/frontend/sw.js b/frontend/sw.js index 2af4142..028b3f4 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v302'; +const CACHE = 'simple-v303'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/ram.test.js b/frontend/tests/ram.test.js index be4eb92..94a7bec 100644 --- a/frontend/tests/ram.test.js +++ b/frontend/tests/ram.test.js @@ -203,6 +203,9 @@ test('explorer action buttons share a fixed-width column, Install is green', () delete global.t; // every action cell is the same fixed-width column assert.ok(out.includes('w-28 shrink-0'), out); + // rows are visible chips (background + hover) so the button belongs to its row + assert.ok(out.includes('bg-gray-50 dark:bg-slate-800/60'), out); + assert.ok(out.includes('hover:bg-gray-100 dark:hover:bg-slate-700/50'), out); // the Install button (module without an instance) is green, not blue const inst = /