web-player: remove dead code and unused props

This commit is contained in:
2026-09-24 05:04:09 +02:00
parent bc43b4b6eb
commit 37fc229bf6
24 changed files with 37 additions and 149 deletions
@@ -69,7 +69,7 @@
{#if visiblePlaylists.length > 0}
<IconButton
label="Crear playlist"
tone="plain"
plain
size="xs"
onclick={() => createPlaylistModal.show()}
>
@@ -96,7 +96,7 @@
<button
type="button"
onclick={() => createPlaylistModal.show()}
class="flex items-center gap-2 rounded-control px-3 py-2 text-xs text-fg-2 transition-colors hover:bg-hover hover:text-fg-2"
class="flex items-center gap-2 rounded-control px-3 py-2 text-xs text-fg-2 transition-colors hover:bg-hover"
>
<Plus class="size-3.5" />
Crear tu primera lista
@@ -54,14 +54,7 @@
</script>
<header class="hidden items-center gap-3.5 px-6.5 pt-4 pb-3 sm:flex">
<IconButton
label="Atrás"
shape="round"
tone="subtle"
surface
size="xs"
onclick={() => history.back()}
>
<IconButton label="Atrás" shape="round" surface size="xs" onclick={() => history.back()}>
<ChevronLeft class="size-icon-sm" />
</IconButton>
@@ -91,9 +84,7 @@
</label>
</form>
<div class="flex-1"></div>
<div class="shrink-0">
<div class="ml-auto shrink-0">
{#if user}
<AccountMenu {user} {accountUrl}>
{#snippet trigger({ toggle, open })}
@@ -49,10 +49,10 @@
</span>
</div>
</div>
<div class="hidden w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5 sm:flex">
<div class="flex w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5">
<IconButton
label={player.muted ? 'Activar sonido' : 'Silenciar'}
tone="plain"
plain
size="xs"
onclick={() => player.toggleMute()}
>
@@ -73,7 +73,7 @@
/>
<IconButton
label="Cola de reproducción"
tone="plain"
plain
size="xs"
pressed={queuePanel.open}
onclick={() => queuePanel.toggle()}
@@ -48,7 +48,7 @@
>
<div class="mb-5 flex items-center justify-between">
<h2 class="font-display text-base font-medium tracking-tight text-fg">En cola</h2>
<IconButton label="Cerrar cola" tone="plain" size="xs" onclick={() => queuePanel.close()}>
<IconButton label="Cerrar cola" plain size="xs" onclick={() => queuePanel.close()}>
<X class="size-icon-md" />
</IconButton>
</div>
@@ -55,7 +55,7 @@
{#if !compact}
<IconButton
label={isLiked ? 'Quitar de Me gusta' : 'Añadir a Me gusta'}
tone="plain"
plain
size="md"
pressed={isLiked}
onclick={toggleLike}
@@ -81,10 +81,8 @@
<div class="flex items-center justify-between gap-4">
{#if helperText}
<p class="text-sm text-fg-2">{helperText}</p>
{:else}
<span></span>
{/if}
<div class="flex shrink-0 items-center gap-3">
<div class="ml-auto flex shrink-0 items-center gap-3">
<Button type="button" variant="secondary" onclick={onCancel}>Cancelar</Button>
<Button type="submit" disabled={submitting || !canSubmit}>
{submitting ? submittingLabel : submitLabel}
@@ -13,7 +13,7 @@
<a
href="/user/{ownerUserId}"
onclick={(e) => e.stopPropagation()}
class="block max-w-full truncate hover:text-fg-2 hover:underline {klass}"
class="block max-w-full truncate hover:underline {klass}"
>
{name}
</a>
@@ -9,7 +9,6 @@
size: Size;
shape?: 'auto' | 'round';
imageSize?: 'small' | 'medium' | 'large';
fallback?: 'music' | 'gradient' | 'none';
alt?: string;
class?: string;
children?: Snippet;
@@ -21,7 +20,6 @@
size,
shape = 'auto',
imageSize,
fallback = 'music',
alt = '',
class: klass = '',
children
@@ -116,7 +114,7 @@
onerror={() => (singleFailed = true)}
class="h-full w-full object-cover"
/>
{:else if fallback === 'music'}
{:else}
<div class="grid h-full w-full place-items-center bg-surface">
<svg viewBox="0 0 24 24" fill="currentColor" class="h-2/5 w-2/5 text-fg-2">
<path
@@ -124,10 +122,6 @@
/>
</svg>
</div>
{:else if fallback === 'gradient'}
<div class="h-full w-full bg-(image:--mf-cover-grad)"></div>
{:else}
<div class="h-full w-full bg-surface"></div>
{/if}
{@render children?.()}
</div>
@@ -1,19 +1,11 @@
<script lang="ts">
interface Props {
size?: number;
barWidth?: number;
paused?: boolean;
overlay?: boolean;
class?: string;
}
let {
size = 13,
barWidth = 2,
paused = false,
overlay = false,
class: klass = ''
}: Props = $props();
let { paused = false, overlay = false, class: klass = '' }: Props = $props();
const delays = [0, 0.3, 0.6];
</script>
@@ -30,11 +22,11 @@
{/each}
</div>
{:else}
<div class="flex items-end justify-center gap-0.5 {klass}" style="height:{size}px">
<div class="flex h-3.5 items-end justify-center gap-0.5 {klass}">
{#each delays as delay (delay)}
<span
class="rounded-full bg-accent"
style="width:{barWidth}px; height:100%; animation:equalize .9s ease-in-out {delay}s infinite; animation-play-state:{paused
class="h-full w-0.5 rounded-full bg-accent"
style="animation:equalize .9s ease-in-out {delay}s infinite; animation-play-state:{paused
? 'paused'
: 'running'}"
></span>
@@ -5,12 +5,11 @@
interface Props {
following: boolean;
userId?: string;
invalidateAll?: boolean;
class?: string;
}
let { following: initial, userId, invalidateAll = false, class: klass = '' }: Props = $props();
let { following: initial, invalidateAll = false, class: klass = '' }: Props = $props();
let following = $state(untrack(() => initial));
let submitting = $state(false);
@@ -30,9 +29,6 @@
};
}}
>
{#if userId}
<input type="hidden" name="userId" value={userId} />
{/if}
<Button
type="submit"
size="sm"
@@ -18,7 +18,6 @@
class?: string;
art?: Snippet;
overlay?: Snippet;
badge?: Snippet;
}
let {
@@ -34,8 +33,7 @@
titleClass = '',
class: klass = '',
art,
overlay,
badge
overlay
}: Props = $props();
</script>
@@ -61,7 +59,6 @@
<span class="min-w-0 truncate text-sm {active ? 'text-accent-soft' : 'text-fg'} {titleClass}"
>{title}</span
>
{@render badge?.()}
</div>
<ArtistLink name={artist} {ownerUserId} class="mt-0.5 text-xs text-fg-2" />
</div>
@@ -138,8 +138,6 @@
role="button"
tabindex="0"
use:pressable={() => onPlay(i)}
onclick={(event) => event.stopPropagation()}
onkeydown={(event) => event.stopPropagation()}
class="flex min-w-0 flex-1 text-left"
>
<MediaIdentity
@@ -173,13 +171,7 @@
</span>
{#if rowAction}
{#if rowAction.action}
<form
method="POST"
action={rowAction.action}
use:enhance={() =>
async ({ update }) =>
update()}
>
<form method="POST" action={rowAction.action} use:enhance>
<input type="hidden" name="trackId" value={track.id} />
<IconButton type="submit" label={rowAction.label} size="xs" revealOnHover>
<rowAction.icon class="size-icon-sm" />
@@ -6,7 +6,7 @@
type?: 'button' | 'submit';
size?: 'xs' | 'sm' | 'md' | 'lg';
shape?: 'square' | 'round';
tone?: 'muted' | 'subtle' | 'plain';
plain?: boolean;
pressed?: boolean;
surface?: boolean;
revealOnHover?: boolean;
@@ -22,7 +22,7 @@
type = 'button',
size = 'sm',
shape = 'square',
tone = 'muted',
plain = false,
pressed,
surface = false,
revealOnHover = false,
@@ -40,18 +40,12 @@
lg: 'size-10'
};
const TEXT: Record<'muted' | 'subtle' | 'plain', string> = {
muted: 'text-fg-2 hover:text-fg',
subtle: 'text-fg-2 hover:text-fg',
plain: 'text-fg-2 hover:text-fg'
};
const background = $derived(
surface ? 'bg-surface-2 hover:bg-surface-hover' : tone === 'plain' ? '' : 'hover:bg-hover'
surface ? 'bg-surface-2 hover:bg-surface-hover' : plain ? '' : 'hover:bg-hover'
);
const classes = $derived(
`grid place-items-center transition focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none ${SIZE[size]} ${shape === 'round' ? 'rounded-full' : 'rounded-control'} ${pressed ? 'text-accent' : TEXT[tone]} ${background} ${
`grid place-items-center transition focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none ${SIZE[size]} ${shape === 'round' ? 'rounded-full' : 'rounded-control'} ${pressed ? 'text-accent' : 'text-fg-2 hover:text-fg'} ${background} ${
revealOnHover ? 'sm:opacity-0 sm:group-hover:opacity-100 sm:focus-visible:opacity-100' : ''
} ${klass}`
);
@@ -26,7 +26,7 @@
class="relative z-(--z-raised) flex-1 px-4 py-1.5 text-center text-xs font-medium transition-colors {value ===
option.value
? 'text-ink'
: 'text-fg-2 hover:text-fg-2'}"
: 'text-fg-2'}"
>
{option.label}
</button>
+4 -32
View File
@@ -1,6 +1,6 @@
import { browser } from '$app/environment';
import { DEFAULT_ACCENT } from '$lib/theme/color';
import { extractAccent, type Accent } from '$lib/theme/palette';
import { extractAccent } from '$lib/theme/palette';
import { shuffle } from '$lib/data/collections';
import { dialog } from '$lib/state/dialog.svelte';
import { ListenTracker } from './listenTracker';
@@ -17,12 +17,6 @@ export interface PlayerTrack {
listensCount?: number | string;
}
export interface Playlist {
id: string | number;
name: string;
trackIds: (string | number)[];
}
export interface QueueItem {
id: string | number;
title: string;
@@ -139,7 +133,6 @@ class PlayerState {
muted = $state(browser ? readStorage(MUTED_KEY) === 'true' : false);
loading = $state(false);
recentlyPlayed = $state<PlayerTrack[]>([]);
playlists = $state<Playlist[]>([]);
shuffle = $state(false);
repeat = $state(false);
@@ -147,7 +140,7 @@ class PlayerState {
#audio: HTMLAudioElement | null = null;
#loadToken = 0;
#accentCache = new Map<string, Accent>();
#accentCache = new Map<string, string>();
#rafId: number | null = null;
#listen = new ListenTracker();
@@ -157,10 +150,6 @@ class PlayerState {
this.current.duration > 0 ? Math.min(100, (this.progress / this.current.duration) * 100) : 0
);
get isPlaying() {
return this.playing;
}
#audioEl(): HTMLAudioElement | null {
if (!browser) return null;
if (this.#audio) return this.#audio;
@@ -301,14 +290,14 @@ class PlayerState {
const key = String(id);
const cached = this.#accentCache.get(key);
if (cached) {
this.accentColor = cached.accent;
this.accentColor = cached;
return;
}
const result = await extractAccent(`/api/tracks/${id}/cover?size=small`);
if (this.currentId !== id) return;
if (result) {
this.#accentCache.set(key, result);
this.accentColor = result.accent;
this.accentColor = result;
} else {
this.accentColor = null;
}
@@ -395,12 +384,6 @@ class PlayerState {
this.#syncMediaSessionMetadata(track);
}
playlistTracks(ids: (string | number)[]): PlayerTrack[] {
return ids
.map((id) => this.tracks.find((t) => t.id === id))
.filter((t): t is PlayerTrack => Boolean(t));
}
playQueue(list: QueueItem[], startIndex = 0) {
if (list.length === 0) return;
this.tracks = list.map(toTrack);
@@ -415,10 +398,6 @@ class PlayerState {
else this.playQueue(list, index);
}
playNextItem(item: QueueItem) {
this.playNext([item]);
}
playNext(items: QueueItem[]) {
if (items.length === 0) return;
if (this.currentId === null) {
@@ -452,13 +431,6 @@ class PlayerState {
this.#loadCurrent();
}
playPlaylist(id: string | number) {
const playlist = this.playlists.find((p) => p.id === id);
if (!playlist) return;
const items = this.playlistTracks(playlist.trackIds);
if (items.length > 0) this.playQueue(items, 0);
}
toggle() {
const audio = this.#audioEl();
if (!audio || this.currentId === null) return;
+1 -1
View File
@@ -51,7 +51,7 @@ function sessionKey(): Promise<Uint8Array> {
return keyPromise;
}
export function sessionCookieOptions(url: URL) {
function sessionCookieOptions(url: URL) {
return {
httpOnly: true,
sameSite: 'lax' as const,
+1 -1
View File
@@ -21,7 +21,7 @@ export function createTrackMenu() {
},
playNext() {
if (!state) return;
player.playNextItem(toQueueItem(state.track));
player.playNext([toQueueItem(state.track)]);
state = null;
}
};
+2 -12
View File
@@ -1,11 +1,6 @@
import { browser } from '$app/environment';
import { ACCENT_LIGHTNESS } from './color';
export interface Accent {
accent: string;
gradient: string;
}
function srgbToLinear(channel: number): number {
const c = channel / 255;
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
@@ -45,7 +40,7 @@ function loadImage(url: string): Promise<HTMLImageElement> {
const BUCKETS = 36;
export async function extractAccent(url: string): Promise<Accent | null> {
export async function extractAccent(url: string): Promise<string | null> {
if (!browser) return null;
let img: HTMLImageElement;
@@ -104,11 +99,6 @@ export async function extractAccent(url: string): Promise<Accent | null> {
const h = hue.toFixed(1);
const c = chroma.toFixed(3);
const c2 = (chroma * 0.85).toFixed(3);
const h2 = ((hue + 25) % 360).toFixed(1);
return {
accent: `oklch(${ACCENT_LIGHTNESS}% ${c} ${h})`,
gradient: `linear-gradient(135deg, oklch(74% ${c} ${h}), oklch(56% ${c2} ${h2}))`
};
return `oklch(${ACCENT_LIGHTNESS}% ${c} ${h})`;
}