// Asset library rendering. Calls API.listAssets, renders a grid into // #asset-grid, tracks the selected asset for the action buttons. (function () { const Library = {}; Library.state = { assets: [], selectedId: null }; Library.render = function () { const grid = UI.$('#asset-grid'); grid.innerHTML = ''; if (!Library.state.assets.length) { const e = document.createElement('div'); e.className = 'empty muted'; e.textContent = 'No assets'; grid.appendChild(e); return; } for (const a of Library.state.assets) { grid.appendChild(makeCard(a)); } Library.syncActions(); }; function makeCard(asset) { const card = document.createElement('div'); card.className = 'asset-card'; if (asset.id === Library.state.selectedId) card.classList.add('selected'); card.dataset.assetId = asset.id; const thumbKey = asset.thumbnail_s3_key || asset.thumbnail || null; const thumbUrl = thumbKey ? `${API.state.serverUrl}/api/v1/assets/${asset.id}/thumbnail?redirect=1` : null; if (thumbUrl) { const img = document.createElement('img'); img.className = 'asset-thumb'; img.alt = asset.display_name || asset.filename || asset.id; // UXP fetch supports cross-origin images; the redirect=1 query on // /thumbnail tells the server to 302 to the presigned S3 URL. img.src = thumbUrl; img.onerror = () => { img.replaceWith(placeholder()); }; card.appendChild(img); } else { card.appendChild(placeholder()); } const name = document.createElement('div'); name.className = 'asset-name'; name.textContent = asset.display_name || asset.filename || asset.id; card.appendChild(name); card.addEventListener('click', () => Library.select(asset.id)); return card; } function placeholder() { const p = document.createElement('div'); p.className = 'asset-thumb-placeholder'; p.textContent = 'no preview'; return p; } Library.select = function (id) { Library.state.selectedId = id; Library.render(); }; Library.selectedAsset = function () { return Library.state.assets.find(a => a.id === Library.state.selectedId) || null; }; Library.syncActions = function () { const sel = Library.selectedAsset(); const info = UI.$('#selected-info'); if (sel) { info.textContent = (sel.display_name || sel.filename || sel.id) + (sel.file_size ? ' · ' + UI.formatBytes(Number(sel.file_size)) : ''); info.classList.remove('muted'); } else { info.textContent = 'No asset selected'; info.classList.add('muted'); } UI.$('#import-proxy-btn').disabled = !sel; UI.$('#import-hires-btn').disabled = !sel || !sel.original_s3_key; }; Library.refresh = async function (query) { const grid = UI.$('#asset-grid'); grid.innerHTML = '