diff --git a/vidflow.html b/vidflow.html index 3e991aa..d61ecb5 100644 --- a/vidflow.html +++ b/vidflow.html @@ -179,6 +179,22 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil /* URL form */ .url-hint{font-size:11px;color:var(--dim);margin-bottom:10px;line-height:1.6;letter-spacing:.3px} +.set-section{margin-bottom:20px} +.set-hd{font-size:10px;letter-spacing:2px;text-transform:uppercase;color:var(--dim);font-weight:700;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--border)} +.set-row{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.04)} +.set-lbl{font-size:13px;font-weight:600;letter-spacing:.3px} +.set-sub{font-size:10px;color:var(--dim);margin-top:2px;letter-spacing:.3px} +.tog{width:36px;height:20px;background:rgba(255,255,255,.1);border-radius:10px;position:relative;cursor:pointer;transition:.2s;flex-shrink:0;border:none} +.tog.on{background:var(--accent2)} +.tog::after{content:'';position:absolute;width:14px;height:14px;background:#fff;border-radius:50%;top:3px;left:3px;transition:.2s} +.tog.on::after{left:19px} +.set-vol{display:flex;align-items:center;gap:8px;padding:8px 0} +.set-vol input[type=range]{flex:1;-webkit-appearance:none;height:3px;background:rgba(255,255,255,.15);border-radius:2px;outline:none} +.set-vol input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--accent2);border-radius:50%;cursor:pointer} +.set-vol-lbl{font-size:11px;color:var(--dim);min-width:32px;text-align:right} +.set-key-row{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid rgba(255,255,255,.03)} +.set-key{font-family:var(--font-b);font-size:11px;color:var(--dim);letter-spacing:.3px} +.set-kbd{font-family:monospace;font-size:11px;color:var(--accent2);background:rgba(0,212,255,.08);padding:1px 6px;border-radius:3px} /* Empty state */ .empty{text-align:center;padding:36px 16px;color:var(--dim)} @@ -365,7 +381,8 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
MY LIST
SEARCH
-
ADD URL
+
ADD
+
SETTINGS
@@ -413,6 +430,8 @@ function sizePW(){ function onPReady(){ A.ready=true; hideLoad(); sizePW(); + const _vol=parseInt(localStorage.getItem('vf_volume')||'100'); + try{ A.player.setVolume(_vol); }catch(e){} // Popup: check for video transferred from main window if(window.opener){ try{ @@ -630,6 +649,7 @@ function renderTab(tab){ if(tab==='channels') renderChTab(); else if(tab==='search') renderSearchTab(); else if(tab==='add') renderAddTab(); + else if(tab==='settings') renderSettingsTab(); } function renderChTab(){ @@ -708,6 +728,74 @@ function renderAddTab(){ setTimeout(()=>inp.focus(),50); } +function renderSettingsTab(){ + const b=qs('#sb-body'); + const shuf=A.shuffled; + const vol=parseInt(localStorage.getItem('vf_volume')||'100'); + b.innerHTML=` +
+
API KEY
+
+
YouTube Data API v3 Key
+ ${A.apiKey?`
Current key: …${esc(A.apiKey.slice(-8))}
`:''} +
+ + +
+ ${A.apiKey?`
Clear key & restart
`:''} +
+
+
+
PLAYBACK
+
+
Shuffle
Play channels in random order
+ +
+
+
+
VOLUME
+
+ + ${vol}% +
+
+
+
KEYBOARD SHORTCUTS
+
Play / PauseSpace
+
Prev / Next video← →
+
Volume↑ ↓
+
Channel up / down+ -
+
ShuffleS
+
Channels panelC
+
Pop-out playerP
+
FullscreenF
+
Close panelEsc
+
`; + const keyIn=qs('#set-key-in'); + const doSaveKey=()=>{ + const k=keyIn.value.trim(); if(!k){ toast('Enter a key'); return; } + A.apiKey=k; save(); toast('Key saved'); renderSettingsTab(); + }; + qs('#set-key-save').onclick=doSaveKey; + keyIn.onkeydown=e=>{ if(e.key==='Enter') doSaveKey(); }; + const resetEl=qs('#set-key-reset'); + if(resetEl) resetEl.onclick=()=>{ if(confirm('Clear API key and restart?')){ localStorage.removeItem('vf_key'); location.reload(); } }; + qs('#tog-shuf').onclick=()=>{ + A.shuffled=!A.shuffled; + qs('#b-shuf').classList.toggle('act',A.shuffled); + try{ A.player?.setShuffle?.(A.shuffled); }catch(e){} + localStorage.setItem('vf_shuffle',A.shuffled); + qs('#tog-shuf').classList.toggle('on',A.shuffled); + }; + const volIn=qs('#set-vol-in'), volVal=qs('#set-vol-val'); + volIn.oninput=()=>{ + const v=parseInt(volIn.value); + volVal.textContent=v+'%'; + try{ A.player?.setVolume?.(v); }catch(e){} + localStorage.setItem('vf_volume',v); + }; +} + // ── NCO onboarding ── function initNCO(){ const demo=A.demo&&!A.apiKey; @@ -805,6 +893,7 @@ function loadState(){ A.apiKey=localStorage.getItem('vf_key')||''; try{ A.channels=JSON.parse(localStorage.getItem('vf_ch')||'[]'); }catch(e){ A.channels=[]; } A.cur=parseInt(localStorage.getItem('vf_cur')||'-1'); + A.shuffled = localStorage.getItem('vf_shuffle') !== 'false'; if(A.cur>=A.channels.length) A.cur=A.channels.length>0?0:-1; } @@ -868,9 +957,7 @@ function wireControls(){ if(!document.fullscreenElement) document.documentElement.requestFullscreen?.().catch(()=>{}); else document.exitFullscreen?.(); }; - qs('#cfg-btn').onclick=()=>{ - if(confirm('Change API key? App will reload.')){ localStorage.removeItem('vf_key'); location.reload(); } - }; + qs('#cfg-btn').onclick=()=>{ openSB(); renderTab('settings'); }; qs('#pb-wrap').onclick=e=>{ try{ if(!A.player?.getDuration) return;