Office: search, kind filter, sorting, pinned and recent documents, saved list, upload and drag-and-drop, document menu; Movies & TV mini player keeps its controls visible

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-22 11:18:48 -04:00
1 parent 1f08443c38
commit 2bde697955
9 files changed
+147 -56

No files matched your search

+15 -5
View File
@@ -220,7 +220,9 @@ function vdUi() {
if (r) { if (!drag) r.value = t ? Math.round(1000 * Math.min(p, t) / t) : 0; const shown = drag ? r.value / 1000 * t : p; $('#vcur').textContent = vdClock(shown); $('#vrem').textContent = '-' + vdClock(Math.max(0, t - shown)); }
const pp = $('#vpp'); if (pp) { pp.innerHTML = icon(el.paused ? 'play' : 'pause'); pp.setAttribute('aria-label', el.paused ? 'Play' : 'Pause'); }
const pv = $('#vprev'), nx = $('#vnextep'); if (pv) pv.disabled = !vp.sibs || vp.sibIdx <= 0; if (nx) nx.disabled = !vp.sibs || vp.sibIdx < 0 || vp.sibIdx >= vp.sibs.length - 1;
const mp = $('#vmpp'); if (mp) mp.innerHTML = icon(el.paused ? 'play' : 'pause'); const pr = $('#vmprog b'); if (pr) pr.style.width = (t ? Math.min(100, 100 * p / t) : 0) + '%';
const mp = $('#vmpp'); if (mp) { mp.innerHTML = icon(el.paused ? 'play' : 'pause'); mp.setAttribute('aria-label', el.paused ? 'Play' : 'Pause'); }
const mr = $('#vmrange'); if (mr) { const d = vp.miniDrag; if (!d) mr.value = t ? Math.round(1000 * Math.min(p, t) / t) : 0; const shown = d ? mr.value / 1000 * t : p; $('#vmcur').textContent = vdClock(shown); $('#vmrem').textContent = '-' + vdClock(Math.max(0, t - shown)); }
const mpv = $('#vmprev'), mnx = $('#vmnext'); if (mpv) mpv.disabled = !vp.sibs || vp.sibIdx <= 0; if (mnx) mnx.disabled = !vp.sibs || vp.sibIdx < 0 || vp.sibIdx >= vp.sibs.length - 1;
}
/** The mini player: the video keeps playing in a small window while you use other tabs. */
function videoMini(on) {
@@ -229,14 +231,22 @@ function videoMini(on) {
if (!vp || !vp.el) return;
if (!box) {
box = document.createElement('div'); box.id = 'vmini'; box.setAttribute('role', 'region'); box.setAttribute('aria-label', 'Video mini player');
box.innerHTML = `<div class="vmslot"></div><div class="vmover"><b class="vmtitle"></b><div class="vmbtns"><button id="vmpp" aria-label="Play or pause"></button><button id="vmx" aria-label="Back to the player">${icon('full')}</button><button id="vmc" aria-label="Close">${icon('x')}</button></div></div><i class="vmprog" id="vmprog"><b></b></i>`;
box.innerHTML = `<div class="vmslot"></div><div class="vmctl">
<div class="vmhead"><b class="vmtitle"></b><button class="vmb" id="vmx" aria-label="Back to the player" title="Back to the player">${icon('full')}</button><button class="vmb" id="vmc" aria-label="Close" title="Close">${icon('x')}</button></div>
<input type="range" id="vmrange" min="0" max="1000" step="1" value="0" aria-label="Seek">
<div class="vmrow"><span id="vmcur">0:00</span><div class="vmmid"><button class="vmb" id="vmprev" aria-label="Previous episode" title="Previous episode" hidden>${icon('prev')}</button><button class="vmb" id="vmb10" aria-label="Back 10 seconds" title="Back 10 seconds"><span class="vskip">${icon('rew')}<em>10</em></span></button><button class="vmb big" id="vmpp" aria-label="Play or pause"></button><button class="vmb" id="vmf10" aria-label="Forward 10 seconds" title="Forward 10 seconds"><span class="vskip">${icon('fwd')}<em>10</em></span></button><button class="vmb" id="vmnext" aria-label="Next episode" title="Next episode" hidden>${icon('next')}</button></div><span id="vmrem">-0:00</span></div></div>`;
document.body.appendChild(box);
box.querySelector('#vmpp').onclick = e => { e.stopPropagation(); const el = vp && vp.el; if (el) el.paused ? el.play().catch(() => {}) : el.pause(); };
box.querySelector('#vmc').onclick = e => { e.stopPropagation(); videoStop(); };
const q = s => box.querySelector(s), stop = f => e => { e.stopPropagation(); f(e); };
q('#vmpp').onclick = stop(() => { const el = vp && vp.el; if (el) el.paused ? el.play().catch(() => {}) : el.pause(); });
q('#vmc').onclick = stop(() => videoStop());
const open = () => { if (vp) location.hash = '#/video/watch/' + vp.id; };
box.querySelector('#vmx').onclick = e => { e.stopPropagation(); open(); }; box.querySelector('.vmslot').onclick = open;
q('#vmx').onclick = stop(open); q('.vmslot').onclick = open;
q('#vmb10').onclick = stop(() => videoSkip(-10)); q('#vmf10').onclick = stop(() => videoSkip(10));
q('#vmprev').onclick = stop(() => videoGo(-1)); q('#vmnext').onclick = stop(() => videoGo(1));
const r = q('#vmrange'); r.oninput = () => { vp && (vp.miniDrag = true); vdUi(); }; r.onchange = () => { if (!vp) return; const t = (vp.m.duration || 0) / 1000 || vp.el.duration || 0; videoSeek(r.value / 1000 * t); vp.miniDrag = false; };
}
box.hidden = false; box.querySelector('.vmtitle').textContent = vdTitle(vp.m);
const ep = vp.m.type === 'episode'; box.querySelector('#vmprev').hidden = !ep; box.querySelector('#vmnext').hidden = !ep;
vp.el.controls = false; box.querySelector('.vmslot').appendChild(vp.el); document.body.classList.remove('onvideo'); document.body.classList.remove('vfullwin');
const st = document.querySelector('.vstage.vfull'); if (st) st.classList.remove('vfull');
vdUi();