Add likes, follows and playlist visibility; redesign web-player UI
Backend: - New Likes feature (toggle/get liked tracks) and endpoints - User follow/unfollow, listening stats, public user profile - Playlist visibility (public/private) support - Various auth and DTO/response adjustments to support the above Frontend (web-player): - New design system pass: theme tokens/mode (light/dark), glass menu, tabs bar, player dock/extras/queue components, mix tiles, artist link - New routes: Liked, public user profile (/u/[id]), likes API proxy - Search refactor: shared SearchBox component used by TopBar and MobileHeader (search now reachable on mobile), live results as you type instead of requiring Enter, dropped the "Buscando…" quick-result preview - Removed now-unused components (MobileNav, CoverBadge, MixBentoTile, PlayPauseOverlay, SuggestionsTable, userDirectory) - Design handoff reference docs added under web-player/design_handoff_musify_player and web-player/docs/design-system-refactor-plan.md
This commit is contained in:
@@ -1,30 +1,71 @@
|
||||
<script lang="ts">
|
||||
import { player } from '$lib/player/player.svelte';
|
||||
import { liked } from '$lib/player/liked.svelte';
|
||||
import Cover from '$lib/components/ui/Cover.svelte';
|
||||
import ExplicitBadge from '$lib/components/ui/ExplicitBadge.svelte';
|
||||
import ArtistLink from '$lib/components/ui/ArtistLink.svelte';
|
||||
import Heart from '@lucide/svelte/icons/heart';
|
||||
|
||||
interface Props {
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
let { compact = false }: Props = $props();
|
||||
|
||||
const isLiked = $derived(player.current.id !== '' && liked.isLiked(player.current.id));
|
||||
|
||||
function toggleLike() {
|
||||
if (!player.current.id) return;
|
||||
liked.toggle({
|
||||
id: player.current.id,
|
||||
title: player.current.title,
|
||||
artist: player.current.artist,
|
||||
coverUrl: player.current.coverUrl,
|
||||
source: player.current.source,
|
||||
explicit: player.current.explicit,
|
||||
ownerUserId: player.current.ownerUserId
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex min-w-0 items-center gap-2.5 md:gap-3">
|
||||
<div class="flex min-w-0 items-center gap-2.5 md:gap-3.25">
|
||||
{#if player.current.id}
|
||||
<Cover
|
||||
trackId={player.current.id}
|
||||
src={player.current.coverUrl}
|
||||
size="small"
|
||||
alt={player.current.title}
|
||||
class="h-11 w-11 shrink-0 rounded-lg shadow-[0_6px_16px_-6px_rgba(0,0,0,0.6)] md:h-13 md:w-13"
|
||||
class="h-11 w-11 shrink-0 rounded-[11px] shadow-[0_8px_20px_rgba(0,0,0,0.5)] md:h-12 md:w-12"
|
||||
/>
|
||||
{:else}
|
||||
<div
|
||||
class="h-11 w-11 shrink-0 rounded-lg bg-surface shadow-[0_6px_16px_-6px_rgba(0,0,0,0.6)] md:h-13 md:w-13"
|
||||
class="h-11 w-11 shrink-0 rounded-[11px] bg-surface shadow-[0_8px_20px_rgba(0,0,0,0.5)] md:h-12 md:w-12"
|
||||
></div>
|
||||
{/if}
|
||||
<div class="min-w-0">
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex min-w-0 items-center gap-1.5">
|
||||
{#if player.current.explicit}
|
||||
<ExplicitBadge />
|
||||
{/if}
|
||||
<span class="truncate text-fg">{player.current.title}</span>
|
||||
<span class="truncate text-[13px] font-semibold tracking-[-0.01em] text-fg"
|
||||
>{player.current.title}</span
|
||||
>
|
||||
</div>
|
||||
<div class="truncate text-sm text-muted">{player.current.artist || '—'}</div>
|
||||
<ArtistLink
|
||||
name={player.current.artist || '—'}
|
||||
ownerUserId={player.current.ownerUserId}
|
||||
class="mt-0.5 text-[11.5px] text-fg-3"
|
||||
/>
|
||||
</div>
|
||||
{#if !compact}
|
||||
<button
|
||||
type="button"
|
||||
onclick={toggleLike}
|
||||
aria-label={isLiked ? 'Quitar de Me gusta' : 'Añadir a Me gusta'}
|
||||
aria-pressed={isLiked}
|
||||
class="shrink-0 transition hover:opacity-80 {isLiked ? 'text-accent' : 'text-fg-3'}"
|
||||
>
|
||||
<Heart class="h-4 w-4" fill={isLiked ? 'currentColor' : 'none'} strokeWidth={1.7} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user