v3.11.0 editor layout: PIN/ADM + TAR side by side, codes as a vertical list
The PIN/ADM and TAR fieldsets now share one responsive row (side by side from lg, stacked below): PIN/ADM is a fixed 224px column (lg:w-56) that stretches to the TAR box's height, TAR takes the rest (flex-1 min-w-0). The codes are a vertical list (label above each input) and the hint is shortened to "All codes are optional" - the specifics stay in the input placeholders and the help. A structural guard pins the row and the short hint; sw cache simple-v363. Tests: 665 Python + 785 frontend green; the whole inline PWA script syntax-checked.
This commit is contained in:
+7
-5
@@ -1637,9 +1637,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
<div class="flex flex-col lg:flex-row gap-3 mb-3">
|
||||||
|
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 lg:w-56 shrink-0">
|
||||||
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="PIN/ADM">PIN/ADM</legend>
|
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="PIN/ADM">PIN/ADM</legend>
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-2 mb-2">
|
<div class="space-y-2">
|
||||||
<div>
|
<div>
|
||||||
<label for="cards-pin1" class="block mb-0.5 text-xs text-gray-600 dark:text-slate-400">PIN1</label>
|
<label for="cards-pin1" class="block mb-0.5 text-xs text-gray-600 dark:text-slate-400">PIN1</label>
|
||||||
<input id="cards-pin1" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono text-center" maxlength="8" inputmode="numeric" placeholder="4-8 digits">
|
<input id="cards-pin1" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono text-center" maxlength="8" inputmode="numeric" placeholder="4-8 digits">
|
||||||
@@ -1661,9 +1662,9 @@
|
|||||||
<input id="cards-adm" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono text-center" maxlength="16" placeholder="ADM (optional)">
|
<input id="cards-adm" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono text-center" maxlength="16" placeholder="ADM (optional)">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-500 dark:text-slate-400" data-l10n="All codes are optional: PIN/PUK are 4-8 decimal digits (stored for later use by the card operations — not consumed yet); ADM is the administrator key.">All codes are optional: PIN/PUK are 4-8 decimal digits (stored for later use by the card operations — not consumed yet); ADM is the administrator key.</p>
|
<p class="text-xs text-gray-500 dark:text-slate-400 mt-2" data-l10n="All codes are optional">All codes are optional</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 flex-1 min-w-0">
|
||||||
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="TAR">TAR</legend>
|
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="TAR">TAR</legend>
|
||||||
<table class="w-full text-sm mb-2">
|
<table class="w-full text-sm mb-2">
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
@@ -1680,6 +1681,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-500 dark:text-slate-400" data-l10n="Each TAR carries its MSL (Minimum SPI1) — the card checks it before the security processing (TS 102 226 8.2.1.3.2.4); the packet SPI1 is derived from it.">Each TAR carries its MSL (Minimum SPI1) — the card checks it before the security processing (TS 102 226 8.2.1.3.2.4); the packet SPI1 is derived from it.</p>
|
<p class="text-xs text-gray-500 dark:text-slate-400" data-l10n="Each TAR carries its MSL (Minimum SPI1) — the card checks it before the security processing (TS 102 226 8.2.1.3.2.4); the packet SPI1 is derived from it.">Each TAR carries its MSL (Minimum SPI1) — the card checks it before the security processing (TS 102 226 8.2.1.3.2.4); the packet SPI1 is derived from it.</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
</div>
|
||||||
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
||||||
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="SCP80 (GSM 03.48, ETSI TS 102 225)">SCP80 (GSM 03.48, ETSI TS 102 225)</legend>
|
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="SCP80 (GSM 03.48, ETSI TS 102 225)">SCP80 (GSM 03.48, ETSI TS 102 225)</legend>
|
||||||
<div class="mb-1 flex items-center justify-between">
|
<div class="mb-1 flex items-center justify-between">
|
||||||
@@ -20915,7 +20917,7 @@ const LANG_RU = {
|
|||||||
'TAR': 'TAR',
|
'TAR': 'TAR',
|
||||||
'Description': 'Описание',
|
'Description': 'Описание',
|
||||||
'Card presets are stored on the server. A preset carries the card codes (PIN/PUK/ADM), a TAR table (every TAR with its MSL) and several keysets, each with its own number and counter.': 'Пресеты карт хранятся на сервере. Пресет содержит коды карты (PIN/PUK/ADM), таблицу TAR (у каждого TAR свой MSL) и несколько keysets — у каждого свой номер и счётчик.',
|
'Card presets are stored on the server. A preset carries the card codes (PIN/PUK/ADM), a TAR table (every TAR with its MSL) and several keysets, each with its own number and counter.': 'Пресеты карт хранятся на сервере. Пресет содержит коды карты (PIN/PUK/ADM), таблицу TAR (у каждого TAR свой MSL) и несколько keysets — у каждого свой номер и счётчик.',
|
||||||
'All codes are optional: PIN/PUK are 4-8 decimal digits (stored for later use by the card operations — not consumed yet); ADM is the administrator key.': 'Все коды необязательны: PIN/PUK — 4–8 десятичных цифр (сохраняются для будущего использования операциями карты — пока не используются); ADM — администраторский ключ.',
|
'All codes are optional': 'Все коды необязательны',
|
||||||
'The first three rows are the fixed role TARs; add further TARs as needed.': 'Первые три строки — фиксированные роли TAR; дополнительные TAR добавляются по необходимости.',
|
'The first three rows are the fixed role TARs; add further TARs as needed.': 'Первые три строки — фиксированные роли TAR; дополнительные TAR добавляются по необходимости.',
|
||||||
'PIN/PUK codes must be 4-8 decimal digits': 'Коды PIN/PUK должны состоять из 4–8 десятичных цифр',
|
'PIN/PUK codes must be 4-8 decimal digits': 'Коды PIN/PUK должны состоять из 4–8 десятичных цифр',
|
||||||
'Keysets (number: KIc/KID — counter)': 'Keysets (номер: KIc/KID — счётчик)',
|
'Keysets (number: KIc/KID — counter)': 'Keysets (номер: KIc/KID — счётчик)',
|
||||||
|
|||||||
+6
-6
@@ -2221,10 +2221,6 @@ video {
|
|||||||
.sm\:grid-cols-2 {
|
.sm\:grid-cols-2 {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:grid-cols-3 {
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
@@ -2240,12 +2236,16 @@ video {
|
|||||||
grid-column: span 3 / span 3;
|
grid-column: span 3 / span 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:w-56 {
|
||||||
|
width: 14rem;
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:grid-cols-3 {
|
.lg\:grid-cols-3 {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.lg\:grid-cols-5 {
|
.lg\:flex-row {
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
}/* ===== Theme contrast adjustments ===== */
|
}/* ===== Theme contrast adjustments ===== */
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v362';
|
const CACHE = 'simple-v363';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -174,6 +174,22 @@ test('the ADM input allows the full 4-16 hex digit key', () => {
|
|||||||
'the ADM input must allow 4-16 hex digits (server _verify_adm)');
|
'the ADM input must allow 4-16 hex digits (server _verify_adm)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the PIN/ADM and TAR fieldsets share one responsive row', () => {
|
||||||
|
const start = html.indexOf('<div class="flex flex-col lg:flex-row gap-3 mb-3">');
|
||||||
|
assert.ok(start >= 0, 'the PIN/ADM + TAR row is missing');
|
||||||
|
const row = html.slice(start, html.indexOf('id="cards-keysets"'));
|
||||||
|
// both fieldsets live in the row: side by side from lg, stacked below
|
||||||
|
assert.match(row, /data-l10n="PIN\/ADM"/);
|
||||||
|
assert.match(row, /data-l10n="TAR"/);
|
||||||
|
assert.match(row, /class="[^"]*rounded p-3 lg:w-56 shrink-0"/);
|
||||||
|
assert.match(row, /class="[^"]*rounded p-3 flex-1 min-w-0"/);
|
||||||
|
// the codes are a vertical list, label above each input
|
||||||
|
assert.match(row, /class="space-y-2"[\s\S]*?for="cards-pin1"[\s\S]*?id="cards-pin1"/);
|
||||||
|
// the hint is the short form
|
||||||
|
assert.match(row, /data-l10n="All codes are optional"/);
|
||||||
|
assert.ok(!row.includes('not consumed yet'), 'the long codes hint is gone');
|
||||||
|
});
|
||||||
|
|
||||||
test('the Cards tab splits the preset list and the editor into views', () => {
|
test('the Cards tab splits the preset list and the editor into views', () => {
|
||||||
assert.match(html, /id="cards-list-view"/);
|
assert.match(html, /id="cards-list-view"/);
|
||||||
assert.match(html, /id="cards-editor-view" class="hidden"/);
|
assert.match(html, /id="cards-editor-view" class="hidden"/);
|
||||||
|
|||||||
Reference in New Issue
Block a user