diff --git a/archive/build.sh b/archive/build.sh
index 4f6d344..9d7d6cd 100644
--- a/archive/build.sh
+++ b/archive/build.sh
@@ -32,6 +32,7 @@ concat_files \
"../shared/zddc.js" \
"../shared/hash.js" \
"../shared/theme.js" \
+ "../shared/preview-lib.js" \
"js/init.js" \
"js/parser.js" \
"js/source.js" \
diff --git a/archive/js/table.js b/archive/js/table.js
index 5e9a5a2..2b34320 100644
--- a/archive/js/table.js
+++ b/archive/js/table.js
@@ -9,7 +9,17 @@
const processedLinks = new WeakSet();
let fileLinkHandlersAttached = false;
let filePreviewWindow = null;
- const PREVIEW_EXTENSIONS = ['pdf', 'docx', 'xlsx', 'xls'];
+ // All extensions previewable in the popup. Image / tiff / zip / text routed
+ // through #previewContent below; pdf gets a direct iframe; docx/xlsx use
+ // dedicated lazy-loaded renderers.
+ const PREVIEW_EXTENSIONS = [
+ 'pdf',
+ 'docx', 'xlsx', 'xls',
+ ...zddc.preview.IMAGE_EXTENSIONS,
+ ...zddc.preview.TIFF_EXTENSIONS,
+ ...zddc.preview.TEXT_EXTENSIONS,
+ 'zip'
+ ];
const loadedLibraries = new Map();
let resizing = null;
@@ -445,6 +455,24 @@
}
/* docx-preview container */
.docx-wrapper { padding: 1rem; }
+ /* Image preview */
+ img.preview-image {
+ max-width: 100%;
+ max-height: 100%;
+ display: block;
+ margin: auto;
+ object-fit: contain;
+ }
+ /* Text preview */
+ pre.preview-text {
+ padding: 1rem;
+ font-family: 'Consolas', 'Monaco', monospace;
+ font-size: 0.85rem;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ color: var(--text);
+ background: var(--bg);
+ }
/* xlsx table styling */
.xlsx-table { border-collapse: collapse; width: 100%; font-size: 0.85rem; }
.xlsx-table th, .xlsx-table td {
@@ -529,8 +557,16 @@
await renderDocxInWindow(file);
} else if (ext === 'xlsx' || ext === 'xls') {
await renderXlsxInWindow(file);
+ } else if (zddc.preview.isTiff(ext)) {
+ await renderTiffInWindow(file);
+ } else if (zddc.preview.isZip(ext)) {
+ await renderZipInWindow(file);
+ } else if (zddc.preview.isImage(ext)) {
+ renderImageInWindow(file, url);
+ } else if (zddc.preview.isText(ext)) {
+ await renderTextInWindow(file);
}
-
+
} catch (err) {
console.error('Error loading file preview:', err);
alert(`Error loading preview: ${err.message}`);
@@ -619,6 +655,91 @@
if (table) table.className = 'xlsx-table';
}
+ async function _getFileArrayBuffer(file) {
+ if (file.handle) {
+ const f = await file.handle.getFile();
+ return f.arrayBuffer();
+ }
+ if (file.url) {
+ const r = await fetch(file.url);
+ if (!r.ok) throw new Error('HTTP ' + r.status);
+ return r.arrayBuffer();
+ }
+ throw new Error('No file source available');
+ }
+
+ /**
+ * Render an image (non-tiff) directly using the popup's element.
+ * The browser handles decoding for jpg/jpeg/png/gif/webp/bmp/svg/ico natively.
+ */
+ function renderImageInWindow(file, url) {
+ const container = filePreviewWindow.document.getElementById('previewContent');
+ if (!container) return;
+ container.innerHTML = '';
+ const img = filePreviewWindow.document.createElement('img');
+ img.className = 'preview-image';
+ img.src = url;
+ img.alt = file.name || '';
+ container.appendChild(img);
+ }
+
+ /**
+ * Render a TIFF using the shared zddc.preview.renderTiff helper (UTIF.js).
+ */
+ async function renderTiffInWindow(file) {
+ const container = filePreviewWindow.document.getElementById('previewContent');
+ if (!container) return;
+ try {
+ const arrayBuffer = await _getFileArrayBuffer(file);
+ await zddc.preview.renderTiff(filePreviewWindow.document, container, arrayBuffer, {
+ fileName: file.name
+ });
+ } catch (err) {
+ console.error('Error rendering TIFF:', err);
+ container.innerHTML = `
${escapeHtml(displayText)}`;
case 'docx':
case 'xlsx':
+ case 'tiff':
+ case 'zip':
return `