finally got the playlist score bar gradient to clip at the score

This commit is contained in:
pleb 2025-11-03 11:07:31 -08:00
parent fbba09f5b6
commit 17890e42e5
2 changed files with 43 additions and 46 deletions

View File

@ -15,5 +15,5 @@
## Shell command guidance
- Whitelisted commands: `grep`
- DO NOT USE: `cd` (prefer `pwd`)
- Dont' use `cd`, prefer `pwd`
- Dont' use `rg`, prefer `grep -r`

View File

@ -62,11 +62,15 @@ let playlistState: Record<number, PlaylistState> = {};
function togglePlaylist(id: number) {
const currentlyExpanded = Boolean(expanded[id]);
expanded = { ...expanded, [id]: !currentlyExpanded };
const nextExpanded: Record<number, boolean> = {};
if (!currentlyExpanded) {
nextExpanded[id] = true;
}
expanded = nextExpanded;
if (!currentlyExpanded) {
const state = playlistState[id];
const offset = state ? state.offset : 0;
loadPlaylistMaps(id, offset);
const currentOffset = state && typeof state.offset === 'number' ? state.offset : 0;
loadPlaylistMaps(id, currentOffset);
}
}
@ -222,16 +226,9 @@ function scorePercent(avgScore: number | undefined | null): number | null {
<span class="map-count">{playlist.stats?.totalMaps ?? 0} maps</span>
</div>
{#if scorePercent(playlist.stats?.avgScore) !== null}
<div
class="row-score"
data-gradient={scorePercent(playlist.stats?.avgScore)! > 50 ? 'true' : 'false'}
>
<div class="score-bar">
<div
class="score-bar-fill"
style={`width: ${scorePercent(playlist.stats?.avgScore) ?? 0}%`}
></div>
</div>
{@const pct = scorePercent(playlist.stats?.avgScore) ?? 0}
<div class="row-score">
<div class="score-bar" style={`--score-fill:${pct}%`}></div>
</div>
{/if}
<div class="row-sub">
@ -255,14 +252,15 @@ function scorePercent(avgScore: number | undefined | null): number | null {
</button>
{#if expanded[playlist.playlistId]}
{@const state = playlistState[playlist.playlistId]}
<div class="row-body">
{#if playlistState[playlist.playlistId]?.loading}
{#if state?.loading}
<div class="row-status">Loading songs…</div>
{:else if playlistState[playlist.playlistId]?.error}
<div class="row-status error">{playlistState[playlist.playlistId]?.error}</div>
{:else if playlistState[playlist.playlistId]?.maps?.length}
{:else if state?.error}
<div class="row-status error">{state.error}</div>
{:else if state?.maps?.length}
<div class="songs-grid">
{#each playlistState[playlist.playlistId].maps as card (card.id)}
{#each state.maps as card (card.id)}
<MapCard
hash={card.hash}
coverURL={card.coverURL}
@ -278,35 +276,34 @@ function scorePercent(avgScore: number | undefined | null): number | null {
/>
{/each}
</div>
{#if playlistState[playlist.playlistId]?.total}
{#if state.total && state.total > SONGS_PER_PAGE}
<div class="row-pagination">
<button
class="pager-btn"
on:click={() => loadPlaylistMaps(playlist.playlistId, Math.max(0, playlistState[playlist.playlistId].offset - SONGS_PER_PAGE))}
disabled={playlistState[playlist.playlistId].offset === 0 || playlistState[playlist.playlistId].loading}
on:click={() => loadPlaylistMaps(playlist.playlistId, Math.max(0, (state.offset ?? 0) - SONGS_PER_PAGE))}
disabled={(state.offset ?? 0) === 0 || state.loading}
>
Prev {SONGS_PER_PAGE}
</button>
<span class="row-status">
{#if playlistState[playlist.playlistId].total === 0}
{#if state.total === 0}
No songs
{:else}
Showing {playlistState[playlist.playlistId].offset + 1}
Showing {(state.offset ?? 0) + 1}
-
{Math.min(
playlistState[playlist.playlistId].offset + playlistState[playlist.playlistId].maps.length,
playlistState[playlist.playlistId].total ?? 0
(state.offset ?? 0) + state.maps.length,
state.total ?? 0
)}
of {playlistState[playlist.playlistId].total}
of {state.total}
{/if}
</span>
<button
class="pager-btn"
on:click={() => loadPlaylistMaps(playlist.playlistId, playlistState[playlist.playlistId].offset + SONGS_PER_PAGE)}
on:click={() => loadPlaylistMaps(playlist.playlistId, (state.offset ?? 0) + SONGS_PER_PAGE)}
disabled={
playlistState[playlist.playlistId].loading ||
(playlistState[playlist.playlistId].offset + playlistState[playlist.playlistId].maps.length) >=
(playlistState[playlist.playlistId].total ?? 0)
state.loading ||
((state.offset ?? 0) + state.maps.length) >= (state.total ?? 0)
}
>
Next {SONGS_PER_PAGE}
@ -431,25 +428,25 @@ function scorePercent(avgScore: number | undefined | null): number | null {
width: 100%;
height: 0.5rem;
border-radius: 999px;
background: rgba(34, 211, 238, 0.15);
background-color: rgba(34, 211, 238, 0.15);
overflow: hidden;
}
.score-bar-fill {
.score-bar::before {
content: '';
position: absolute;
inset: 0;
width: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: inherit;
background: var(--score-gradient, var(--score-default));
transition: width 0.3s ease;
}
.row-score[data-gradient='true'] .score-bar-fill {
--score-gradient: linear-gradient(90deg, var(--color-neon-fuchsia), var(--color-neon));
}
.row-score[data-gradient='false'] .score-bar-fill {
--score-gradient: rgba(148, 163, 184, 0.35);
background: linear-gradient(90deg, var(--color-neon-fuchsia), var(--color-neon));
/* Reveal only the first N% of the full-width gradient */
-webkit-mask-image: linear-gradient(90deg, #000 0 var(--score-fill, 0%), transparent var(--score-fill, 0%) 100%);
mask-image: linear-gradient(90deg, #000 0 var(--score-fill, 0%), transparent var(--score-fill, 0%) 100%);
/* Fallback for environments without mask-image support */
clip-path: inset(0 calc(100% - var(--score-fill, 0%)) 0 0 round 999px);
transition: -webkit-mask-image 0.3s ease, mask-image 0.3s ease, clip-path 0.3s ease;
}
.row-arrow {