chore(embedded): cut v0.0.27-beta
Some checks failed
Notify chart dev on beta cut / notify-chart-dev (push) Failing after 8s

This commit is contained in:
ZDDC 2026-06-03 08:55:39 -05:00
parent 3e8737b7c9
commit 8875d490f5
7 changed files with 544 additions and 17 deletions

View file

@ -2582,7 +2582,7 @@ td[data-field="trackingNumber"] {
</svg> </svg>
<div class="header-title-group"> <div class="header-title-group">
<span class="app-header__title">ZDDC Archive</span> <span class="app-header__title">ZDDC Archive</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4</span></span> <span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b</span></span>
</div> </div>
<button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button> <button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button>
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh Data"></button> <button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh Data"></button>
@ -5125,15 +5125,23 @@ X.B(E,Y);return E}return J}())
* Cross-tool helpers for previewing file types that need a decoder: * Cross-tool helpers for previewing file types that need a decoder:
* - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar * - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar
* - ZIP listing (JSZip) — sortable file-list view * - ZIP listing (JSZip) — sortable file-list view
* - DOCX (docx-preview) — Word-styled pages in a scroll container
* - XLSX/XLS (SheetJS) — sheet-to-HTML table with a sheet tab bar
* *
* Renderers operate on any document (parent window or popup window), so the * Renderers operate on any document (parent window or popup window), so the
* same code works for tools whose preview opens in a popup (classifier, * same code works for tools whose preview opens in a popup (classifier,
* archive, transmittal) and tools that render inline (browse). * archive, transmittal) and tools that render inline (browse).
* *
* The DOCX/XLSX renderers expect their vendor lib bundled by the calling
* tool's build.sh (docx-preview.min.js → window.docx, xlsx.full.min.js →
* window.XLSX); they degrade to a friendly message if it isn't present.
*
* Public API on window.zddc.preview: * Public API on window.zddc.preview:
* loadLibrary(url) → Promise<void> * loadLibrary(url) → Promise<void>
* renderTiff(doc, container, arrayBuffer, opts) → Promise<void> * renderTiff(doc, container, arrayBuffer, opts) → Promise<void>
* renderZipListing(doc, container, arrayBuffer, opts) → Promise<void> * renderZipListing(doc, container, arrayBuffer, opts) → Promise<void>
* renderDocx(doc, container, arrayBuffer, opts) → Promise<void>
* renderXlsx(doc, container, arrayBuffer, opts) → Promise<void>
* TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS * TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS
* isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext) * isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext)
* *
@ -5646,6 +5654,111 @@ X.B(E,Y);return E}return J}())
}); });
} }
// ── DOCX (docx-preview) ────────────────────────────────────────────────
//
// docx-preview renders Word-styled pages with an intrinsic page width, so
// we wrap it in a scroll container: a wide document scrolls WITHIN the
// preview pane rather than pushing the page wider. docx-preview is bundled
// by the tools that opt in (each build.sh concatenates
// shared/vendor/docx-preview.min.js → window.docx).
var DOCX_CSS =
'.zddc-docx{height:100%;min-width:0;overflow:auto;'
+ 'background:var(--bg-secondary,#eee);padding:1rem;box-sizing:border-box;}'
+ '.zddc-docx .docx-wrapper{background:transparent;padding:0;}';
function renderDocx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-docx-styles', DOCX_CSS);
if (!window.docx || typeof window.docx.renderAsync !== 'function') {
container.innerHTML = '<div class="preview-empty">DOCX preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
container.innerHTML = '';
var scroll = doc.createElement('div');
scroll.className = 'zddc-docx';
container.appendChild(scroll);
return Promise.resolve(
window.docx.renderAsync(arrayBuffer, scroll, null, { inWrapper: true })
).catch(function (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render DOCX: ' + escapeHtml(err.message || err) + '</div>';
});
}
// ── XLSX / XLS (SheetJS) ───────────────────────────────────────────────
//
// Reads the workbook and renders the active sheet to an HTML table; a tab
// bar switches sheets when there's more than one. SheetJS is bundled by
// the tools that opt in (shared/vendor/xlsx.full.min.js → window.XLSX).
var XLSX_CSS =
'.zddc-xlsx{display:flex;flex-direction:column;height:100%;min-width:0;'
+ 'min-height:0;overflow:hidden;}'
+ '.zddc-xlsx__tabs{display:flex;flex-wrap:wrap;gap:0.25rem;padding:0.4rem;'
+ 'border-bottom:1px solid var(--border,#ccc);flex:0 0 auto;}'
+ '.zddc-xlsx__tab{padding:0.2rem 0.6rem;border:1px solid var(--border,#ccc);'
+ 'border-radius:4px;background:var(--bg,#fff);color:var(--text,#222);'
+ 'cursor:pointer;font-size:0.85rem;}'
+ '.zddc-xlsx__tab.is-active{background:var(--primary,#2563eb);color:#fff;'
+ 'border-color:var(--primary,#2563eb);}'
+ '.zddc-xlsx__body{flex:1 1 auto;min-width:0;min-height:0;overflow:auto;}'
+ '.zddc-xlsx__body table{border-collapse:collapse;font-size:0.85rem;'
+ 'color:var(--text,#222);}'
+ '.zddc-xlsx__body td,.zddc-xlsx__body th{border:1px solid var(--border,#ddd);'
+ 'padding:0.2rem 0.45rem;white-space:nowrap;}';
function renderXlsx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-xlsx-styles', XLSX_CSS);
if (!window.XLSX || typeof window.XLSX.read !== 'function') {
container.innerHTML = '<div class="preview-empty">Spreadsheet preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
try {
var wb = window.XLSX.read(arrayBuffer, { type: 'array' });
container.innerHTML = '';
var rootEl = doc.createElement('div');
rootEl.className = 'zddc-xlsx';
var body = doc.createElement('div');
body.className = 'zddc-xlsx__body';
function showSheet(name) {
var sheet = wb.Sheets[name];
body.innerHTML = sheet
? window.XLSX.utils.sheet_to_html(sheet, { editable: false })
: '';
}
if (wb.SheetNames.length > 1) {
var tabs = doc.createElement('div');
tabs.className = 'zddc-xlsx__tabs';
wb.SheetNames.forEach(function (name, i) {
var btn = doc.createElement('button');
btn.className = 'zddc-xlsx__tab' + (i === 0 ? ' is-active' : '');
btn.textContent = name;
btn.addEventListener('click', function () {
var all = tabs.querySelectorAll('.zddc-xlsx__tab');
for (var j = 0; j < all.length; j++) all[j].classList.remove('is-active');
btn.classList.add('is-active');
showSheet(name);
});
tabs.appendChild(btn);
});
rootEl.appendChild(tabs);
}
rootEl.appendChild(body);
container.appendChild(rootEl);
showSheet(wb.SheetNames[0]);
} catch (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render spreadsheet: ' + escapeHtml(err.message || err) + '</div>';
}
return Promise.resolve();
}
// ── Public API ─────────────────────────────────────────────────────────── // ── Public API ───────────────────────────────────────────────────────────
if (!root.zddc) root.zddc = {}; if (!root.zddc) root.zddc = {};
@ -5662,6 +5775,8 @@ X.B(E,Y);return E}return J}())
loadLibrary: loadLibrary, loadLibrary: loadLibrary,
renderTiff: renderTiff, renderTiff: renderTiff,
renderZipListing: renderZipListing, renderZipListing: renderZipListing,
renderDocx: renderDocx,
renderXlsx: renderXlsx,
formatSize: formatSize, formatSize: formatSize,
formatDate: formatDate formatDate: formatDate
}; };

