Files view: widen the change-details modal again and keep the legend on one row

- modal max-width 900px -> 1100px
- the legend's swatch and label were separate flex children, so a line break
  could split them and the three entries wrapped; each pair is now one
  `.hex-legend-item` (nowrap, no shrink) and the legend itself is
  `flex-wrap: nowrap` with `overflow-x: auto`, so it stays on a single row
- Node test: the modal test now checks the path header and that the legend
  follows the views as three grouped items
- SW cache simtrace-analyser-v70 (cosmetic, no version bump)
This commit is contained in:
catarrh committed 2026-10-17 21:40:50 +03:00
1 parent f13a2aeacd
commit bd0c9a2c4a
3 files changed
+12 -7

No files matched your search

+6 -5
View File
@@ -190,9 +190,10 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
.file-op-card { color: var(--warn); } .file-op-card { color: var(--warn); }
.file-op .file-op-diff { margin-left: auto; background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; padding: 0 2px; flex: 0 0 auto; text-decoration: underline; } .file-op .file-op-diff { margin-left: auto; background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; padding: 0 2px; flex: 0 0 auto; text-decoration: underline; }
.file-op .file-op-diff:hover { color: var(--warn); } .file-op .file-op-diff:hover { color: var(--warn); }
.file-diff-modal { max-width: 900px; } .file-diff-modal { max-width: 1100px; }
.file-diff-body { max-height: 60vh; overflow-y: auto; margin-bottom: 16px; } .file-diff-body { max-height: 60vh; overflow-y: auto; margin-bottom: 16px; }
.hex-legend { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); margin-top: 10px; flex-wrap: wrap; } .hex-legend { display: flex; align-items: center; gap: 14px; font-size: 11px; color: var(--text-muted); margin-top: 10px; flex-wrap: nowrap; overflow-x: auto; }
.hex-legend-item { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; flex: 0 0 auto; }
.hex-summary { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; } .hex-summary { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; }
.hex-pair { display: flex; gap: 16px; flex-wrap: wrap; } .hex-pair { display: flex; gap: 16px; flex-wrap: wrap; }
.hex-pair > div { flex: 1 1 320px; min-width: 0; } .hex-pair > div { flex: 1 1 320px; min-width: 0; }
@@ -2253,9 +2254,9 @@ function renderFileDiff(image) {
<div><h4>${t('After')}</h4>${hexImageHtml(image, 'after')}</div> <div><h4>${t('After')}</h4>${hexImageHtml(image, 'after')}</div>
</div> </div>
<div class="hex-legend"> <div class="hex-legend">
<span class="hex-cell hex-changed">aa</span> ${t('changed')} <span class="hex-legend-item"><span class="hex-cell hex-changed">aa</span> ${t('changed')}</span>
<span class="hex-cell hex-new">aa</span> ${t('newly observed')} <span class="hex-legend-item"><span class="hex-cell hex-new">aa</span> ${t('newly observed')}</span>
<span class="hex-cell hex-unknown">--</span> ${t('never observed')} <span class="hex-legend-item"><span class="hex-cell hex-unknown">--</span> ${t('never observed')}</span>
</div>` + </div>` +
(image.image_truncated ? `<p class="hex-note">${t('The image is frozen (size cap reached) — later changes are not tracked.')}</p>` : ''); (image.image_truncated ? `<p class="hex-note">${t('The image is frozen (size cap reached) — later changes are not tracked.')}</p>` : '');
} }
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v69'; const CACHE = 'simtrace-analyser-v70';
const PRECACHE = [ const PRECACHE = [
'index.html', 'index.html',
+5 -1
View File
@@ -466,6 +466,7 @@ eval(
test('Change details modal: header, summary, legend and both views', () => { test('Change details modal: header, summary, legend and both views', () => {
renderFileDiff({ renderFileDiff({
name: 'EF_ICCID', name: 'EF_ICCID',
path: 'MF/EF_ICCID (2FE2)',
op: 'READ BINARY', op: 'READ BINARY',
record: null, record: null,
n_records: null, n_records: null,
@@ -478,7 +479,7 @@ test('Change details modal: header, summary, legend and both views', () => {
image_truncated: false, image_truncated: false,
}); });
const sub = el('file-diff-sub').textContent; const sub = el('file-diff-sub').textContent;
assert.match(sub, /EF_ICCID — READ BINARY/); assert.match(sub, /MF\/EF_ICCID \(2FE2\) — READ BINARY/);
assert.match(sub, /#12/); assert.match(sub, /#12/);
const body = el('file-diff-body').innerHTML; const body = el('file-diff-body').innerHTML;
assert.match(body, /2 bytes changed, 4 bytes newly observed/); assert.match(body, /2 bytes changed, 4 bytes newly observed/);
@@ -488,6 +489,9 @@ test('Change details modal: header, summary, legend and both views', () => {
assert.match(body, /Before/); assert.match(body, /Before/);
assert.match(body, /After/); assert.match(body, /After/);
assert.equal((body.match(/class="hex-view"/g) || []).length, 2); assert.equal((body.match(/class="hex-view"/g) || []).length, 2);
// The legend sits below the two views, each swatch bound to its label.
assert.ok(body.indexOf('hex-legend') > body.lastIndexOf('hex-view'));
assert.equal((body.match(/class="hex-legend-item"/g) || []).length, 3);
// The record header variant and the frozen-image note. // The record header variant and the frozen-image note.
renderFileDiff({ renderFileDiff({
name: 'EF_IMSI', op: 'READ RECORD', record: 2, n_records: 5, index: 40, name: 'EF_IMSI', op: 'READ RECORD', record: 2, n_records: 5, index: 40,