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,8 +1,44 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { LayoutServerLoad } from './$types';
|
||||
import { getAllowAnonymousListening } from '$lib/server/playbackConfig';
|
||||
import { createApiClient } from '$lib/server/api';
|
||||
import { authConfig } from '$lib/server/config';
|
||||
import { LIKED_TRACKS_PAGE_SIZE } from '$lib/config';
|
||||
|
||||
const PUBLIC_PATHS = new Set(['/login']);
|
||||
const SIDEBAR_PLAYLISTS_LIMIT = 8;
|
||||
|
||||
async function fetchSidebarPlaylists(
|
||||
fetchFn: typeof fetch,
|
||||
accessToken: string | null,
|
||||
userId: string
|
||||
) {
|
||||
try {
|
||||
const api = createApiClient({ fetch: fetchFn, accessToken: accessToken ?? undefined });
|
||||
const { data } = await api.GET('/playlists/users/{userId}', {
|
||||
params: {
|
||||
path: { userId },
|
||||
query: { pageNumber: 1, pageSize: SIDEBAR_PLAYLISTS_LIMIT }
|
||||
}
|
||||
});
|
||||
return data?.items ?? [];
|
||||
} catch {
|
||||
// The sidebar shell must render even when the API is unreachable.
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchLikedTracks(fetchFn: typeof fetch, accessToken: string | null) {
|
||||
try {
|
||||
const api = createApiClient({ fetch: fetchFn, accessToken: accessToken ?? undefined });
|
||||
const { data } = await api.GET('/likes', {
|
||||
params: { query: { pageNumber: 1, pageSize: LIKED_TRACKS_PAGE_SIZE } }
|
||||
});
|
||||
return data?.items ?? [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export const load: LayoutServerLoad = async ({ locals, url, fetch }) => {
|
||||
const allowAnonymousListening = await getAllowAnonymousListening(fetch);
|
||||
@@ -10,5 +46,31 @@ export const load: LayoutServerLoad = async ({ locals, url, fetch }) => {
|
||||
if (!locals.user && !allowAnonymousListening && !PUBLIC_PATHS.has(url.pathname)) {
|
||||
redirect(302, `/login?returnTo=${encodeURIComponent(url.pathname + url.search)}`);
|
||||
}
|
||||
return { user: locals.user, allowAnonymousListening };
|
||||
|
||||
const accountUrl = authConfig.issuer
|
||||
? `${authConfig.issuer.replace(/\/+$/, '')}/ui/console`
|
||||
: null;
|
||||
|
||||
if (!locals.user) {
|
||||
return {
|
||||
user: locals.user,
|
||||
allowAnonymousListening,
|
||||
sidebarPlaylists: [],
|
||||
likedTracks: [],
|
||||
accountUrl
|
||||
};
|
||||
}
|
||||
|
||||
const [sidebarPlaylists, likedTracks] = await Promise.all([
|
||||
fetchSidebarPlaylists(fetch, locals.accessToken, locals.user.sub),
|
||||
fetchLikedTracks(fetch, locals.accessToken)
|
||||
]);
|
||||
|
||||
return {
|
||||
user: locals.user,
|
||||
allowAnonymousListening,
|
||||
sidebarPlaylists,
|
||||
likedTracks,
|
||||
accountUrl
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user