feat(editor): show fps/codec/resolution/duration in media panel asset list
- Add two-line layout to media panel items: name on top, metadata below - fmtMs() converts duration_ms to MM:SS or HH:MM:SS for display - Meta line shows resolution · codec · fps · duration, skipping null fields - Assets with no extracted metadata (no proxy yet) show name only - Active item meta line inherits accent color at reduced opacity
This commit is contained in:
parent
508cf8d41b
commit
660afb94bb
1 changed files with 53 additions and 4 deletions
|
|
@ -120,19 +120,43 @@
|
||||||
|
|
||||||
.media-asset-item {
|
.media-asset-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: var(--sp-2);
|
gap: var(--sp-2);
|
||||||
padding: var(--sp-2) var(--sp-3);
|
padding: var(--sp-2) var(--sp-3);
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background var(--t-fast), color var(--t-fast);
|
transition: background var(--t-fast), color var(--t-fast);
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
.media-asset-item svg { flex-shrink: 0; margin-top: 2px; }
|
||||||
.media-asset-item:hover { background: var(--bg-hover); color: var(--text-primary); }
|
.media-asset-item:hover { background: var(--bg-hover); color: var(--text-primary); }
|
||||||
.media-asset-item.active { background: var(--accent-subtle); color: var(--accent); }
|
.media-asset-item.active { background: var(--accent-subtle); color: var(--accent); }
|
||||||
.media-asset-item span { overflow: hidden; text-overflow: ellipsis; }
|
|
||||||
|
.media-asset-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-asset-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-asset-meta {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.media-asset-item.active .media-asset-meta { color: var(--accent); opacity: 0.7; }
|
||||||
|
|
||||||
/* ── Timeline panel ────────────────────────────────────────── */
|
/* ── Timeline panel ────────────────────────────────────────── */
|
||||||
.timeline-panel {
|
.timeline-panel {
|
||||||
|
|
@ -481,18 +505,43 @@ async function loadMediaAssets() {
|
||||||
renderMediaList();
|
renderMediaList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fmtMs(ms) {
|
||||||
|
if (!ms || ms <= 0) return null;
|
||||||
|
const s = Math.floor(ms / 1000);
|
||||||
|
const h = Math.floor(s / 3600);
|
||||||
|
const m = Math.floor((s % 3600) / 60);
|
||||||
|
const sc = s % 60;
|
||||||
|
if (h > 0) return [h, m, sc].map(v => String(v).padStart(2,'0')).join(':');
|
||||||
|
return [m, sc].map(v => String(v).padStart(2,'0')).join(':');
|
||||||
|
}
|
||||||
|
|
||||||
function renderMediaList() {
|
function renderMediaList() {
|
||||||
const list = document.getElementById('mediaAssetList');
|
const list = document.getElementById('mediaAssetList');
|
||||||
list.innerHTML = '';
|
list.innerHTML = '';
|
||||||
state.assets.forEach(function(asset) {
|
state.assets.forEach(function(asset) {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'media-asset-item';
|
el.className = 'media-asset-item';
|
||||||
|
|
||||||
|
const metaParts = [
|
||||||
|
asset.resolution || null,
|
||||||
|
asset.codec || null,
|
||||||
|
asset.fps ? asset.fps + ' fps' : null,
|
||||||
|
fmtMs(asset.duration_ms),
|
||||||
|
].filter(Boolean);
|
||||||
|
const metaStr = metaParts.join(' · ');
|
||||||
|
|
||||||
el.innerHTML =
|
el.innerHTML =
|
||||||
'<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.3" width="12" height="12">' +
|
'<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.3" width="12" height="12">' +
|
||||||
'<rect x="1" y="3" width="8" height="8" rx="1"/>' +
|
'<rect x="1" y="3" width="8" height="8" rx="1"/>' +
|
||||||
'<path d="M9 6l4-2v6l-4-2"/>' +
|
'<path d="M9 6l4-2v6l-4-2"/>' +
|
||||||
'</svg>' +
|
'</svg>' +
|
||||||
'<span title="' + esc(asset.display_name || asset.filename) + '">' + esc(asset.display_name || asset.filename) + '</span>';
|
'<div class="media-asset-info">' +
|
||||||
|
'<span class="media-asset-name" title="' + esc(asset.display_name || asset.filename) + '">' +
|
||||||
|
esc(asset.display_name || asset.filename) +
|
||||||
|
'</span>' +
|
||||||
|
(metaStr ? '<span class="media-asset-meta">' + esc(metaStr) + '</span>' : '') +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
el.ondblclick = function() { loadSourceAsset(asset); };
|
el.ondblclick = function() { loadSourceAsset(asset); };
|
||||||
el.onclick = function() {
|
el.onclick = function() {
|
||||||
list.querySelectorAll('.media-asset-item').forEach(function(e) { e.classList.remove('active'); });
|
list.querySelectorAll('.media-asset-item').forEach(function(e) { e.classList.remove('active'); });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue