106 lines
3.3 KiB
JavaScript
106 lines
3.3 KiB
JavaScript
|
|
// 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 = '<div class="empty muted">Loading…</div>';
|
||
|
|
try {
|
||
|
|
const data = await API.listAssets(query);
|
||
|
|
Library.state.assets = (data && (data.assets || data.rows)) || [];
|
||
|
|
Library.render();
|
||
|
|
} catch (e) {
|
||
|
|
grid.innerHTML = '';
|
||
|
|
const err = document.createElement('div');
|
||
|
|
err.className = 'empty muted';
|
||
|
|
err.textContent = 'Error loading assets: ' + e.message;
|
||
|
|
grid.appendChild(err);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
window.Library = Library;
|
||
|
|
})();
|