Tighten bottom UI, fix ch-bug/ticker/hamburger, reduce gradients
Layout: - Move NOW PLAYING ticker into #np-strip above scrubber; #bb is controls-only at 46px - --bot-h: 76px → 46px; #tc repositioned to clear new ticker strip - #np-strip added to idle slide-out animation Bug fixes: - Channel bug (#ch-bug) now hides during title card display, restores after - Reset A.npTitle/A.npArtist in loadCh() so ticker always updates on channel change - Hamburger (☰) and C key always open to MY LIST tab Visual: - .gt gradient 140px → 72px, .gb gradient 220px → 140px (less intrusive) Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
+19
-17
@@ -17,7 +17,7 @@
|
||||
--accent:#ff2200;--accent2:#00d4ff;--text:#f0f0ff;--dim:#6668a0;
|
||||
--font-d:'Bebas Neue',Impact,'Arial Black',sans-serif;
|
||||
--font-b:'Rajdhani',sans-serif;
|
||||
--top-h:52px;--bot-h:76px;
|
||||
--top-h:52px;--bot-h:46px;
|
||||
}
|
||||
html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-family:var(--font-b);color:var(--text);user-select:none;-webkit-tap-highlight-color:transparent}
|
||||
|
||||
@@ -61,8 +61,8 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
|
||||
#pw iframe{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);border:none;pointer-events:none}
|
||||
|
||||
/* Overlays */
|
||||
.gt{position:absolute;top:0;left:0;right:0;height:140px;background:linear-gradient(180deg,rgba(6,6,15,.92) 0%,transparent 100%);z-index:2;pointer-events:none}
|
||||
.gb{position:absolute;bottom:0;left:0;right:0;height:220px;background:linear-gradient(0deg,rgba(6,6,15,1) 0%,rgba(6,6,15,.92) 35%,rgba(6,6,15,.55) 65%,transparent 100%);z-index:2;pointer-events:none}
|
||||
.gt{position:absolute;top:0;left:0;right:0;height:72px;background:linear-gradient(180deg,rgba(6,6,15,.92) 0%,transparent 100%);z-index:2;pointer-events:none}
|
||||
.gb{position:absolute;bottom:0;left:0;right:0;height:140px;background:linear-gradient(0deg,rgba(6,6,15,1) 0%,rgba(6,6,15,.85) 30%,rgba(6,6,15,.4) 65%,transparent 100%);z-index:2;pointer-events:none}
|
||||
.gr{position:absolute;top:0;right:0;bottom:0;width:220px;background:linear-gradient(270deg,rgba(6,6,15,.85) 0%,rgba(6,6,15,.4) 50%,transparent 100%);z-index:2;pointer-events:none}
|
||||
.gl{position:absolute;top:0;left:0;bottom:0;width:180px;background:linear-gradient(90deg,rgba(6,6,15,.85) 0%,rgba(6,6,15,.4) 50%,transparent 100%);z-index:2;pointer-events:none}
|
||||
#scanlines{position:absolute;inset:0;z-index:3;pointer-events:none;background:repeating-linear-gradient(0deg,transparent,transparent 3px,rgba(0,0,0,.055) 3px,rgba(0,0,0,.055) 4px);opacity:.5}
|
||||
@@ -119,9 +119,8 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
|
||||
#pb-thumb{position:absolute;right:-5px;top:-3px;width:10px;height:10px;background:#fff;border-radius:50%;opacity:0;transition:opacity .15s;pointer-events:none}
|
||||
|
||||
/* Bottom bar */
|
||||
#bb{position:absolute;bottom:0;left:0;right:0;height:var(--bot-h);z-index:5;display:flex;flex-direction:column;justify-content:center;align-items:stretch;padding:5px 14px;gap:2px}
|
||||
.bb-top{display:flex;align-items:center;gap:8px;}
|
||||
.bb-bot{display:flex;justify-content:center;align-items:center}
|
||||
#np-strip{position:absolute;bottom:calc(var(--bot-h) + 3px);left:0;right:0;height:26px;z-index:5;display:flex;align-items:center;padding:0 14px;gap:8px}
|
||||
#bb{position:absolute;bottom:0;left:0;right:0;height:var(--bot-h);z-index:5;display:flex;align-items:center;justify-content:center;padding:0 14px}
|
||||
.np-lbl{font-family:var(--font-d);font-size:12px;letter-spacing:2.5px;color:var(--accent);flex-shrink:0;display:flex;align-items:center;gap:5px;white-space:nowrap}
|
||||
.np-lbl-dot{width:5px;height:5px;background:var(--accent);border-radius:50%;animation:dot-p 1s ease-in-out infinite}
|
||||
.np-wrap{flex:1;overflow:hidden;height:26px;position:relative}
|
||||
@@ -231,23 +230,23 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
|
||||
}
|
||||
@media(max-width:420px){
|
||||
.c-btn{width:30px;height:30px;font-size:13px}
|
||||
#bb{gap:7px;padding:0 10px}
|
||||
#np-strip{padding:0 10px}
|
||||
.np-lbl{display:none}
|
||||
}
|
||||
|
||||
/* ── Title card (lower-third) ── */
|
||||
#tc{position:absolute;bottom:calc(var(--bot-h) + 16px);left:0;z-index:7;padding:0 24px 0 20px;pointer-events:none;opacity:0;transform:translateY(14px);transition:opacity .45s ease,transform .45s ease;max-width:75vw}
|
||||
#tc{position:absolute;bottom:calc(var(--bot-h) + 45px);left:0;z-index:7;padding:0 24px 0 20px;pointer-events:none;opacity:0;transform:translateY(14px);transition:opacity .45s ease,transform .45s ease;max-width:75vw}
|
||||
#tc.show{opacity:1;transform:translateY(0)}
|
||||
#tc.hide{opacity:0;transform:translateY(6px);transition:opacity .6s ease,transform .6s ease}
|
||||
.tc-bar{position:absolute;left:0;top:4px;bottom:4px;width:4px;background:var(--accent)}
|
||||
.tc-artist{font-family:var(--font-d);font-size:clamp(13px,1.8vw,18px);letter-spacing:3px;color:var(--accent2);text-transform:uppercase;line-height:1.2;margin-bottom:3px;text-shadow:0 1px 12px rgba(0,0,0,.9)}
|
||||
.tc-title{font-family:var(--font-d);font-size:clamp(26px,4.5vw,52px);letter-spacing:1px;color:#fff;line-height:1.05;text-shadow:0 2px 24px rgba(0,0,0,.95)}
|
||||
@media(max-width:600px){
|
||||
#tc{max-width:90vw;bottom:calc(var(--bot-h) + 10px)}
|
||||
#tc{max-width:90vw;bottom:calc(var(--bot-h) + 39px)}
|
||||
}
|
||||
|
||||
/* ── Idle / broadcast mode ── */
|
||||
#tb,#bb,#pb-wrap{
|
||||
#tb,#bb,#pb-wrap,#np-strip{
|
||||
will-change:transform,opacity;
|
||||
transition:transform .5s cubic-bezier(.4,0,.15,1), opacity .5s ease;
|
||||
}
|
||||
@@ -257,6 +256,7 @@ body.idle{cursor:none}
|
||||
body.idle #tb{transform:translateY(-120%) scaleY(0.5);transform-origin:top center;opacity:0}
|
||||
body.idle #bb{transform:translateY(120%) scaleY(0.5);transform-origin:bottom center;opacity:0}
|
||||
body.idle #pb-wrap{opacity:0}
|
||||
body.idle #np-strip{transform:translateY(120%) scaleY(0.5);transform-origin:bottom center;opacity:0}
|
||||
body.idle #scanlines{opacity:.68}
|
||||
body.idle #ch-bug{opacity:1}
|
||||
body.idle #tc{bottom:20px}
|
||||
@@ -370,8 +370,7 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
|
||||
<div id="pb"><div id="pb-thumb"></div></div>
|
||||
</div>
|
||||
|
||||
<div id="bb">
|
||||
<div class="bb-top">
|
||||
<div id="np-strip">
|
||||
<div class="np-lbl"><span class="np-lbl-dot"></span><span>NOW PLAYING</span></div>
|
||||
<div class="np-wrap">
|
||||
<div id="np-ticker">
|
||||
@@ -379,7 +378,8 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bb-bot">
|
||||
|
||||
<div id="bb">
|
||||
<div class="ctrls">
|
||||
<button class="c-btn" id="b-prev" title="Previous (←)">⏪</button>
|
||||
<button class="c-btn" id="b-play" title="Play / Pause (Space)">▶</button>
|
||||
@@ -388,7 +388,6 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
|
||||
<button class="c-btn" id="b-sb" title="Channels (C)">☰</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lo"><div class="ldr"><div class="lb"></div><div class="lb"></div><div class="lb"></div><div class="lb"></div></div></div>
|
||||
<div id="toast"></div>
|
||||
@@ -531,6 +530,7 @@ function loadCh(i){
|
||||
A.player.stopVideo();
|
||||
const startIdx=A.shuffled?Math.floor(Math.random()*30):0;
|
||||
A.player.loadPlaylist({list:ch.pid,listType:'playlist',index:startIdx});
|
||||
A.npTitle=''; A.npArtist='';
|
||||
setTicker('',ch.title);
|
||||
setTimeout(()=>{
|
||||
try{
|
||||
@@ -572,16 +572,18 @@ function cleanArtist(s){
|
||||
|
||||
function showTitleCard(artist, title){
|
||||
if(!title) return;
|
||||
const card=qs('#tc');
|
||||
const card=qs('#tc'), bug=qs('#ch-bug');
|
||||
qs('#tc-artist').textContent = artist||'';
|
||||
qs('#tc-title').textContent = title||'';
|
||||
card.classList.remove('hide');
|
||||
card.classList.add('show');
|
||||
if(bug) bug.style.opacity='0';
|
||||
clearTimeout(A.tcTimer);
|
||||
// hold for 2.8s then fade out
|
||||
A.tcTimer = setTimeout(()=>{
|
||||
card.classList.remove('show');
|
||||
card.classList.add('hide');
|
||||
if(bug) bug.style.opacity='';
|
||||
}, 2800);
|
||||
}
|
||||
|
||||
@@ -981,7 +983,7 @@ function wireControls(){
|
||||
localStorage.setItem('vf_shuffle', A.shuffled);
|
||||
toast(A.shuffled?'\u21cc Shuffle ON':'Shuffle OFF');
|
||||
};
|
||||
qs('#b-sb').onclick=openSB;
|
||||
qs('#b-sb').onclick=()=>{ openSB(); renderTab('channels'); };
|
||||
qs('#b-shuf').classList.toggle('act',A.shuffled); // reflect default shuffle state
|
||||
qs('#sb-close').onclick=closeSB;
|
||||
qs('#ts').onclick=()=>{ try{A.player?.playVideo?.();}catch(e){} hideTap(); };
|
||||
@@ -1044,7 +1046,7 @@ function wireControls(){
|
||||
try{A.player?.setShuffle?.(A.shuffled);}catch(err){}
|
||||
localStorage.setItem('vf_shuffle', A.shuffled);
|
||||
toast(A.shuffled?'⇌ Shuffle ON':'Shuffle OFF');
|
||||
} else if(e.code==='KeyC'){ openSB();
|
||||
} else if(e.code==='KeyC'){ openSB(); renderTab('channels');
|
||||
} else if(e.code==='KeyP'){ window.opener ? window.close() : popOut();
|
||||
} else if(e.code==='KeyF'){
|
||||
if(!document.fullscreenElement) document.documentElement.requestFullscreen?.().catch(()=>{});
|
||||
|
||||
Reference in New Issue
Block a user