Unify web-player design tokens and componentize collection headers
Migrates remaining one-off colors (bg-white/[N%], border-white/N, hardcoded shadows/gradients) to the existing --mf-* tokens so light mode reacts consistently everywhere, including a fix to --color-hover which was hardcoded instead of pointing at --mf-surface-2. Extracts CollectionHeader (album/playlist/mix/liked headers) and AccountMenu (TopBar/MobileHeader) to remove five and two duplicated implementations respectively, and normalizes inconsistent empty-state copy.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import PlaylistArt from '$lib/components/ui/PlaylistArt.svelte';
|
||||
import BackLink from '$lib/components/ui/BackLink.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import CollectionHeader from '$lib/components/ui/CollectionHeader.svelte';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
@@ -48,45 +49,34 @@
|
||||
label={isOwner ? 'Volver a tus álbumes' : 'Volver al inicio'}
|
||||
/>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-5 sm:mt-4 sm:flex-row sm:items-end sm:gap-6">
|
||||
<PlaylistArt
|
||||
{trackIds}
|
||||
{coverUrl}
|
||||
size="large"
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-[0_24px_56px_rgba(0,0,0,.55)] sm:h-41 sm:w-41"
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">Álbum</p>
|
||||
<h1
|
||||
class="mt-1.5 font-display text-[28px] font-semibold tracking-[-0.035em] break-words text-fg sm:text-[33px]"
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
{#if description}
|
||||
<p class="mt-3 max-w-2xl text-sm text-fg-2 sm:text-base">{description}</p>
|
||||
{/if}
|
||||
<p class="mt-3 text-sm text-muted">{meta}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2.5 sm:mt-7">
|
||||
<Button size="sm" onclick={onPlayAll} disabled={trackIds.length === 0}>
|
||||
{#if playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
{#if isOwner}
|
||||
<Button size="sm" variant="secondary" onclick={onEdit}>
|
||||
<SquarePencil class="h-4 w-4" strokeWidth={1.5} />
|
||||
Editar
|
||||
<CollectionHeader eyebrow="Álbum" {title} {description} {meta}>
|
||||
{#snippet cover()}
|
||||
<PlaylistArt
|
||||
{trackIds}
|
||||
{coverUrl}
|
||||
size="large"
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-cover-lg sm:h-41 sm:w-41"
|
||||
/>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={onPlayAll} disabled={trackIds.length === 0}>
|
||||
{#if playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onDelete}>
|
||||
<Trash class="h-4 w-4" strokeWidth={1.5} />
|
||||
Eliminar
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if isOwner}
|
||||
<Button size="sm" variant="secondary" onclick={onEdit}>
|
||||
<SquarePencil class="h-4 w-4" strokeWidth={1.5} />
|
||||
Editar
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onDelete}>
|
||||
<Trash class="h-4 w-4" strokeWidth={1.5} />
|
||||
Eliminar
|
||||
</Button>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</CollectionHeader>
|
||||
|
||||
+35
-42
@@ -8,6 +8,7 @@
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Cover from '$lib/components/ui/Cover.svelte';
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import CollectionHeader from '$lib/components/ui/CollectionHeader.svelte';
|
||||
import TrackTable from '$lib/components/ui/TrackTable.svelte';
|
||||
import TrackRow from '$lib/components/ui/TrackRow.svelte';
|
||||
import TrackMeta from '$lib/components/ui/TrackMeta.svelte';
|
||||
@@ -79,48 +80,40 @@
|
||||
<Page>
|
||||
<BackLink href="/explore" label="Volver a explorar" />
|
||||
|
||||
<div class="mt-3 flex flex-col gap-5 sm:mt-4 sm:flex-row sm:items-end sm:gap-6">
|
||||
<Cover
|
||||
trackId={album.albumId}
|
||||
src={album.thumbnailUrl}
|
||||
size="large"
|
||||
alt={album.title}
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-[0_24px_56px_rgba(0,0,0,.55)] sm:h-41 sm:w-41"
|
||||
oncontextmenu={(e) => (albumMenu = albumContextMenuStateFor(e, 'youtube', album.albumId))}
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">
|
||||
{album.isSingle ? 'Single' : album.isEp ? 'EP' : 'Álbum'}
|
||||
</p>
|
||||
<h1
|
||||
class="mt-1.5 font-display text-[28px] font-semibold tracking-[-0.035em] break-words text-fg sm:text-[33px]"
|
||||
>
|
||||
{album.title}
|
||||
</h1>
|
||||
<p class="mt-3 text-base text-fg-2">{album.artist}</p>
|
||||
<p class="mt-1 text-sm text-muted">
|
||||
{[
|
||||
album.releaseYear ? String(album.releaseYear) : undefined,
|
||||
`${tracks.length} ${tracks.length === 1 ? 'canción' : 'canciones'}`,
|
||||
fmtTime(Number(data.album.totalDurationSeconds))
|
||||
]
|
||||
.filter((part) => !!part)
|
||||
.join(' · ')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2.5 sm:mt-7">
|
||||
<Button size="sm" onclick={playAll} disabled={queue.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
<CollectionHeader
|
||||
eyebrow={album.isSingle ? 'Single' : album.isEp ? 'EP' : 'Álbum'}
|
||||
title={album.title}
|
||||
description={album.artist}
|
||||
meta={[
|
||||
album.releaseYear ? String(album.releaseYear) : undefined,
|
||||
`${tracks.length} ${tracks.length === 1 ? 'canción' : 'canciones'}`,
|
||||
fmtTime(Number(data.album.totalDurationSeconds))
|
||||
]
|
||||
.filter((part) => !!part)
|
||||
.join(' · ')}
|
||||
>
|
||||
{#snippet cover()}
|
||||
<Cover
|
||||
trackId={album.albumId}
|
||||
src={album.thumbnailUrl}
|
||||
size="large"
|
||||
alt={album.title}
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-cover-lg sm:h-41 sm:w-41"
|
||||
oncontextmenu={(e) => (albumMenu = albumContextMenuStateFor(e, 'youtube', album.albumId))}
|
||||
/>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={playAll} disabled={queue.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
{/snippet}
|
||||
</CollectionHeader>
|
||||
|
||||
{#if form?.message}
|
||||
<Alert tone="danger" class="mt-4">{form.message}</Alert>
|
||||
|
||||
@@ -313,7 +313,7 @@
|
||||
Resultados de búsqueda
|
||||
</div>
|
||||
<h1
|
||||
class="font-display text-2xl font-semibold tracking-[-0.03em] text-pretty text-fg sm:text-[28px]"
|
||||
class="font-display text-2xl font-semibold tracking-[-0.03em] text-pretty text-fg sm:text-3xl"
|
||||
>
|
||||
Resultados para «{data.query}»
|
||||
</h1>
|
||||
@@ -331,13 +331,11 @@
|
||||
class="flex items-center gap-1.75 rounded-full px-3.5 py-1.75 text-xs font-medium transition {sfilter ===
|
||||
chip.label
|
||||
? 'bg-cta-strong text-ink'
|
||||
: 'bg-white/[3.5%] text-fg-2 hover:bg-white/7 hover:text-fg'}"
|
||||
: 'bg-surface-2 text-fg-2 hover:bg-surface-hover hover:text-fg'}"
|
||||
>
|
||||
<span>{chip.label}</span>
|
||||
<span
|
||||
class="text-[10.5px] tabular-nums {sfilter === chip.label
|
||||
? 'opacity-55'
|
||||
: 'text-muted'}">{chip.count}</span
|
||||
<span class="text-xs tabular-nums {sfilter === chip.label ? 'opacity-55' : 'text-muted'}"
|
||||
>{chip.count}</span
|
||||
>
|
||||
</button>
|
||||
{/each}
|
||||
@@ -394,9 +392,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="flex h-22 min-w-0 flex-1 flex-col justify-center gap-3">
|
||||
<div
|
||||
class="text-xs leading-none font-semibold tracking-[0.14em] text-fg-3 uppercase"
|
||||
>
|
||||
<div class="text-xs leading-none font-semibold tracking-[0.14em] text-fg-3 uppercase">
|
||||
Mejor resultado · {TOP_RESULT_KIND_LABEL[topResult.kind]}
|
||||
</div>
|
||||
<div
|
||||
@@ -456,7 +452,7 @@
|
||||
<h1 class="font-display text-xl font-semibold tracking-[-0.025em] text-fg">
|
||||
Sin resultados para «{data.query}»
|
||||
</h1>
|
||||
<p class="mt-2.5 text-[13px] leading-[1.65] text-fg-2">
|
||||
<p class="mt-2.5 text-sm leading-[1.65] text-fg-2">
|
||||
Revisa la ortografía o prueba con un término más corto. También puedes buscar por álbum o
|
||||
por playlist.
|
||||
</p>
|
||||
@@ -464,7 +460,7 @@
|
||||
{#each genreTiles.slice(0, 4) as genre (genre.query)}
|
||||
<a
|
||||
href={buildHref(genre.query)}
|
||||
class="rounded-full border border-white/8 px-3.5 py-2 text-xs text-fg-2 transition-colors hover:bg-white/5 hover:text-fg"
|
||||
class="rounded-full border border-line-strong px-3.5 py-2 text-xs text-fg-2 transition-colors hover:bg-hover hover:text-fg"
|
||||
>
|
||||
{genre.label}
|
||||
</a>
|
||||
@@ -481,12 +477,12 @@
|
||||
href={buildHref(genre.query)}
|
||||
class="animate-enter group relative block h-28 overflow-hidden rounded-2xl p-4.25 transition-[filter] hover:brightness-125"
|
||||
style="animation-delay:{Math.min(i, 10) *
|
||||
40}ms; background:linear-gradient(140deg, oklch(0.24 0.07 {genre.hue}), rgba(9,9,12,.95))"
|
||||
40}ms; background:linear-gradient(140deg, oklch(0.24 0.07 {genre.hue}), var(--mf-ink))"
|
||||
>
|
||||
<div class="font-display text-[15.5px] font-semibold tracking-[-0.02em] text-fg">
|
||||
<div class="font-display text-base font-semibold tracking-[-0.02em] text-fg">
|
||||
{genre.label}
|
||||
</div>
|
||||
<div class="mt-1.5 text-[11.5px] text-fg-3">{genre.tagline}</div>
|
||||
<div class="mt-1.5 text-xs text-fg-3">{genre.tagline}</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -500,7 +496,7 @@
|
||||
<SectionHeading title="Canciones">
|
||||
{#snippet actions()}
|
||||
<div class="h-px flex-1 self-center bg-line"></div>
|
||||
<span class="shrink-0 text-[11px] text-muted tabular-nums">
|
||||
<span class="shrink-0 text-xs text-muted tabular-nums">
|
||||
{searchCounts.Canciones}
|
||||
{searchCounts.Canciones === 1 ? 'Resultado' : 'Resultados'}
|
||||
</span>
|
||||
@@ -553,7 +549,7 @@
|
||||
<SectionHeading title="Álbumes">
|
||||
{#snippet actions()}
|
||||
<div class="h-px flex-1 self-center bg-line"></div>
|
||||
<span class="shrink-0 text-[11px] text-muted tabular-nums">
|
||||
<span class="shrink-0 text-xs text-muted tabular-nums">
|
||||
{searchCounts.Álbumes}
|
||||
{searchCounts.Álbumes === 1 ? 'Resultado' : 'Resultados'}
|
||||
</span>
|
||||
@@ -605,7 +601,7 @@
|
||||
<SectionHeading title="Usuarios">
|
||||
{#snippet actions()}
|
||||
<div class="h-px flex-1 self-center bg-line"></div>
|
||||
<span class="shrink-0 text-[11px] text-muted tabular-nums">
|
||||
<span class="shrink-0 text-xs text-muted tabular-nums">
|
||||
{searchCounts.Usuarios}
|
||||
{searchCounts.Usuarios === 1 ? 'Resultado' : 'Resultados'}
|
||||
</span>
|
||||
@@ -638,7 +634,7 @@
|
||||
<SectionHeading title="Playlists">
|
||||
{#snippet actions()}
|
||||
<div class="h-px flex-1 self-center bg-line"></div>
|
||||
<span class="shrink-0 text-[11px] text-muted tabular-nums">
|
||||
<span class="shrink-0 text-xs text-muted tabular-nums">
|
||||
{searchCounts.Playlists}
|
||||
{searchCounts.Playlists === 1 ? 'Resultado' : 'Resultados'}
|
||||
</span>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { liked } from '$lib/player/liked.svelte';
|
||||
import { fmtDate } from '$lib/format';
|
||||
import Page from '$lib/components/ui/Page.svelte';
|
||||
import CollectionHeader from '$lib/components/ui/CollectionHeader.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import IconButton from '$lib/components/ui/IconButton.svelte';
|
||||
import EmptyState from '$lib/components/ui/EmptyState.svelte';
|
||||
@@ -46,38 +47,31 @@
|
||||
</svelte:head>
|
||||
|
||||
<Page>
|
||||
<div class="flex flex-col gap-5 sm:flex-row sm:items-center sm:gap-6">
|
||||
<div
|
||||
class="grid h-36 w-36 shrink-0 place-items-center rounded-[18px] shadow-[0_24px_56px_rgba(0,0,0,.55)] sm:h-41 sm:w-41"
|
||||
style="background:linear-gradient(150deg, oklch(0.4 0.09 330), oklch(0.18 0.04 10))"
|
||||
>
|
||||
<Heart class="h-10 w-10 text-white/90" fill="currentColor" strokeWidth={0} />
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">Colección</p>
|
||||
<h1
|
||||
class="mt-3 font-display text-[28px] font-semibold tracking-[-0.035em] text-fg sm:text-[33px]"
|
||||
<CollectionHeader
|
||||
eyebrow="Colección"
|
||||
title="Me gusta"
|
||||
meta="{tracks.length} {tracks.length === 1 ? 'canción' : 'canciones'}"
|
||||
align="center"
|
||||
>
|
||||
{#snippet cover()}
|
||||
<div
|
||||
class="grid h-36 w-36 shrink-0 place-items-center rounded-[18px] bg-[image:var(--mf-liked-grad)] shadow-cover-lg sm:h-41 sm:w-41"
|
||||
>
|
||||
Me gusta
|
||||
</h1>
|
||||
<p class="mt-3.25 text-[12.5px] text-fg-2">
|
||||
{tracks.length}
|
||||
{tracks.length === 1 ? 'canción' : 'canciones'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2.5 sm:mt-7">
|
||||
<Button size="sm" onclick={playAll} disabled={tracks.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
<Heart class="h-10 w-10 text-on-art/90" fill="currentColor" strokeWidth={0} />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={playAll} disabled={tracks.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
{/snippet}
|
||||
</CollectionHeader>
|
||||
|
||||
{#if tracks.length > 0}
|
||||
<TrackTable
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import MixArt from '$lib/components/ui/MixArt.svelte';
|
||||
import CollectionHeader from '$lib/components/ui/CollectionHeader.svelte';
|
||||
import TrackTable from '$lib/components/ui/TrackTable.svelte';
|
||||
import TrackRow from '$lib/components/ui/TrackRow.svelte';
|
||||
import TrackMeta from '$lib/components/ui/TrackMeta.svelte';
|
||||
@@ -67,43 +68,31 @@
|
||||
<Page>
|
||||
<BackLink href="/" label="Volver al inicio" />
|
||||
|
||||
<div class="mt-3 flex flex-col gap-5 sm:mt-4 sm:flex-row sm:items-end sm:gap-6">
|
||||
<MixArt
|
||||
{items}
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-[0_24px_56px_rgba(0,0,0,.55)] sm:h-41 sm:w-41"
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">Mezcla</p>
|
||||
<h1
|
||||
class="mt-1.5 font-display text-[28px] font-semibold tracking-[-0.035em] break-words text-fg sm:text-[33px]"
|
||||
>
|
||||
{mix.title}
|
||||
</h1>
|
||||
{#if mix.subtitle}
|
||||
<p class="mt-3 text-base text-fg-2">{mix.subtitle}</p>
|
||||
{/if}
|
||||
<p class="mt-1 text-sm text-muted">
|
||||
{items.length}
|
||||
{items.length === 1 ? 'canción' : 'canciones'} · {fmtTime(totalSeconds)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2.5 sm:mt-7">
|
||||
<Button size="sm" onclick={playAll} disabled={queue.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<Button variant="secondary" size="sm" onclick={playShuffled} disabled={queue.length === 0}>
|
||||
<Shuffle class="h-4 w-4" />
|
||||
Aleatorio
|
||||
</Button>
|
||||
</div>
|
||||
<CollectionHeader
|
||||
eyebrow="Mezcla"
|
||||
title={mix.title}
|
||||
description={mix.subtitle ?? undefined}
|
||||
meta="{items.length} {items.length === 1 ? 'canción' : 'canciones'} · {fmtTime(totalSeconds)}"
|
||||
>
|
||||
{#snippet cover()}
|
||||
<MixArt {items} class="h-36 w-36 shrink-0 rounded-[18px] shadow-cover-lg sm:h-41 sm:w-41" />
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={playAll} disabled={queue.length === 0}>
|
||||
{#if isCurrentQueue && player.playing}
|
||||
<Pause class="h-4 w-4" strokeWidth={1.5} />
|
||||
Pausar
|
||||
{:else}
|
||||
<Play class="h-4 w-4" strokeWidth={1.5} />
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<Button variant="secondary" size="sm" onclick={playShuffled} disabled={queue.length === 0}>
|
||||
<Shuffle class="h-4 w-4" />
|
||||
Aleatorio
|
||||
</Button>
|
||||
{/snippet}
|
||||
</CollectionHeader>
|
||||
|
||||
{#if form?.message}
|
||||
<Alert tone="danger" class="mt-4">{form.message}</Alert>
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
<h2 class="font-display text-xl font-semibold tracking-[-0.02em] text-fg">
|
||||
¿Eliminar «{playlist.name}»?
|
||||
</h2>
|
||||
<p class="mt-2.5 text-[13px] leading-[1.65] text-fg-2">
|
||||
<p class="mt-2.5 text-sm leading-[1.65] text-fg-2">
|
||||
Esta acción no se puede deshacer, la playlist se eliminará de tu biblioteca y de todos los
|
||||
dispositivos donde la tengas guardada.
|
||||
</p>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Play from '@lucide/svelte/icons/play';
|
||||
import Pause from '@lucide/svelte/icons/pause';
|
||||
import SquarePencil from '@lucide/svelte/icons/square-pen';
|
||||
import Trash from '@lucide/svelte/icons/trash';
|
||||
import PlaylistArt from '$lib/components/ui/PlaylistArt.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import CollectionHeader from '$lib/components/ui/CollectionHeader.svelte';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
@@ -31,47 +28,39 @@
|
||||
onEdit,
|
||||
onDelete
|
||||
}: Props = $props();
|
||||
|
||||
const meta = $derived(
|
||||
`${trackIds.length} ${trackIds.length === 1 ? 'canción' : 'canciones'} · ${
|
||||
visibility === 'Public' ? 'Pública' : 'Privada'
|
||||
}`
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-5 sm:flex-row sm:items-center sm:gap-6">
|
||||
<PlaylistArt
|
||||
playlistId={id}
|
||||
{trackIds}
|
||||
size="large"
|
||||
version={updatedAt}
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-[0_24px_56px_rgba(0,0,0,.55)] sm:h-41 sm:w-41"
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">Lista</p>
|
||||
<h1
|
||||
class="mt-3 font-display text-[28px] font-semibold tracking-[-0.035em] break-words text-fg sm:text-[33px]"
|
||||
>
|
||||
{name}
|
||||
</h1>
|
||||
{#if description}
|
||||
<p class="mt-3 max-w-2xl text-sm text-fg-2 sm:text-base">{description}</p>
|
||||
{/if}
|
||||
<p class="mt-3.25 text-[12.5px] text-fg-2">
|
||||
{trackIds.length}
|
||||
{trackIds.length === 1 ? 'canción' : 'canciones'} · {visibility === 'Public'
|
||||
? 'Pública'
|
||||
: 'Privada'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2.5 sm:mt-7">
|
||||
<Button size="sm" onclick={onPlayAll} disabled={trackIds.length === 0}>
|
||||
{#if playing}
|
||||
Pausar
|
||||
{:else}
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onEdit}>
|
||||
Editar
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onDelete}>
|
||||
Eliminar
|
||||
</Button>
|
||||
</div>
|
||||
<CollectionHeader
|
||||
eyebrow="Lista"
|
||||
title={name}
|
||||
description={description ?? undefined}
|
||||
{meta}
|
||||
align="center"
|
||||
>
|
||||
{#snippet cover()}
|
||||
<PlaylistArt
|
||||
playlistId={id}
|
||||
{trackIds}
|
||||
size="large"
|
||||
version={updatedAt}
|
||||
class="h-36 w-36 shrink-0 rounded-[18px] shadow-cover-lg sm:h-41 sm:w-41"
|
||||
/>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={onPlayAll} disabled={trackIds.length === 0}>
|
||||
{#if playing}
|
||||
Pausar
|
||||
{:else}
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onEdit}>Editar</Button>
|
||||
<Button size="sm" variant="secondary" onclick={onDelete}>Eliminar</Button>
|
||||
{/snippet}
|
||||
</CollectionHeader>
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
<div class="flex flex-col gap-5 sm:flex-row sm:items-center sm:gap-6">
|
||||
<ArtistAvatar name={profile.name} imageUrl={profile.profilePictureUrl} size={144} />
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-[10.5px] font-semibold tracking-[0.16em] text-fg-2 uppercase">Perfil</p>
|
||||
<p class="text-xs font-semibold tracking-[0.16em] text-fg-2 uppercase">Perfil</p>
|
||||
<h1
|
||||
class="mt-3 font-display text-[28px] font-semibold tracking-[-0.035em] break-words text-fg sm:text-[33px]"
|
||||
class="mt-3 font-display text-3xl font-semibold tracking-[-0.035em] break-words text-fg sm:text-4xl"
|
||||
>
|
||||
{profile.name}
|
||||
</h1>
|
||||
<p class="mt-3.25 text-[12.5px] text-fg-2">
|
||||
<p class="mt-3.25 text-sm text-fg-2">
|
||||
{profile.followersCount}
|
||||
{profile.followersCount === 1 ? 'seguidor' : 'seguidores'} · {profile.followingCount} siguiendo
|
||||
</p>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
class="grid h-7 w-7 shrink-0 place-items-center rounded-full text-xs font-bold {stepStates[
|
||||
i
|
||||
] === 'idle'
|
||||
? 'bg-white/[3.5%] text-fg-2'
|
||||
? 'bg-surface-2 text-fg-2'
|
||||
: 'bg-accent-btn text-accent-soft'}"
|
||||
>
|
||||
{#if stepStates[i] === 'done'}
|
||||
@@ -228,7 +228,7 @@
|
||||
{#if coverPreview !== ''}
|
||||
<img src={coverPreview} alt="Portada" class="h-full w-full object-cover" />
|
||||
{:else}
|
||||
<ImageIcon class="h-11 w-11 text-white/70" strokeWidth={1.3} />
|
||||
<ImageIcon class="h-11 w-11 text-on-art/70" strokeWidth={1.3} />
|
||||
{/if}
|
||||
</label>
|
||||
</Field>
|
||||
|
||||
Reference in New Issue
Block a user