diff --git a/services/web-ui/public/editor.html b/services/web-ui/public/editor.html
index ce601d1..bccd830 100644
--- a/services/web-ui/public/editor.html
+++ b/services/web-ui/public/editor.html
@@ -112,6 +112,31 @@
color: var(--text-tertiary);
}
+ .media-panel-search {
+ padding: var(--sp-2) var(--sp-3);
+ border-bottom: 1px solid var(--border);
+ flex-shrink: 0;
+ }
+
+ .media-panel-search input {
+ width: 100%;
+ height: 24px;
+ padding: 0 var(--sp-2);
+ font-size: var(--text-xs);
+ background: var(--bg-surface);
+ border: 1px solid var(--border);
+ border-radius: var(--r-sm);
+ color: var(--text-primary);
+ outline: none;
+ box-sizing: border-box;
+ }
+ .media-panel-search input:focus {
+ border-color: var(--accent-border);
+ }
+ .media-panel-search input::placeholder {
+ color: var(--text-tertiary);
+ }
+
.media-asset-list {
flex: 1;
overflow-y: auto;
@@ -193,8 +218,27 @@
.tl-sep { width: 1px; height: 18px; background: var(--border); }
- .tl-save-status {
+ .tl-seq-info {
margin-left: auto;
+ display: flex;
+ align-items: center;
+ gap: var(--sp-3);
+ }
+
+ .tl-seq-duration {
+ font-size: var(--text-xs);
+ font-variant-numeric: tabular-nums;
+ font-family: var(--font-mono, monospace);
+ color: var(--text-secondary);
+ letter-spacing: .03em;
+ }
+
+ .tl-seq-fps {
+ font-size: var(--text-xs);
+ color: var(--text-tertiary);
+ }
+
+ .tl-save-status {
font-size: var(--text-xs);
color: var(--text-tertiary);
}
@@ -425,6 +469,9 @@
+
+
+
@@ -439,7 +486,11 @@
-
+
+
+
+
+
@@ -593,6 +644,11 @@ document.addEventListener('DOMContentLoaded', async () => {
});
})();
+ // Media search
+ document.getElementById('mediaSearch').addEventListener('input', function() {
+ renderMediaList();
+ });
+
await loadProject();
await loadSequences();
await loadMediaAssets();
@@ -641,8 +697,10 @@ async function openSequence(id) {
state.history = [cloneClips(state.seq.clips)];
state.historyIdx = 0;
document.getElementById('seqSelect').value = id;
- Timeline.render(state.seq.clips, { fps: state.seq.frame_rate || 59.94 });
+ const fps = parseFloat(state.seq.frame_rate) || 59.94;
+ Timeline.render(state.seq.clips, { fps });
updateProgramScrub();
+ updateSeqInfo();
}
// ════════════════════════════════════════════════════════════════
@@ -668,9 +726,23 @@ function fmtMs(ms) {
}
function renderMediaList() {
- const list = document.getElementById('mediaAssetList');
+ const list = document.getElementById('mediaAssetList');
+ const query = (document.getElementById('mediaSearch').value || '').trim().toLowerCase();
+ const assets = query
+ ? state.assets.filter(a =>
+ (a.display_name || '').toLowerCase().includes(query) ||
+ (a.filename || '').toLowerCase().includes(query))
+ : state.assets;
+
list.innerHTML = '';
- state.assets.forEach(function(asset) {
+
+ if (assets.length === 0) {
+ list.innerHTML = '' +
+ (query ? 'No clips match "' + esc(query) + '"' : 'No assets in this bin.') + '
';
+ return;
+ }
+
+ assets.forEach(function(asset) {
const el = document.createElement('div');
el.className = 'media-asset-item';
@@ -708,6 +780,23 @@ function renderMediaList() {
});
}
+// ════════════════════════════════════════════════════════════════
+// SEQUENCE INFO BADGE
+// ════════════════════════════════════════════════════════════════
+function updateSeqInfo() {
+ if (!state.seq) {
+ document.getElementById('seqDuration').textContent = '';
+ document.getElementById('seqFps').textContent = '';
+ return;
+ }
+ const fps = parseFloat(state.seq.frame_rate) || 59.94;
+ const clips = state.seq.clips || [];
+ const maxOut = clips.reduce(function(m, c) { return Math.max(m, c.timeline_out_frames || 0); }, 0);
+ const durTC = maxOut > 0 ? TC.framesToTC(maxOut) : '00:00:00;00';
+ document.getElementById('seqDuration').textContent = durTC;
+ document.getElementById('seqFps').textContent = fps + ' fps';
+}
+
// ════════════════════════════════════════════════════════════════
// SOURCE MONITOR
// ════════════════════════════════════════════════════════════════
@@ -920,6 +1009,7 @@ function onClipsChanged(clips) {
state.history.push(cloneClips(clips));
state.historyIdx = state.history.length - 1;
state.seq.clips = clips;
+ updateSeqInfo();
markDirty();
}
@@ -992,7 +1082,9 @@ function redo() {
function applyHistory() {
const clips = cloneClips(state.history[state.historyIdx]);
state.seq.clips = clips;
- Timeline.render(clips, { fps: state.seq.frame_rate || 59.94 });
+ const fps = parseFloat(state.seq.frame_rate) || 59.94;
+ Timeline.render(clips, { fps });
+ updateSeqInfo();
markDirty();
}
@@ -1077,7 +1169,7 @@ function toggleKbdHelp() {
}
document.addEventListener('DOMContentLoaded', function() {
- document.getElementById('closeKbdHelp').onclick = closeKbdHelp;
+ document.getElementById('closeKbdHelp').onclick = closeKbdHelp;
document.getElementById('kbdHelpBackdrop').onclick = closeKbdHelp;
});