web-player: split player, navigation and accent state into focused modules
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { isSectionActive, appNavLinks } from '$lib/state/navigation.svelte';
|
||||
import { appNavLinks, isNavActive } from './navLinks';
|
||||
import { playlistCover } from '$lib/utils/hrefs';
|
||||
import { liked } from '$lib/player/liked.svelte';
|
||||
import { createPlaylistModal } from '$lib/state/playlists.svelte';
|
||||
import { createPlaylistModal } from '$lib/state/panels.svelte';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
import ListRow from '../ui/media/ListRow.svelte';
|
||||
import IconButton from '../ui/primitives/IconButton.svelte';
|
||||
@@ -14,7 +15,7 @@
|
||||
interface SidebarPlaylist {
|
||||
id: string;
|
||||
name: string;
|
||||
coverTrackIds: (string | number)[];
|
||||
coverTrackIds: string[];
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -29,10 +30,6 @@
|
||||
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);
|
||||
}
|
||||
</script>
|
||||
|
||||
<aside
|
||||
@@ -45,7 +42,7 @@
|
||||
|
||||
<nav class="flex flex-col gap-1">
|
||||
{#each navLinks as link (link.href)}
|
||||
{@const active = isActive(link.href)}
|
||||
{@const active = isNavActive(link.href)}
|
||||
<a
|
||||
href={link.href}
|
||||
aria-current={active ? 'page' : undefined}
|
||||
@@ -86,9 +83,7 @@
|
||||
{active}
|
||||
size="xs"
|
||||
title={playlist.name}
|
||||
coverSrc="/api/playlists/{playlist.id}/cover?size=small&v={encodeURIComponent(
|
||||
playlist.updatedAt
|
||||
)}"
|
||||
coverSrc={playlistCover(playlist, 'small')}
|
||||
trackIds={playlist.coverTrackIds}
|
||||
class="px-3 py-2"
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { isSectionActive, appNavLinks } from '$lib/state/navigation.svelte';
|
||||
import { appNavLinks, isNavActive } from './navLinks';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
|
||||
interface Props {
|
||||
@@ -11,10 +10,6 @@
|
||||
let { user, class: klass = '' }: Props = $props();
|
||||
|
||||
const links = $derived(appNavLinks(user).filter((link) => link.primary));
|
||||
|
||||
function isActive(href: string) {
|
||||
return isSectionActive(href, page.url.pathname, page.data.section);
|
||||
}
|
||||
</script>
|
||||
|
||||
<nav
|
||||
@@ -22,7 +17,7 @@
|
||||
style="padding-bottom:calc(0.4375rem + var(--mf-safe-b))"
|
||||
>
|
||||
{#each links as link (link.href)}
|
||||
{@const active = isActive(link.href)}
|
||||
{@const active = isNavActive(link.href)}
|
||||
<a
|
||||
href={link.href}
|
||||
aria-current={active ? 'page' : undefined}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { page } from '$app/state';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
import { SEARCH_DEBOUNCE_MS, SEARCH_MIN_LENGTH } from '$lib/config';
|
||||
import { searchHref } from '$lib/state/navigation.svelte';
|
||||
import { searchHref } from '$lib/utils/hrefs';
|
||||
import Search from '@lucide/svelte/icons/search';
|
||||
import X from '@lucide/svelte/icons/x';
|
||||
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { page } from '$app/state';
|
||||
import type { LucideIcon } from '@lucide/svelte';
|
||||
import Home from '@lucide/svelte/icons/house';
|
||||
import Compass from '@lucide/svelte/icons/compass';
|
||||
import ListMusic from '@lucide/svelte/icons/list-music';
|
||||
import Heart from '@lucide/svelte/icons/heart';
|
||||
import Disc from '@lucide/svelte/icons/disc-2';
|
||||
import Folder from '@lucide/svelte/icons/folder';
|
||||
import Upload from '@lucide/svelte/icons/upload';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
|
||||
export interface AppNavLink {
|
||||
href: string;
|
||||
label: string;
|
||||
icon: LucideIcon;
|
||||
count?: number;
|
||||
primary: boolean;
|
||||
}
|
||||
|
||||
export interface AppNavCounts {
|
||||
playlists?: number;
|
||||
liked?: number;
|
||||
}
|
||||
|
||||
export function isNavActive(href: string): boolean {
|
||||
const section: string | null | undefined = page.data.section;
|
||||
if (section !== undefined) return section === href;
|
||||
return href === '/' ? page.url.pathname === '/' : page.url.pathname.startsWith(href);
|
||||
}
|
||||
|
||||
export function appNavLinks(user: SessionUser | null, counts: AppNavCounts = {}): AppNavLink[] {
|
||||
if (!user) return [{ href: '/explore', label: 'Descubrir', icon: Compass, primary: true }];
|
||||
return [
|
||||
{ href: '/', label: 'Inicio', icon: Home, primary: true },
|
||||
{ href: '/explore', label: 'Descubrir', icon: Compass, primary: true },
|
||||
{
|
||||
href: '/playlists',
|
||||
label: 'Playlists',
|
||||
icon: ListMusic,
|
||||
count: counts.playlists,
|
||||
primary: true
|
||||
},
|
||||
{ href: '/liked', label: 'Me gusta', icon: Heart, count: counts.liked, primary: true },
|
||||
{ href: '/albums', label: 'Mis álbumes', icon: Disc, primary: false },
|
||||
{ href: '/library', label: 'Canciones subidas', icon: Folder, primary: false },
|
||||
{ href: '/upload', label: 'Subir música', icon: Upload, primary: false }
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user