feat(web-player): rebuild Inicio and Buscar to the design handoff
Applies the handoff's layout and image shapes while keeping the current Musify design system (Inter, colors, tokens) — no font or palette swap. Inicio now stacks distinct shelves instead of repeated square grids: recently played rows, a rail of recently listened albums with an "Álbum" badge, a "Hecho para ti" bento of mixes, a rail of playlists with a trailing dashed "Ver todas" tile, tall "Canciones nuevas" posters with a "Nuevo" badge, a rail of circular top-artist avatars, and a recommended rail. Buscar splits into Álbumes (square cards + badge), Usuarios (a circular-avatar directory) and a flat Canciones list. Top artists and the search user directory are filler data until the backend exposes them. New shared pieces: Rail, CoverBadge, ArtistAvatar, MixBentoTile. The orphaned TrackTile and MixCard are removed.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { gradientForHue, hueFor } from '$lib/theme/color';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
name: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
let { id, name, size = 108 }: Props = $props();
|
||||
|
||||
const initials = $derived(
|
||||
name
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map((part) => part[0]?.toUpperCase() ?? '')
|
||||
.join('')
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-center gap-2.5 text-center" style="width:{size}px">
|
||||
<div
|
||||
class="relative grid shrink-0 place-items-center overflow-hidden rounded-full shadow-art ring-1 ring-line transition duration-300 ease-out ring-inset group-hover/artist:-translate-y-1 group-hover/artist:shadow-art-lg"
|
||||
style="width:{size}px;height:{size}px;background:{gradientForHue(hueFor(id))}"
|
||||
>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0"
|
||||
style="background:repeating-linear-gradient(135deg, rgba(255,255,255,0.12) 0 2px, transparent 2px 10px)"
|
||||
></div>
|
||||
<span class="relative text-lg font-semibold text-white/90">{initials}</span>
|
||||
</div>
|
||||
<div class="w-full truncate text-sm text-fg">{name}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
label: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
let { label, class: klass = '' }: Props = $props();
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="pointer-events-none absolute top-2 left-2 rounded-full bg-black/45 px-2 py-0.5 text-[10px] font-semibold tracking-[0.08em] text-white uppercase backdrop-blur-sm {klass}"
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import MixArt from './MixArt.svelte';
|
||||
import { hueFor } from '$lib/theme/color';
|
||||
import type { Mix } from '$lib/mixes';
|
||||
|
||||
interface Props {
|
||||
mix: Mix;
|
||||
featured?: boolean;
|
||||
banner?: boolean;
|
||||
class?: string;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
let { mix, featured = false, banner = false, class: klass = '', index = 0 }: Props = $props();
|
||||
</script>
|
||||
|
||||
<a
|
||||
href="/mixes/{mix.id}"
|
||||
class="group/tile animate-enter relative block overflow-hidden rounded-art shadow-art ring-1 ring-line transition duration-300 ease-out ring-inset hover:shadow-art-lg focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none {klass}"
|
||||
style="animation-delay:{Math.min(index, 10) * 45}ms"
|
||||
>
|
||||
<MixArt
|
||||
items={mix.items}
|
||||
hue={hueFor(mix.id)}
|
||||
class="absolute inset-0 h-full w-full transition duration-500 ease-out group-hover/tile:scale-[1.04]"
|
||||
/>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0"
|
||||
style="background:linear-gradient(to top, rgba(0,0,0,0.78) 0%, rgba(0,0,0,0.32) 42%, rgba(0,0,0,0.05) 100%)"
|
||||
></div>
|
||||
<div
|
||||
class="relative flex h-full flex-col justify-end p-3 sm:p-4 {banner
|
||||
? 'sm:flex-row sm:items-center sm:justify-between sm:gap-4'
|
||||
: ''}"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<div
|
||||
class="truncate font-semibold text-white {featured ? 'text-xl sm:text-2xl' : 'text-base'}"
|
||||
>
|
||||
{mix.title}
|
||||
</div>
|
||||
{#if mix.subtitle}
|
||||
<div class="mt-0.5 truncate text-xs text-white/70 sm:text-sm">{mix.subtitle}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -1,26 +0,0 @@
|
||||
<script lang="ts">
|
||||
import MediaCard from './MediaCard.svelte';
|
||||
import MixArt from './MixArt.svelte';
|
||||
import { hueFor } from '$lib/theme/color';
|
||||
import type { Mix } from '$lib/mixes';
|
||||
|
||||
interface Props {
|
||||
mix: Mix;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
let { mix, index = 0 }: Props = $props();
|
||||
|
||||
const count = $derived(Number(mix.itemCount));
|
||||
</script>
|
||||
|
||||
<MediaCard
|
||||
href="/mixes/{mix.id}"
|
||||
title={mix.title}
|
||||
subtitle="{count} {count === 1 ? 'canción' : 'canciones'}"
|
||||
{index}
|
||||
>
|
||||
{#snippet art(artClass)}
|
||||
<MixArt items={mix.items} hue={hueFor(mix.id)} class={artClass} />
|
||||
{/snippet}
|
||||
</MediaCard>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
children: Snippet;
|
||||
}
|
||||
|
||||
let { class: klass = '', children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="no-scrollbar -mx-1 flex gap-4 overflow-x-auto px-1 pb-2 {klass}">
|
||||
{@render children()}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.no-scrollbar {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
{#if actions}
|
||||
<div class="mb-3 flex items-baseline justify-between gap-4 sm:mb-4 {klass}">
|
||||
<h2 class="text-lg font-semibold tracking-tight text-fg sm:text-xl">{title}</h2>
|
||||
<h2 class="text-lg tracking-tight text-fg sm:text-[28px]">{title}</h2>
|
||||
{@render actions()}
|
||||
</div>
|
||||
{:else}
|
||||
<h2 class="mb-3 text-lg font-semibold tracking-tight text-fg sm:mb-4 sm:text-xl {klass}">
|
||||
<h2 class="mb-3 text-lg tracking-tight text-fg sm:mb-4 sm:text-[28px] {klass}">
|
||||
{title}
|
||||
</h2>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user