feat: bring over the albums, explore and player work from the worktree
Moves the remaining uncommitted work: the home gets quick mixes and a "Tus álbumes" shelf, saving a YouTube album now goes through addYoutubeAlbumToPlaylistAction instead of the SaveYouTubeAlbum command, and UserAlbum drops its unused ExternalId. The mixes section keeps its current shape (no refresh action, no badge, hidden when empty) rather than the older version the worktree carried.
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import { createApiClient, requireUser, unwrapOrError } from '$lib/server/api';
|
||||
import {
|
||||
createApiClient,
|
||||
requireAccessTokenAction,
|
||||
requireUser,
|
||||
unwrapOrError
|
||||
} from '$lib/server/api';
|
||||
import { addYouTubeToPlaylistAction } from '$lib/server/playlistActions';
|
||||
addYouTubeToPlaylistAction,
|
||||
addYoutubeAlbumToPlaylistAction
|
||||
} from '$lib/server/playlistActions';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, locals, url, fetch }) => {
|
||||
const user = requireUser(locals, url);
|
||||
@@ -26,27 +23,5 @@ export const load: PageServerLoad = async ({ params, locals, url, fetch }) => {
|
||||
|
||||
export const actions: Actions = {
|
||||
addYouTubeToPlaylist: addYouTubeToPlaylistAction,
|
||||
|
||||
save: async ({ params, locals, fetch }) => {
|
||||
const accessToken = requireAccessTokenAction(locals);
|
||||
if (typeof accessToken !== 'string') return accessToken;
|
||||
|
||||
const api = createApiClient({ fetch, accessToken });
|
||||
const {
|
||||
data,
|
||||
error: err,
|
||||
response
|
||||
} = await api.POST('/albums/youtube/{albumId}', {
|
||||
params: { path: { albumId: params.albumId } }
|
||||
});
|
||||
|
||||
if (response?.status === 409) {
|
||||
return fail(409, { message: 'Ese álbum ya está en tu biblioteca.' });
|
||||
}
|
||||
if (err || !data) {
|
||||
return fail(502, { message: 'No se pudo guardar el álbum.' });
|
||||
}
|
||||
|
||||
redirect(303, `/albums/${data.id}`);
|
||||
}
|
||||
addYoutubeAlbumToPlaylist: addYoutubeAlbumToPlaylistAction
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import ArrowLeft from '@lucide/svelte/icons/arrow-left';
|
||||
import Play from '@lucide/svelte/icons/play';
|
||||
import Pause from '@lucide/svelte/icons/pause';
|
||||
import Plus from '@lucide/svelte/icons/plus';
|
||||
import { player, type QueueItem } from '$lib/player/player.svelte';
|
||||
import { hueFor } from '$lib/theme/color';
|
||||
import { fmtTime } from '$lib/format';
|
||||
@@ -20,6 +18,10 @@
|
||||
contextMenuStateFor,
|
||||
type ContextMenuState
|
||||
} from '$lib/components/TrackContextMenu.svelte';
|
||||
import AlbumContextMenu, {
|
||||
albumContextMenuStateFor,
|
||||
type AlbumMenuState
|
||||
} from '$lib/components/AlbumContextMenu.svelte';
|
||||
import type { TrackTarget } from '$lib/tracks';
|
||||
|
||||
let { data, form } = $props();
|
||||
@@ -28,7 +30,7 @@
|
||||
const tracks = $derived(data.album.tracks);
|
||||
|
||||
let contextMenu = $state<ContextMenuState | null>(null);
|
||||
let saving = $state(false);
|
||||
let albumMenu = $state<AlbumMenuState | null>(null);
|
||||
|
||||
const queue = $derived<QueueItem[]>(
|
||||
tracks.map((track) => ({
|
||||
@@ -94,6 +96,7 @@
|
||||
size="large"
|
||||
alt={album.title}
|
||||
class="h-36 w-36 shrink-0 rounded-art-lg shadow-art-lg sm:h-44 sm:w-44"
|
||||
oncontextmenu={(e) => (albumMenu = albumContextMenuStateFor(e, 'youtube', album.albumId))}
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-sm tracking-[0.14em] text-fg-3 uppercase">
|
||||
@@ -127,22 +130,6 @@
|
||||
Reproducir
|
||||
{/if}
|
||||
</Button>
|
||||
<form
|
||||
method="POST"
|
||||
action="?/save"
|
||||
use:enhance={() => {
|
||||
saving = true;
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
saving = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<Button type="submit" size="sm" variant="secondary" loading={saving}>
|
||||
<Plus class="h-4 w-4" strokeWidth={2} />
|
||||
Guardar en mi biblioteca
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{#if form?.message}
|
||||
@@ -150,7 +137,7 @@
|
||||
{/if}
|
||||
|
||||
{#if data.album.description}
|
||||
<p class="mt-6 max-w-3xl text-sm text-fg-3">{data.album.description}</p>
|
||||
<p class="mt-6 text-sm text-fg-3">{data.album.description}</p>
|
||||
{/if}
|
||||
|
||||
<TrackTable columns="32px 1fr 64px" columnsMobile="28px 1fr 52px" class="mt-6 sm:mt-8">
|
||||
@@ -197,3 +184,11 @@
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if albumMenu}
|
||||
<AlbumContextMenu
|
||||
menu={albumMenu}
|
||||
playlists={data.playlists}
|
||||
onClose={() => (albumMenu = null)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user