discovery: elevate the wave dial — full width + glow, luminous fill, pulsing orb, colour aura
This commit is contained in:
parent
c50465984f
commit
d9bd5c1d7f
3 changed files with 65 additions and 25 deletions
|
|
@ -3156,8 +3156,16 @@
|
|||
<span class="adv-wave-state" id="adv-wave-state">Balanced</span>
|
||||
</div>
|
||||
<div class="adv-wave-track" id="adv-wave-track">
|
||||
<div class="adv-wave-aura" id="adv-wave-aura"></div>
|
||||
<svg class="adv-wave-svg" id="adv-wave-svg" viewBox="0 0 1000 80" preserveAspectRatio="none" aria-hidden="true">
|
||||
<path id="adv-wave-path" fill="none" stroke-width="3" stroke-linecap="round"></path>
|
||||
<defs>
|
||||
<linearGradient id="adv-wave-fill" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop id="adv-wave-fill-top" offset="0" stop-color="#1DB954" stop-opacity="0.32"/>
|
||||
<stop offset="1" stop-color="#1DB954" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path id="adv-wave-area" fill="url(#adv-wave-fill)" stroke="none"></path>
|
||||
<path id="adv-wave-path" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
<div class="adv-wave-orb" id="adv-wave-orb"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ function _advState(v) {
|
|||
return 'Deep cuts only';
|
||||
}
|
||||
// green (120°) → red (0°) through the warm spectrum (yellow, orange) as the orb moves right.
|
||||
function _advColor(v, light) {
|
||||
function _advColor(v, light, alpha) {
|
||||
const hue = 120 * (1 - Math.max(0, Math.min(1, v)));
|
||||
return `hsl(${hue.toFixed(0)}, 85%, ${light || 55}%)`;
|
||||
const l = light || 55;
|
||||
return alpha != null ? `hsla(${hue.toFixed(0)}, 85%, ${l}%, ${alpha})` : `hsl(${hue.toFixed(0)}, 85%, ${l}%)`;
|
||||
}
|
||||
// Wave height (viewBox units, centre 40) at position u (0..1) for adventurousness v.
|
||||
function _advWaveY(u, v) {
|
||||
|
|
@ -57,14 +58,16 @@ function _advDraw() {
|
|||
if (track.offsetParent !== null) { // skip the work while the Discover page is hidden
|
||||
const v = _advWave.value;
|
||||
_advWave.phase += 0.03 + v * 0.07; // waves faster the more adventurous
|
||||
let d = '';
|
||||
let line = '';
|
||||
const N = 90;
|
||||
for (let i = 0; i <= N; i++) {
|
||||
const u = i / N;
|
||||
d += (i === 0 ? 'M ' : ' L ') + (u * 1000).toFixed(1) + ' ' + _advWaveY(u, v).toFixed(1);
|
||||
line += (i === 0 ? 'M ' : ' L ') + (u * 1000).toFixed(1) + ' ' + _advWaveY(u, v).toFixed(1);
|
||||
}
|
||||
path.setAttribute('d', d);
|
||||
path.setAttribute('stroke', _advColor(v));
|
||||
path.setAttribute('d', line);
|
||||
// the luminous filled area = the wave closed down to the baseline
|
||||
const area = document.getElementById('adv-wave-area');
|
||||
if (area) area.setAttribute('d', line + ' L 1000 80 L 0 80 Z');
|
||||
const orb = document.getElementById('adv-wave-orb');
|
||||
if (orb) orb.style.top = (_advWaveY(v, v) / 80 * 100).toFixed(2) + '%'; // orb rides the wave
|
||||
}
|
||||
|
|
@ -73,15 +76,27 @@ function _advDraw() {
|
|||
function _advApply(v) {
|
||||
v = Math.max(0, Math.min(1, v));
|
||||
_advWave.value = v;
|
||||
const c = _advColor(v, 55);
|
||||
const cBright = _advColor(v, 62);
|
||||
// Line stroke + its colour glow (set on change, not every frame, so the rAF stays cheap).
|
||||
const path = document.getElementById('adv-wave-path');
|
||||
if (path) { path.setAttribute('stroke', c); path.style.filter = `drop-shadow(0 0 7px ${c})`; }
|
||||
const fillTop = document.getElementById('adv-wave-fill-top');
|
||||
if (fillTop) fillTop.setAttribute('stop-color', c); // luminous filled area
|
||||
const orb = document.getElementById('adv-wave-orb');
|
||||
if (orb) {
|
||||
orb.style.left = (v * 100).toFixed(2) + '%';
|
||||
const c = _advColor(v, 58);
|
||||
orb.style.background = c;
|
||||
orb.style.boxShadow = `0 0 18px 2px ${c}, 0 0 0 5px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.55)`;
|
||||
orb.style.color = c; // currentColor for the pulsing ring
|
||||
orb.style.background = cBright;
|
||||
orb.style.boxShadow = `0 0 22px 3px ${c}, 0 0 0 6px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.6)`;
|
||||
}
|
||||
const aura = document.getElementById('adv-wave-aura'); // colour wash that follows the orb
|
||||
if (aura) {
|
||||
aura.style.left = (v * 100).toFixed(2) + '%';
|
||||
aura.style.background = `radial-gradient(circle, ${_advColor(v, 50, 0.42)} 0%, transparent 68%)`;
|
||||
}
|
||||
const stateEl = document.getElementById('adv-wave-state');
|
||||
if (stateEl) { stateEl.textContent = _advState(v); stateEl.style.color = _advColor(v, 62); }
|
||||
if (stateEl) { stateEl.textContent = _advState(v); stateEl.style.color = cBright; }
|
||||
}
|
||||
let _advCommitTimer = null;
|
||||
function _advCommit(v) {
|
||||
|
|
|
|||
|
|
@ -35168,35 +35168,52 @@ div.artist-hero-badge {
|
|||
and wilder + redder at the right (obscure). The path + colours are drawn each frame in
|
||||
JS (rAF). Syncs with Settings → Discovery. */
|
||||
.adv-wave {
|
||||
max-width: 880px;
|
||||
margin: 0 0 26px;
|
||||
padding: 16px 22px 14px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(135deg, rgba(255,255,255,0.035), rgba(255,255,255,0.01));
|
||||
position: relative;
|
||||
margin: 0 0 28px;
|
||||
padding: 18px 26px 16px;
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(135deg, rgba(255,255,255,0.04), rgba(255,255,255,0.012));
|
||||
border: 1px solid rgba(255,255,255,0.07);
|
||||
box-shadow: 0 8px 28px rgba(0,0,0,0.25);
|
||||
box-shadow: 0 10px 34px rgba(0,0,0,0.30);
|
||||
overflow: hidden; /* contain the colour aura wash */
|
||||
}
|
||||
.adv-wave-head { display: flex; align-items: baseline; gap: 12px; }
|
||||
.adv-wave-title { font-size: 14px; font-weight: 700; color: #fff; }
|
||||
.adv-wave-head { display: flex; align-items: baseline; gap: 12px; position: relative; z-index: 2; }
|
||||
.adv-wave-title { font-size: 15px; font-weight: 800; color: #fff; letter-spacing: 0.2px; }
|
||||
.adv-wave-state { font-size: 12px; font-weight: 700; transition: color 0.25s; }
|
||||
.adv-wave-track {
|
||||
position: relative; height: 84px; margin: 4px 0 2px;
|
||||
position: relative; height: 104px; margin: 6px 0 2px;
|
||||
cursor: grab; touch-action: none;
|
||||
}
|
||||
.adv-wave-track:active { cursor: grabbing; }
|
||||
.adv-wave-svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.adv-wave-orb {
|
||||
.adv-wave-aura {
|
||||
position: absolute; top: 50%; left: 30%;
|
||||
width: 20px; height: 20px; border-radius: 50%;
|
||||
width: 360px; height: 230px; transform: translate(-50%, -50%);
|
||||
pointer-events: none; filter: blur(14px); z-index: 0;
|
||||
will-change: left, background;
|
||||
}
|
||||
.adv-wave-svg { width: 100%; height: 100%; display: block; overflow: visible; position: relative; z-index: 1; }
|
||||
.adv-wave-orb {
|
||||
position: absolute; top: 50%; left: 30%; z-index: 2;
|
||||
width: 22px; height: 22px; border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #1DB954;
|
||||
box-shadow: 0 0 18px 2px #1DB954, 0 0 0 5px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.55);
|
||||
background: #1DB954; color: #1DB954;
|
||||
box-shadow: 0 0 20px 3px #1DB954, 0 0 0 6px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.6);
|
||||
pointer-events: none; /* the track captures the pointer; the orb is purely visual */
|
||||
will-change: left, top;
|
||||
}
|
||||
.adv-wave-orb::after {
|
||||
content: ''; position: absolute; inset: -7px; border-radius: 50%;
|
||||
border: 2px solid currentColor; opacity: 0.5;
|
||||
animation: adv-orb-pulse 2.4s ease-out infinite;
|
||||
}
|
||||
@keyframes adv-orb-pulse {
|
||||
0% { transform: scale(0.7); opacity: 0.55; }
|
||||
100% { transform: scale(1.95); opacity: 0; }
|
||||
}
|
||||
.adv-wave-ends {
|
||||
display: flex; justify-content: space-between;
|
||||
font-size: 11px; font-weight: 500; color: rgba(255,255,255,0.35);
|
||||
position: relative; z-index: 2;
|
||||
}
|
||||
|
||||
/* Watchlist toggle on recommended-artist .ya-cards — corner pill, appears on hover,
|
||||
|
|
|
|||
Loading…
Reference in a new issue