File diff suppressed because one or more lines are too long

View file

@ -1793,7 +1793,7 @@ body.is-elevated::after {
</svg> </svg>
<div class="header-title-group"> <div class="header-title-group">
<span class="app-header__title">ZDDC Classifier</span> <span class="app-header__title">ZDDC Classifier</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4</span></span> <span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b</span></span>
</div> </div>
<button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button> <button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button>
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh and rescan directory" aria-label="Refresh" style="font-size:1.1rem;"></button> <button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh and rescan directory" aria-label="Refresh" style="font-size:1.1rem;"></button>
@ -4396,15 +4396,23 @@ X.B(E,Y);return E}return J}())
* Cross-tool helpers for previewing file types that need a decoder: * Cross-tool helpers for previewing file types that need a decoder:
* - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar * - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar
* - ZIP listing (JSZip) — sortable file-list view * - ZIP listing (JSZip) — sortable file-list view
* - DOCX (docx-preview) — Word-styled pages in a scroll container
* - XLSX/XLS (SheetJS) — sheet-to-HTML table with a sheet tab bar
* *
* Renderers operate on any document (parent window or popup window), so the * Renderers operate on any document (parent window or popup window), so the
* same code works for tools whose preview opens in a popup (classifier, * same code works for tools whose preview opens in a popup (classifier,
* archive, transmittal) and tools that render inline (browse). * archive, transmittal) and tools that render inline (browse).
* *
* The DOCX/XLSX renderers expect their vendor lib bundled by the calling
* tool's build.sh (docx-preview.min.js → window.docx, xlsx.full.min.js →
* window.XLSX); they degrade to a friendly message if it isn't present.
*
* Public API on window.zddc.preview: * Public API on window.zddc.preview:
* loadLibrary(url) → Promise<void> * loadLibrary(url) → Promise<void>
* renderTiff(doc, container, arrayBuffer, opts) → Promise<void> * renderTiff(doc, container, arrayBuffer, opts) → Promise<void>
* renderZipListing(doc, container, arrayBuffer, opts) → Promise<void> * renderZipListing(doc, container, arrayBuffer, opts) → Promise<void>
* renderDocx(doc, container, arrayBuffer, opts) → Promise<void>
* renderXlsx(doc, container, arrayBuffer, opts) → Promise<void>
* TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS * TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS
* isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext) * isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext)
* *
@ -4917,6 +4925,111 @@ X.B(E,Y);return E}return J}())
}); });
} }
// ── DOCX (docx-preview) ────────────────────────────────────────────────
//
// docx-preview renders Word-styled pages with an intrinsic page width, so
// we wrap it in a scroll container: a wide document scrolls WITHIN the
// preview pane rather than pushing the page wider. docx-preview is bundled
// by the tools that opt in (each build.sh concatenates
// shared/vendor/docx-preview.min.js → window.docx).
var DOCX_CSS =
'.zddc-docx{height:100%;min-width:0;overflow:auto;'
+ 'background:var(--bg-secondary,#eee);padding:1rem;box-sizing:border-box;}'
+ '.zddc-docx .docx-wrapper{background:transparent;padding:0;}';
function renderDocx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-docx-styles', DOCX_CSS);
if (!window.docx || typeof window.docx.renderAsync !== 'function') {
container.innerHTML = '<div class="preview-empty">DOCX preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
container.innerHTML = '';
var scroll = doc.createElement('div');
scroll.className = 'zddc-docx';
container.appendChild(scroll);
return Promise.resolve(
window.docx.renderAsync(arrayBuffer, scroll, null, { inWrapper: true })
).catch(function (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render DOCX: ' + escapeHtml(err.message || err) + '</div>';
});
}
// ── XLSX / XLS (SheetJS) ───────────────────────────────────────────────
//
// Reads the workbook and renders the active sheet to an HTML table; a tab
// bar switches sheets when there's more than one. SheetJS is bundled by
// the tools that opt in (shared/vendor/xlsx.full.min.js → window.XLSX).
var XLSX_CSS =
'.zddc-xlsx{display:flex;flex-direction:column;height:100%;min-width:0;'
+ 'min-height:0;overflow:hidden;}'
+ '.zddc-xlsx__tabs{display:flex;flex-wrap:wrap;gap:0.25rem;padding:0.4rem;'
+ 'border-bottom:1px solid var(--border,#ccc);flex:0 0 auto;}'
+ '.zddc-xlsx__tab{padding:0.2rem 0.6rem;border:1px solid var(--border,#ccc);'
+ 'border-radius:4px;background:var(--bg,#fff);color:var(--text,#222);'
+ 'cursor:pointer;font-size:0.85rem;}'
+ '.zddc-xlsx__tab.is-active{background:var(--primary,#2563eb);color:#fff;'
+ 'border-color:var(--primary,#2563eb);}'
+ '.zddc-xlsx__body{flex:1 1 auto;min-width:0;min-height:0;overflow:auto;}'
+ '.zddc-xlsx__body table{border-collapse:collapse;font-size:0.85rem;'
+ 'color:var(--text,#222);}'
+ '.zddc-xlsx__body td,.zddc-xlsx__body th{border:1px solid var(--border,#ddd);'
+ 'padding:0.2rem 0.45rem;white-space:nowrap;}';
function renderXlsx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-xlsx-styles', XLSX_CSS);
if (!window.XLSX || typeof window.XLSX.read !== 'function') {
container.innerHTML = '<div class="preview-empty">Spreadsheet preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
try {
var wb = window.XLSX.read(arrayBuffer, { type: 'array' });
container.innerHTML = '';
var rootEl = doc.createElement('div');
rootEl.className = 'zddc-xlsx';
var body = doc.createElement('div');
body.className = 'zddc-xlsx__body';
function showSheet(name) {
var sheet = wb.Sheets[name];
body.innerHTML = sheet
? window.XLSX.utils.sheet_to_html(sheet, { editable: false })
: '';
}
if (wb.SheetNames.length > 1) {
var tabs = doc.createElement('div');
tabs.className = 'zddc-xlsx__tabs';
wb.SheetNames.forEach(function (name, i) {
var btn = doc.createElement('button');
btn.className = 'zddc-xlsx__tab' + (i === 0 ? ' is-active' : '');
btn.textContent = name;
btn.addEventListener('click', function () {
var all = tabs.querySelectorAll('.zddc-xlsx__tab');
for (var j = 0; j < all.length; j++) all[j].classList.remove('is-active');
btn.classList.add('is-active');
showSheet(name);
});
tabs.appendChild(btn);
});
rootEl.appendChild(tabs);
}
rootEl.appendChild(body);
container.appendChild(rootEl);
showSheet(wb.SheetNames[0]);
} catch (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render spreadsheet: ' + escapeHtml(err.message || err) + '</div>';
}
return Promise.resolve();
}
// ── Public API ─────────────────────────────────────────────────────────── // ── Public API ───────────────────────────────────────────────────────────
if (!root.zddc) root.zddc = {}; if (!root.zddc) root.zddc = {};
@ -4933,6 +5046,8 @@ X.B(E,Y);return E}return J}())
loadLibrary: loadLibrary, loadLibrary: loadLibrary,
renderTiff: renderTiff, renderTiff: renderTiff,
renderZipListing: renderZipListing, renderZipListing: renderZipListing,
renderDocx: renderDocx,
renderXlsx: renderXlsx,
formatSize: formatSize, formatSize: formatSize,
formatDate: formatDate formatDate: formatDate
}; };

