feat: Add visual scrubber to video editor
Task #69 completed by ClaudeQueue ClaudeQueue
This commit is contained in:
@@ -745,6 +745,11 @@ function openVideoEditor(source) {
|
|||||||
body.className = 'video-editor';
|
body.className = 'video-editor';
|
||||||
body.innerHTML = `
|
body.innerHTML = `
|
||||||
<p class="ve-intro">Mark the parts to <strong>remove</strong>. Everything else is kept and saved as a new offline video.</p>
|
<p class="ve-intro">Mark the parts to <strong>remove</strong>. Everything else is kept and saved as a new offline video.</p>
|
||||||
|
<div class="ve-scrubber-track">
|
||||||
|
<div class="ve-scrubber-bar"></div>
|
||||||
|
<div class="ve-marker ve-marker-a"></div>
|
||||||
|
<div class="ve-marker ve-marker-b"></div>
|
||||||
|
</div>
|
||||||
<div class="ve-add-row">
|
<div class="ve-add-row">
|
||||||
<label>From <input type="text" class="ve-from" placeholder="0:30" inputmode="numeric" /></label>
|
<label>From <input type="text" class="ve-from" placeholder="0:30" inputmode="numeric" /></label>
|
||||||
<label>To <input type="text" class="ve-to" placeholder="1:15" inputmode="numeric" /></label>
|
<label>To <input type="text" class="ve-to" placeholder="1:15" inputmode="numeric" /></label>
|
||||||
@@ -762,8 +767,33 @@ function openVideoEditor(source) {
|
|||||||
const cutsEl = body.querySelector('.ve-cuts');
|
const cutsEl = body.querySelector('.ve-cuts');
|
||||||
const titleEl = body.querySelector('.ve-title');
|
const titleEl = body.querySelector('.ve-title');
|
||||||
const sumEl = body.querySelector('.ve-summary');
|
const sumEl = body.querySelector('.ve-summary');
|
||||||
|
const trackEl = body.querySelector('.ve-scrubber-track');
|
||||||
|
const markerA = body.querySelector('.ve-marker-a');
|
||||||
|
const markerB = body.querySelector('.ve-marker-b');
|
||||||
|
|
||||||
titleEl.value = (source.title || 'Video') + ' (edit)';
|
titleEl.value = (source.title || 'Video') + ' (edit)';
|
||||||
|
|
||||||
|
// Update markers based on duration
|
||||||
|
function updateScrubber() {
|
||||||
|
const a = VideoEdit.parseTime(fromEl.value);
|
||||||
|
const b = VideoEdit.parseTime(toEl.value);
|
||||||
|
|
||||||
|
if (a !== null) markerA.style.left = (a / duration * 100) + '%';
|
||||||
|
if (b !== null) markerB.style.left = (b / duration * 100) + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
trackEl.onclick = (e) => {
|
||||||
|
const rect = trackEl.getBoundingClientRect();
|
||||||
|
const percent = (e.clientX - rect.left) / rect.width;
|
||||||
|
const time = Math.round(percent * duration);
|
||||||
|
if (!fromEl.value) fromEl.value = VideoEdit.fmtTime(time);
|
||||||
|
else if (!toEl.value) toEl.value = VideoEdit.fmtTime(time);
|
||||||
|
updateScrubber();
|
||||||
|
};
|
||||||
|
|
||||||
|
fromEl.oninput = updateScrubber;
|
||||||
|
toEl.oninput = updateScrubber;
|
||||||
|
|
||||||
function showErr(msg) {
|
function showErr(msg) {
|
||||||
errEl.textContent = msg;
|
errEl.textContent = msg;
|
||||||
errEl.hidden = !msg;
|
errEl.hidden = !msg;
|
||||||
|
|||||||
@@ -2259,3 +2259,29 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
|
|||||||
box-shadow: 0 2px 6px -2px var(--accent-glow);
|
box-shadow: 0 2px 6px -2px var(--accent-glow);
|
||||||
}
|
}
|
||||||
.saved-card.custom .thumb { position: relative; }
|
.saved-card.custom .thumb { position: relative; }
|
||||||
|
|
||||||
|
/* Video Editor Scrubber */
|
||||||
|
.ve-scrubber-track {
|
||||||
|
height: 30px;
|
||||||
|
background: var(--bg-3);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.ve-scrubber-bar {
|
||||||
|
height: 100%;
|
||||||
|
background: var(--bg-2);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
}
|
||||||
|
.ve-marker {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 4px;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--accent);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.ve-marker-a { left: 0; }
|
||||||
|
.ve-marker-b { right: 0; }
|
||||||
|
|||||||
Reference in New Issue
Block a user