ui: group the eSIM chip info into boxes and wrap values nicely
The chip view was one long flat list spread over the full height. - esimRenderChip split into esimChipSectionRows (object or RAT rule list -> rows) and esimChipBox (titled box, skipped when empty); the boxes are laid out on a grid: EID, EUICCInfo1, Addresses and the rules authorisation table in the left column, the larger EUICCInfo2 in the wider right-hand box (single column on narrow screens). Rows use a narrower label column (w-36). - Values wrap with break-words + min-w-0 instead of break-all: text breaks at spaces first and long hex/AID tokens only when they cannot fit (same for the profile metadata rows). - style.css rebuilt (grid-cols-1, lg:grid-cols-3, lg:col-span-1/2/3, break-words). - tests: the new helpers, the grid/box layout and the wrapping check; help EN/RU note the grouping; sw.js simple-v232.
This commit is contained in:
+44
-28
@@ -1665,41 +1665,57 @@ function esimIconDataUrl(p) {
|
||||
return 'data:' + mime + ';base64,' + btoa(bin);
|
||||
}
|
||||
|
||||
// One chip-info section -> rows (the RAT is a list of rules).
|
||||
function esimChipSectionRows(data) {
|
||||
if (!data) return [];
|
||||
if (Array.isArray(data)) {
|
||||
const rows = [];
|
||||
data.forEach((item, i) => {
|
||||
rows.push(...esimFieldRows(item, t('Rule') + ' ' + (i + 1)));
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
return esimFieldRows(data, '');
|
||||
}
|
||||
|
||||
// One bordered chip-info box; no rows -> no box.
|
||||
function esimChipBox(title, rows) {
|
||||
if (!rows || !rows.length) return '';
|
||||
let html = '<div class="border border-gray-200 dark:border-slate-700 rounded p-2 min-w-0">';
|
||||
html += '<div class="mb-1 text-xs font-semibold text-gray-600 dark:text-slate-300">' + esc(title) + '</div>';
|
||||
for (const [k, v] of rows) {
|
||||
html += '<div class="flex gap-2 mb-0.5">';
|
||||
if (k) html += '<span class="w-36 shrink-0 text-right text-gray-500 dark:text-slate-400 break-words">' + esc(k) + '</span>';
|
||||
html += '<span class="font-mono break-words min-w-0">' + esc(v) + '</span></div>';
|
||||
}
|
||||
return html + '</div>';
|
||||
}
|
||||
|
||||
function esimRenderChip() {
|
||||
const el = document.getElementById('esim-chip');
|
||||
if (!el) return;
|
||||
const c = _esimChip || {};
|
||||
const rows = [];
|
||||
if (c.eid) rows.push(['EID', esimGroupEid(c.eid)]);
|
||||
const sections = [
|
||||
['EUICCInfo1', c.info1], ['EUICCInfo2', c.info2],
|
||||
['Addresses', c.addresses], ['Rules authorisation table', c.rat],
|
||||
];
|
||||
for (const [name, data] of sections) {
|
||||
if (!data || (Array.isArray(data) && !data.length)) continue;
|
||||
rows.push(['§ ' + t(name), '']);
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach((item, i) => {
|
||||
rows.push(...esimFieldRows(item, t('Rule') + ' ' + (i + 1)));
|
||||
});
|
||||
} else {
|
||||
rows.push(...esimFieldRows(data, ''));
|
||||
}
|
||||
}
|
||||
let html = '';
|
||||
for (const [k, v] of rows) {
|
||||
if (k.startsWith('§ ')) {
|
||||
html += '<div class="mt-2 mb-0.5 font-semibold text-gray-600 dark:text-slate-300">' + esc(k.slice(2)) + '</div>';
|
||||
continue;
|
||||
}
|
||||
html += '<div class="flex gap-2 mb-0.5"><span class="w-56 shrink-0 text-right text-gray-500 dark:text-slate-400 break-all">' + esc(k) + '</span>' +
|
||||
'<span class="font-mono break-all">' + esc(v) + '</span></div>';
|
||||
const left = [
|
||||
c.eid ? esimChipBox('EID', [['', esimGroupEid(c.eid)]]) : '',
|
||||
esimChipBox('EUICCInfo1', esimChipSectionRows(c.info1)),
|
||||
esimChipBox(t('Addresses'), esimChipSectionRows(c.addresses)),
|
||||
esimChipBox(t('Rules authorisation table'), esimChipSectionRows(c.rat)),
|
||||
].filter(Boolean);
|
||||
const right = esimChipBox('EUICCInfo2', esimChipSectionRows(c.info2));
|
||||
if (!left.length && !right) {
|
||||
el.innerHTML = '<span class="text-gray-400">' + esc(t('No data')) + '</span>';
|
||||
return;
|
||||
}
|
||||
let html = '<div class="grid grid-cols-1 lg:grid-cols-3 gap-3 items-start">';
|
||||
html += '<div class="' + (right ? 'lg:col-span-1' : 'lg:col-span-3') + ' space-y-3 min-w-0">' +
|
||||
left.join('') + '</div>';
|
||||
if (right) html += '<div class="lg:col-span-2 min-w-0">' + right + '</div>';
|
||||
html += '</div>';
|
||||
const errs = Object.keys(c.errors || {});
|
||||
if (errs.length) {
|
||||
html += '<div class="text-xs text-yellow-600 dark:text-yellow-500 mt-1">' + esc(t('Not available')) + ': ' + esc(errs.join(', ')) + '</div>';
|
||||
}
|
||||
el.innerHTML = html || '<span class="text-gray-400">' + esc(t('No data')) + '</span>';
|
||||
el.innerHTML = html;
|
||||
}
|
||||
|
||||
function esimRenderProfiles() {
|
||||
@@ -1724,8 +1740,8 @@ function esimRenderProfiles() {
|
||||
esc(t(enabled ? 'Disable' : 'Enable')) + '</button></div>';
|
||||
let rowsHtml = '';
|
||||
for (const [k, v] of esimProfileRows(p)) {
|
||||
rowsHtml += '<div class="flex gap-2"><span class="w-40 shrink-0 text-right text-gray-500 dark:text-slate-400 break-all">' + esc(k) + '</span>' +
|
||||
'<span class="font-mono break-all">' + esc(v) + '</span></div>';
|
||||
rowsHtml += '<div class="flex gap-2"><span class="w-40 shrink-0 text-right text-gray-500 dark:text-slate-400 break-words">' + esc(k) + '</span>' +
|
||||
'<span class="font-mono break-words min-w-0">' + esc(v) + '</span></div>';
|
||||
}
|
||||
const iconUrl = esimIconDataUrl(p);
|
||||
html += '<div class="flex gap-3 items-start">';
|
||||
|
||||
Reference in New Issue
Block a user