View file

@ -1536,7 +1536,7 @@ body {
</svg> </svg>
<div class="header-title-group"> <div class="header-title-group">
<span class="app-header__title">ZDDC</span> <span class="app-header__title">ZDDC</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4</span></span> <span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b</span></span>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">

View file

@ -2635,7 +2635,7 @@ dialog.modal--narrow {
</svg> </svg>
<div class="header-title-group"> <div class="header-title-group">
<span class="app-header__title">ZDDC Transmittal</span> <span class="app-header__title">ZDDC Transmittal</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4</span></span> <span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b</span></span>
</div> </div>
<span id="no-js-notice" class="text-gray-400 text-xs italic">JavaScript not available</span> <span id="no-js-notice" class="text-gray-400 text-xs italic">JavaScript not available</span>
<!-- Publish split-button (Transmittal-specific primary action; <!-- Publish split-button (Transmittal-specific primary action;
@ -5452,15 +5452,23 @@ X.B(E,Y);return E}return J}())
* Cross-tool helpers for previewing file types that need a decoder: * Cross-tool helpers for previewing file types that need a decoder:
* - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar * - TIFF (UTIF.js) — multi-page, browser-PDF-viewer-style toolbar
* - ZIP listing (JSZip) — sortable file-list view * - ZIP listing (JSZip) — sortable file-list view
* - DOCX (docx-preview) — Word-styled pages in a scroll container
* - XLSX/XLS (SheetJS) — sheet-to-HTML table with a sheet tab bar
* *
* Renderers operate on any document (parent window or popup window), so the * Renderers operate on any document (parent window or popup window), so the
* same code works for tools whose preview opens in a popup (classifier, * same code works for tools whose preview opens in a popup (classifier,
* archive, transmittal) and tools that render inline (browse). * archive, transmittal) and tools that render inline (browse).
* *
* The DOCX/XLSX renderers expect their vendor lib bundled by the calling
* tool's build.sh (docx-preview.min.js → window.docx, xlsx.full.min.js →
* window.XLSX); they degrade to a friendly message if it isn't present.
*
* Public API on window.zddc.preview: * Public API on window.zddc.preview:
* loadLibrary(url) → Promise<void> * loadLibrary(url) → Promise<void>
* renderTiff(doc, container, arrayBuffer, opts) → Promise<void> * renderTiff(doc, container, arrayBuffer, opts) → Promise<void>
* renderZipListing(doc, container, arrayBuffer, opts) → Promise<void> * renderZipListing(doc, container, arrayBuffer, opts) → Promise<void>
* renderDocx(doc, container, arrayBuffer, opts) → Promise<void>
* renderXlsx(doc, container, arrayBuffer, opts) → Promise<void>
* TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS * TIFF_EXTENSIONS, IMAGE_EXTENSIONS, TEXT_EXTENSIONS, OFFICE_EXTENSIONS
* isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext) * isTiff(ext), isImage(ext), isText(ext), isZip(ext), isOffice(ext)
* *
@ -5973,6 +5981,111 @@ X.B(E,Y);return E}return J}())
}); });
} }
// ── DOCX (docx-preview) ────────────────────────────────────────────────
//
// docx-preview renders Word-styled pages with an intrinsic page width, so
// we wrap it in a scroll container: a wide document scrolls WITHIN the
// preview pane rather than pushing the page wider. docx-preview is bundled
// by the tools that opt in (each build.sh concatenates
// shared/vendor/docx-preview.min.js → window.docx).
var DOCX_CSS =
'.zddc-docx{height:100%;min-width:0;overflow:auto;'
+ 'background:var(--bg-secondary,#eee);padding:1rem;box-sizing:border-box;}'
+ '.zddc-docx .docx-wrapper{background:transparent;padding:0;}';
function renderDocx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-docx-styles', DOCX_CSS);
if (!window.docx || typeof window.docx.renderAsync !== 'function') {
container.innerHTML = '<div class="preview-empty">DOCX preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
container.innerHTML = '';
var scroll = doc.createElement('div');
scroll.className = 'zddc-docx';
container.appendChild(scroll);
return Promise.resolve(
window.docx.renderAsync(arrayBuffer, scroll, null, { inWrapper: true })
).catch(function (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render DOCX: ' + escapeHtml(err.message || err) + '</div>';
});
}
// ── XLSX / XLS (SheetJS) ───────────────────────────────────────────────
//
// Reads the workbook and renders the active sheet to an HTML table; a tab
// bar switches sheets when there's more than one. SheetJS is bundled by
// the tools that opt in (shared/vendor/xlsx.full.min.js → window.XLSX).
var XLSX_CSS =
'.zddc-xlsx{display:flex;flex-direction:column;height:100%;min-width:0;'
+ 'min-height:0;overflow:hidden;}'
+ '.zddc-xlsx__tabs{display:flex;flex-wrap:wrap;gap:0.25rem;padding:0.4rem;'
+ 'border-bottom:1px solid var(--border,#ccc);flex:0 0 auto;}'
+ '.zddc-xlsx__tab{padding:0.2rem 0.6rem;border:1px solid var(--border,#ccc);'
+ 'border-radius:4px;background:var(--bg,#fff);color:var(--text,#222);'
+ 'cursor:pointer;font-size:0.85rem;}'
+ '.zddc-xlsx__tab.is-active{background:var(--primary,#2563eb);color:#fff;'
+ 'border-color:var(--primary,#2563eb);}'
+ '.zddc-xlsx__body{flex:1 1 auto;min-width:0;min-height:0;overflow:auto;}'
+ '.zddc-xlsx__body table{border-collapse:collapse;font-size:0.85rem;'
+ 'color:var(--text,#222);}'
+ '.zddc-xlsx__body td,.zddc-xlsx__body th{border:1px solid var(--border,#ddd);'
+ 'padding:0.2rem 0.45rem;white-space:nowrap;}';
function renderXlsx(doc, container, arrayBuffer, opts) {
opts = opts || {};
injectStyles(doc, 'zddc-xlsx-styles', XLSX_CSS);
if (!window.XLSX || typeof window.XLSX.read !== 'function') {
container.innerHTML = '<div class="preview-empty">Spreadsheet preview unavailable '
+ '(renderer not bundled in this tool).</div>';
return Promise.resolve();
}
try {
var wb = window.XLSX.read(arrayBuffer, { type: 'array' });
container.innerHTML = '';
var rootEl = doc.createElement('div');
rootEl.className = 'zddc-xlsx';
var body = doc.createElement('div');
body.className = 'zddc-xlsx__body';
function showSheet(name) {
var sheet = wb.Sheets[name];
body.innerHTML = sheet
? window.XLSX.utils.sheet_to_html(sheet, { editable: false })
: '';
}
if (wb.SheetNames.length > 1) {
var tabs = doc.createElement('div');
tabs.className = 'zddc-xlsx__tabs';
wb.SheetNames.forEach(function (name, i) {
var btn = doc.createElement('button');
btn.className = 'zddc-xlsx__tab' + (i === 0 ? ' is-active' : '');
btn.textContent = name;
btn.addEventListener('click', function () {
var all = tabs.querySelectorAll('.zddc-xlsx__tab');
for (var j = 0; j < all.length; j++) all[j].classList.remove('is-active');
btn.classList.add('is-active');
showSheet(name);
});
tabs.appendChild(btn);
});
rootEl.appendChild(tabs);
}
rootEl.appendChild(body);
container.appendChild(rootEl);
showSheet(wb.SheetNames[0]);
} catch (err) {
container.innerHTML = '<div class="preview-empty" style="color:var(--danger,#c00)">'
+ 'Failed to render spreadsheet: ' + escapeHtml(err.message || err) + '</div>';
}
return Promise.resolve();
}
// ── Public API ─────────────────────────────────────────────────────────── // ── Public API ───────────────────────────────────────────────────────────
if (!root.zddc) root.zddc = {}; if (!root.zddc) root.zddc = {};
@ -5989,6 +6102,8 @@ X.B(E,Y);return E}return J}())
loadLibrary: loadLibrary, loadLibrary: loadLibrary,
renderTiff: renderTiff, renderTiff: renderTiff,
renderZipListing: renderZipListing, renderZipListing: renderZipListing,
renderDocx: renderDocx,
renderXlsx: renderXlsx,
formatSize: formatSize, formatSize: formatSize,
formatDate: formatDate formatDate: formatDate
}; };

View file

@ -1,8 +1,8 @@
# Generated by build.sh — do not edit. One <app>=<build label> per line. # Generated by build.sh — do not edit. One <app>=<build label> per line.
archive=v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4 archive=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
transmittal=v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4 transmittal=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
classifier=v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4 classifier=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
landing=v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4 landing=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
form=v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4 form=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
tables=v0.0.27-beta · 2026-06-02 19:01:23 · af07fa4 tables=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b
browse=v0.0.27-beta · 2026-06-02 19:01:23 · af07fa4 browse=v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b

View file

@ -1534,7 +1534,7 @@ body.is-elevated::after {
</svg> </svg>
<div class="header-title-group"> <div class="header-title-group">
<span class="app-header__title" id="table-title">ZDDC Table</span> <span class="app-header__title" id="table-title">ZDDC Table</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-02 19:01:23 · af07fa4</span></span> <span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.27-beta · 2026-06-03 13:55:32 · 3e8737b</span></span>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">