mirror of
https://github.com/narrrl/pl8list-rewind.git
synced 2026-11-03 16:41:26 +01:00
Scale the card up on desktop, glass header controls, slim volume slider
On wide windows with a mouse the card grows with the window (--u), the action rail sits beside the content, the header controls share one glass capsule and up next is larger. The volume slider is a slim filled track everywhere. The drop's canvas is capped at 2.6M pixels so the bigger drop costs no more than it shows.
This commit is contained in:
1 parent
b29062db3e
commit
aa0e28d326
3 files changed
+110
-3
No files matched your search
@@ -43,6 +43,7 @@ const SLOW_FOR = 2; // … and this many seconds of them step the quality down
|
|||||||
const FAST_FOR = 10; // s of frames on time before it tries one step up again
|
const FAST_FOR = 10; // s of frames on time before it tries one step up again
|
||||||
/// Quality steps: icosphere subdivisions and resolution scale.
|
/// Quality steps: icosphere subdivisions and resolution scale.
|
||||||
const QUALITY: [number, number][] = [[5, 1], [4, 1], [4, 0.6], [3, 0.5]];
|
const QUALITY: [number, number][] = [[5, 1], [4, 1], [4, 0.6], [3, 0.5]];
|
||||||
|
const MAX_PIXELS = 2.6e6; // canvas pixels at full quality, about 1600 x 1600
|
||||||
|
|
||||||
const UNIFORMS = [
|
const UNIFORMS = [
|
||||||
"uProj", "uDist", "uTime", "uMorph", "uLevel", "uWobble", "uKick", "uKickAge", "uSnare", "uDrop", "uBass", "uGrowl",
|
"uProj", "uDist", "uTime", "uMorph", "uLevel", "uWobble", "uKick", "uKickAge", "uSnare", "uDrop", "uBass", "uGrowl",
|
||||||
@@ -252,8 +253,10 @@ export class LiquidBlob {
|
|||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
const { playing } = s;
|
const { playing } = s;
|
||||||
if (playing) this.watch(dt);
|
if (playing) this.watch(dt);
|
||||||
const scale = this.density() * QUALITY[this.quality][1];
|
const cw = this.canvas.clientWidth, ch = this.canvas.clientHeight;
|
||||||
const w = Math.round(this.canvas.clientWidth * scale), h = Math.round(this.canvas.clientHeight * scale);
|
// The drop is big on big screens: past MAX_PIXELS it gets no sharper, only slower.
|
||||||
|
const scale = Math.min(this.density(), Math.sqrt(MAX_PIXELS / (cw * ch || 1))) * QUALITY[this.quality][1];
|
||||||
|
const w = Math.round(cw * scale), h = Math.round(ch * scale);
|
||||||
if (!w || !h) return false;
|
if (!w || !h) return false;
|
||||||
if (this.canvas.width !== w || this.canvas.height !== h) {
|
if (this.canvas.width !== w || this.canvas.height !== h) {
|
||||||
this.canvas.width = w;
|
this.canvas.width = w;
|
||||||
|
|||||||
@@ -504,6 +504,8 @@ function showVolume(): void {
|
|||||||
muteBtn.querySelector("use")!.setAttribute("href", silent ? "#i-mute" : "#i-vol");
|
muteBtn.querySelector("use")!.setAttribute("href", silent ? "#i-mute" : "#i-vol");
|
||||||
muteBtn.setAttribute("aria-pressed", String(player.muted));
|
muteBtn.setAttribute("aria-pressed", String(player.muted));
|
||||||
volumeSlider.value = String(player.muted ? 0 : player.volume);
|
volumeSlider.value = String(player.muted ? 0 : player.volume);
|
||||||
|
// How far the slider's track is filled (style.css).
|
||||||
|
volumeSlider.style.setProperty("--v", `${Number(volumeSlider.value) * 100}%`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMuted(m: boolean): void {
|
function setMuted(m: boolean): void {
|
||||||
|
|||||||
+103
-1
@@ -133,7 +133,38 @@ body.zen #bar { display: none; }
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
#volume { display: flex; align-items: center; gap: 0.3rem; margin-right: 0.3rem; }
|
#volume { display: flex; align-items: center; gap: 0.3rem; margin-right: 0.3rem; }
|
||||||
#volume-slider { width: 5.5rem; accent-color: var(--accent); cursor: pointer; }
|
/* A slim track filled up to --v (main.ts), and a small round thumb. */
|
||||||
|
#volume-slider {
|
||||||
|
--v: 100%;
|
||||||
|
width: 5.5rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin: 0;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background: linear-gradient(90deg, var(--fg) var(--v), #ffffff30 var(--v)) center / 100% 4px no-repeat;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#volume-slider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 0.75rem;
|
||||||
|
height: 0.75rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--fg);
|
||||||
|
box-shadow: 0 0 0 3px #0006;
|
||||||
|
transition: transform var(--fast);
|
||||||
|
}
|
||||||
|
#volume-slider::-moz-range-thumb {
|
||||||
|
width: 0.75rem;
|
||||||
|
height: 0.75rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--fg);
|
||||||
|
box-shadow: 0 0 0 3px #0006;
|
||||||
|
transition: transform var(--fast);
|
||||||
|
}
|
||||||
|
#volume-slider:hover::-webkit-slider-thumb { transform: scale(1.25); }
|
||||||
|
#volume-slider:hover::-moz-range-thumb { transform: scale(1.25); }
|
||||||
#mode-chip {
|
#mode-chip {
|
||||||
max-width: 16rem;
|
max-width: 16rem;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -1072,6 +1103,77 @@ body.zen .why, body.zen .byline button, body.zen #feed-status { display: none; }
|
|||||||
body.zen .art { width: min(30rem, 62vh, 86vw); }
|
body.zen .art { width: min(30rem, 62vh, 86vw); }
|
||||||
body.zen .content { gap: 0.3rem; }
|
body.zen .content { gap: 0.3rem; }
|
||||||
|
|
||||||
|
/* Desktop ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* The card grows with the window, so a big screen is not a phone layout lost in
|
||||||
|
the middle of it. --u is a rem that grows with the window: 1rem at 1280x800,
|
||||||
|
1.5rem around 2000x1100, at most 1.6rem; the shorter side decides. */
|
||||||
|
@media (min-width: 900px) and (pointer: fine) {
|
||||||
|
#bar { padding: 1rem 1.6rem; }
|
||||||
|
.logo { font-size: 1.15rem; }
|
||||||
|
#mode-tabs { padding: 0.25rem; }
|
||||||
|
#mode-tabs button { font-size: 0.95rem; padding: 0.45em 1.15em; }
|
||||||
|
/* The controls as one glass capsule, a match for the tabs. */
|
||||||
|
.bar-end {
|
||||||
|
gap: 0.15rem;
|
||||||
|
padding: 0.25rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--glass);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
.bar-end .icon-btn { width: 2.5rem; height: 2.5rem; background: none; }
|
||||||
|
.bar-end .icon-btn:hover, .bar-end .icon-btn[aria-expanded="true"] { background: var(--glass-strong); }
|
||||||
|
.bar-end .icon-btn svg { width: 1.15rem; height: 1.15rem; }
|
||||||
|
.avatar-btn { width: 2.5rem; height: 2.5rem; margin-left: 0.2rem; }
|
||||||
|
#volume { margin: 0 0.5rem 0 0; gap: 0.2rem; }
|
||||||
|
|
||||||
|
.card {
|
||||||
|
--u: clamp(1rem, min(2.667vh - 0.33rem, 1.111vw + 0.11rem), 1.6rem);
|
||||||
|
/* Above the true middle, where the eye puts it, and clear of up next. */
|
||||||
|
padding-bottom: 4vh;
|
||||||
|
}
|
||||||
|
.content { width: min(calc(30 * var(--u)), 56vw); gap: calc(0.6 * var(--u)); }
|
||||||
|
.art { width: min(calc(16 * var(--u)), 46vh); margin-bottom: calc(1.2 * var(--u)); }
|
||||||
|
.title { font-size: calc(1.45 * var(--u)); }
|
||||||
|
.why { font-size: 0.8rem; }
|
||||||
|
.byline { gap: 0.6rem; font-size: 1.1rem; }
|
||||||
|
.artist-avatar { width: 2rem; height: 2rem; font-size: 0.85rem; }
|
||||||
|
.pill { font-size: 0.85rem; padding: 0.3em 0.9em 0.3em 0.7em; }
|
||||||
|
.chips { gap: 0.5rem; }
|
||||||
|
.chips span { font-size: 0.85rem; padding: 0.2em 0.75em; }
|
||||||
|
.desc { font-size: 0.95rem; }
|
||||||
|
.wave-wrap { margin-top: calc(0.8 * var(--u)); }
|
||||||
|
.wave { height: calc(4 * var(--u)); }
|
||||||
|
.time { font-size: 0.85rem; }
|
||||||
|
|
||||||
|
/* The actions beside the content, not lost at the edge of the screen. */
|
||||||
|
.actions {
|
||||||
|
top: calc(50% - 2vh);
|
||||||
|
bottom: auto;
|
||||||
|
right: auto;
|
||||||
|
left: min(calc(50% + min(calc(15 * var(--u)), 28vw) + 2.5rem), calc(100% - 5rem));
|
||||||
|
translate: 0 -50%;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.act { gap: 0.3rem; font-size: 0.75rem; }
|
||||||
|
.act .ring {
|
||||||
|
width: 3.5rem;
|
||||||
|
height: 3.5rem;
|
||||||
|
background: var(--glass);
|
||||||
|
box-shadow: inset 0 0 0 1px #ffffff14;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
.act:hover .ring { background: var(--glass-strong); }
|
||||||
|
.act svg { width: 1.5rem; height: 1.5rem; }
|
||||||
|
|
||||||
|
#up-next { bottom: 1.6rem; max-width: 28rem; gap: 0.75rem; padding: 0.4rem 1.2rem 0.4rem 0.4rem; }
|
||||||
|
.up-next-avatar { width: 2.6rem; height: 2.6rem; }
|
||||||
|
.up-next-title { font-size: 0.95rem; }
|
||||||
|
#toast { bottom: 6rem; }
|
||||||
|
|
||||||
|
body.zen .art { width: min(40rem, 70vh); }
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
|
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user