feat(frontend): add (app) route group and rework auth routing
Move authenticated pages under an (app) group with a Sidebar shell, add /auth/login and page-based /login, drop the old explore page and login +server endpoint, and add the server upload helper.
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { createApiClient } from '$lib/server/api';
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
|
||||
export const load: PageServerLoad = async ({ locals, fetch }) => {
|
||||
if (!locals.user) error(401, 'Inicia sesión.');
|
||||
|
||||
const api = createApiClient({ fetch, accessToken: locals.accessToken ?? undefined });
|
||||
const { data, error: err } = await api.GET('/tracks/users/{userId}', {
|
||||
params: { path: { userId: locals.user.sub }, query: { pageNumber: 1, pageSize: PAGE_SIZE } }
|
||||
});
|
||||
|
||||
if (err || !data) error(502, 'No se pudo cargar tu biblioteca.');
|
||||
|
||||
return { tracks: data };
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
<script lang="ts">
|
||||
import Upload from '@lucide/svelte/icons/upload';
|
||||
import { player } from '$lib/player/player.svelte';
|
||||
import { HUES } from '$lib/theme/color';
|
||||
import Cover from '$lib/components/ui/Cover.svelte';
|
||||
import NowPlaying from '$lib/components/ui/NowPlaying.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const items = $derived(data.tracks.items);
|
||||
const total = $derived(Number(data.tracks.totalItemCount));
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat('es', { dateStyle: 'medium' });
|
||||
|
||||
function hueFor(id: string) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||||
return HUES[hash % HUES.length];
|
||||
}
|
||||
|
||||
function togglePlay(index: number) {
|
||||
const track = items[index];
|
||||
if (player.current.id === track.id) player.toggle();
|
||||
else player.playQueue(items, index);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Tu biblioteca · Musify</title>
|
||||
<meta name="description" content="Todas tus canciones en Musify." />
|
||||
</svelte:head>
|
||||
|
||||
<section class="px-8 py-11">
|
||||
<div class="flex items-end justify-between gap-4">
|
||||
<div>
|
||||
<h1 class="font-display text-[28px] font-extrabold tracking-tight">Tu biblioteca</h1>
|
||||
<p class="mt-1.5 text-sm text-[var(--mf-text-2)]">
|
||||
{total}
|
||||
{total === 1 ? 'canción' : 'canciones'} en tu biblioteca.
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
href="/upload"
|
||||
class="inline-flex items-center gap-2 rounded-lg bg-[var(--mf-accent)] px-5 py-2.5 text-sm font-semibold text-neutral-950 transition hover:brightness-110 hover:shadow-[0_8px_24px_-8px] active:scale-[0.97]"
|
||||
>
|
||||
<Upload class="h-4 w-4" />
|
||||
Subir música
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{#if items.length > 0}
|
||||
<div class="mt-7 flex max-w-[900px] flex-col">
|
||||
{#each items as track, i (track.id)}
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => togglePlay(i)}
|
||||
class="animate-enter flex items-center gap-3.5 rounded-[10px] px-3 py-[11px] text-left transition duration-100 hover:bg-[var(--mf-surface-hover)] active:scale-[0.99]"
|
||||
style="animation-delay:{i * 35}ms"
|
||||
>
|
||||
<Cover
|
||||
trackId={track.id}
|
||||
hue={hueFor(track.id)}
|
||||
size="small"
|
||||
alt={track.title}
|
||||
class="h-[46px] w-[46px] flex-shrink-0 rounded-md"
|
||||
>
|
||||
{#if player.current.id === track.id}
|
||||
<NowPlaying paused={!player.playing} />
|
||||
{/if}
|
||||
</Cover>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="truncate text-[14.5px] font-semibold text-[var(--mf-text)]">
|
||||
{track.title}
|
||||
</div>
|
||||
<div class="truncate text-[12.5px] text-[var(--mf-text-3)]">
|
||||
{dateFormatter.format(new Date(track.createdAt))}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="mt-7 max-w-[560px] rounded-xl border border-[var(--mf-border)] bg-[var(--mf-surface)] px-6 py-10 text-center"
|
||||
>
|
||||
<p class="text-sm text-[var(--mf-text-2)]">Todavía no tienes canciones</p>
|
||||
<a
|
||||
href="/upload"
|
||||
class="mt-4 inline-flex items-center gap-2 rounded-lg bg-[var(--mf-accent)] px-5 py-2.5 text-sm font-semibold text-neutral-950 transition hover:brightness-110 hover:shadow-[0_8px_24px_-8px] active:scale-[0.97]"
|
||||
>
|
||||
<Upload class="h-4 w-4" />
|
||||
Sube la primera
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
Reference in New Issue
Block a user