web-player: fix playlist ownership, sidebar counts, home spotlight and assorted page bugs
This commit is contained in:
Vendored
+1
@@ -940,6 +940,7 @@ export interface components {
|
||||
smallImageKeyName: null | string;
|
||||
mediumImageKeyName: null | string;
|
||||
largeImageKeyName: null | string;
|
||||
ownerUserId: string;
|
||||
visibility: components["schemas"]["PlaylistVisibility"];
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
import Plus from '@lucide/svelte/icons/plus';
|
||||
import Logo from '../ui/primitives/Logo.svelte';
|
||||
|
||||
const SIDEBAR_PLAYLISTS_LIMIT = 8;
|
||||
|
||||
interface SidebarPlaylist {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -19,11 +21,14 @@
|
||||
interface Props {
|
||||
user: SessionUser | null;
|
||||
playlists: SidebarPlaylist[];
|
||||
playlistCount: number;
|
||||
}
|
||||
|
||||
let { user, playlists }: Props = $props();
|
||||
let { user, playlists, playlistCount }: Props = $props();
|
||||
|
||||
const navLinks = $derived(appNavLinks(user, { playlists: playlists.length, liked: liked.count }));
|
||||
const visiblePlaylists = $derived(playlists.slice(0, SIDEBAR_PLAYLISTS_LIMIT));
|
||||
|
||||
const navLinks = $derived(appNavLinks(user, { playlists: playlistCount, liked: liked.count }));
|
||||
|
||||
function isActive(href: string) {
|
||||
return isSectionActive(href, page.url.pathname, page.data.section);
|
||||
@@ -61,7 +66,7 @@
|
||||
<div class="mx-3 mt-6 mb-3.5 h-px bg-line"></div>
|
||||
<div class="flex items-center justify-between px-3 pb-1.5">
|
||||
<span class="text-eyebrow text-fg-2">Tus playlists</span>
|
||||
{#if playlists.length > 0}
|
||||
{#if visiblePlaylists.length > 0}
|
||||
<IconButton
|
||||
label="Crear playlist"
|
||||
tone="plain"
|
||||
@@ -74,7 +79,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex min-h-0 flex-1 flex-col gap-px overflow-y-auto pb-icon-md">
|
||||
{#each playlists as playlist (playlist.id)}
|
||||
{#each visiblePlaylists as playlist (playlist.id)}
|
||||
{@const active = page.url.pathname === `/playlists/${playlist.id}`}
|
||||
<ListRow
|
||||
href="/playlists/{playlist.id}"
|
||||
|
||||
@@ -37,9 +37,16 @@
|
||||
function onInput(event: Event) {
|
||||
const file = (event.currentTarget as HTMLInputElement).files?.[0];
|
||||
if (!file) return;
|
||||
releasePreview();
|
||||
preview = URL.createObjectURL(file);
|
||||
onselect?.(file);
|
||||
}
|
||||
|
||||
function releasePreview() {
|
||||
if (preview !== '') URL.revokeObjectURL(preview);
|
||||
}
|
||||
|
||||
$effect(() => releasePreview);
|
||||
</script>
|
||||
|
||||
<label
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{/if}
|
||||
<MenuItem
|
||||
icon={themeMode.current === 'dark' ? Sun : Moon}
|
||||
label={themeMode.current === 'dark' ? 'Modo blanco' : 'Modo oscuro'}
|
||||
label={themeMode.current === 'dark' ? 'Modo claro' : 'Modo oscuro'}
|
||||
onclick={() => themeMode.toggle()}
|
||||
/>
|
||||
<form method="POST" action="/auth/logout" data-sveltekit-reload>
|
||||
|
||||
@@ -9,15 +9,19 @@
|
||||
description: string;
|
||||
confirmLabel: string;
|
||||
action: string;
|
||||
fields?: Record<string, string>;
|
||||
}
|
||||
|
||||
let { open, onClose, title, description, confirmLabel, action }: Props = $props();
|
||||
let { open, onClose, title, description, confirmLabel, action, fields = {} }: Props = $props();
|
||||
</script>
|
||||
|
||||
<Dialog {open} {onClose} {title} {description}>
|
||||
{#snippet actions()}
|
||||
<Button variant="secondary" onclick={onClose}>Cancelar</Button>
|
||||
<form method="POST" {action}>
|
||||
{#each Object.entries(fields) as [name, value] (name)}
|
||||
<input type="hidden" {name} {value} />
|
||||
{/each}
|
||||
<Button type="submit" variant="danger">{confirmLabel}</Button>
|
||||
</form>
|
||||
{/snippet}
|
||||
|
||||
@@ -5,6 +5,7 @@ export const SEARCH_MIN_LENGTH = 2;
|
||||
export const INFINITE_SCROLL_ROOT_MARGIN = '300px';
|
||||
export const ALBUMS_PAGE_SIZE = 50;
|
||||
export const ALBUM_TRACKS_PAGE_SIZE = 200;
|
||||
export const PLAYLIST_TRACKS_PAGE_SIZE = 200;
|
||||
export const ALBUM_EARLIEST_YEAR = 1877;
|
||||
export const LIBRARY_PICKER_PAGE_SIZE = 50;
|
||||
export const EXPLORE_ALBUMS_PAGE_SIZE = 10;
|
||||
@@ -14,7 +15,6 @@ export const HOME_MIXES_LIMIT = 6;
|
||||
export const HOME_SHELF_LIMIT = 6;
|
||||
export const HOME_CONTINUE_LIMIT = 10;
|
||||
export const HOME_SPOTLIGHT_TRACKS_LIMIT = 5;
|
||||
export const HOME_POPULAR_MAX = 8;
|
||||
export const PLAYLIST_PICKER_PAGE_SIZE = 50;
|
||||
export const LIKED_TRACKS_PAGE_SIZE = 500;
|
||||
export const EXPLORE_USERS_LIMIT = 12;
|
||||
|
||||
@@ -6,3 +6,10 @@ export async function fetchAlbumQueueItems(albumId: string): Promise<QueueItem[]
|
||||
const data = (await res.json()) as { items: ApiTrackLike[] };
|
||||
return toQueueItems(data.items ?? []);
|
||||
}
|
||||
|
||||
export async function fetchPlaylistQueueItems(playlistId: string): Promise<QueueItem[]> {
|
||||
const res = await fetch(`/api/playlists/${playlistId}/tracks`);
|
||||
if (!res.ok) return [];
|
||||
const data = (await res.json()) as { items: ApiTrackLike[] };
|
||||
return toQueueItems(data.items ?? []);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ export async function getAllowAnonymousListening(fetchFn: typeof fetch): Promise
|
||||
|
||||
try {
|
||||
const api = createApiClient({ fetch: fetchFn });
|
||||
const { data } = await api.GET('/config/playback');
|
||||
const { data, error } = await api.GET('/config/playback');
|
||||
if (error !== undefined) return cached?.allowAnonymousListening ?? false;
|
||||
const allowAnonymousListening = data?.allowAnonymousListening ?? false;
|
||||
|
||||
cached = { allowAnonymousListening, expiresAt: Date.now() + CACHE_TTL_MS };
|
||||
|
||||
Reference in New Issue
Block a user