web-player: unify the context menu (ContextMenu) + AccountMenu
Add src/lib/components/ui/ContextMenu.svelte, replacing
TrackContextMenu and AlbumContextMenu (109 and 119 lines, 90%
identical): same positioning function (contextMenuPosition, exported
from the module, using MENU_WIDTH/SUBMENU_WIDTH moved to config.ts),
same backdrop, same Escape handling, same generic "Add to playlist"
submenu via {items, playlistAction, playlists}. Uses MenuItem for
actions (previously each reimplemented its own classes by hand) and
Artwork size="xs" for playlist thumbnails.
menus.svelte.ts (createTrackMenu) adapts to the new
contextMenuPosition; Home, Explore (track and album menus) and Mix
are migrated.
AccountMenu: panelClass (free-form Tailwind classes) becomes prop
width: 'sm'|'md'; adds Escape-to-close (accessibility improvement, it
didn't close before); TopBar and MobileHeader no longer wrap it in a
duplicate div.relative (its own root already is one). The panel's
z-index becomes z-(--z-menu), matching ContextMenu (previously z-20
in TopBar / no explicit z in MobileHeader).
Verified with npm run check/build; no authenticated visual QA (Docker
unavailable this session).
This commit is contained in:
@@ -17,11 +17,11 @@
|
||||
import { EXPLORE_PAGE_SIZE } from '$lib/config';
|
||||
import { searchHref } from '$lib/navigation.svelte';
|
||||
import { createTrackMenu } from '$lib/menus.svelte';
|
||||
import TrackContextMenu from '$lib/components/TrackContextMenu.svelte';
|
||||
import AlbumContextMenu, {
|
||||
albumContextMenuStateFor,
|
||||
type AlbumMenuState
|
||||
} from '$lib/components/AlbumContextMenu.svelte';
|
||||
import ContextMenu, { contextMenuPosition } from '$lib/components/ui/ContextMenu.svelte';
|
||||
import ListPlus from '@lucide/svelte/icons/list-plus';
|
||||
import ListEnd from '@lucide/svelte/icons/list-end';
|
||||
|
||||
type AlbumMenuState = { x: number; y: number; openLeft: boolean; albumId: string };
|
||||
import { appendUnique } from '$lib/collections';
|
||||
import {
|
||||
isTargetCurrent,
|
||||
@@ -190,7 +190,7 @@
|
||||
}
|
||||
|
||||
function openAlbumMenu(event: MouseEvent, albumId: string) {
|
||||
albumMenu = albumContextMenuStateFor(event, albumId);
|
||||
albumMenu = { ...contextMenuPosition(event), albumId };
|
||||
}
|
||||
|
||||
async function albumPlayNext() {
|
||||
@@ -539,20 +539,38 @@
|
||||
</Page>
|
||||
|
||||
{#if trackMenu.state}
|
||||
<TrackContextMenu
|
||||
menu={trackMenu.state}
|
||||
playlists={data.playlists}
|
||||
<ContextMenu
|
||||
x={trackMenu.state.x}
|
||||
y={trackMenu.state.y}
|
||||
openLeft={trackMenu.state.openLeft}
|
||||
onClose={() => trackMenu.close()}
|
||||
onAddToQueue={() => trackMenu.playNext()}
|
||||
items={[
|
||||
{ icon: ListPlus, label: 'Reproducir a continuación', onclick: () => trackMenu.playNext() }
|
||||
]}
|
||||
playlistAction={{
|
||||
action: '?/addTrack',
|
||||
fields: { trackId: String(trackMenu.state.track.id) },
|
||||
label: 'Añadir a una playlist'
|
||||
}}
|
||||
playlists={data.playlists}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if albumMenu}
|
||||
<AlbumContextMenu
|
||||
menu={albumMenu}
|
||||
playlists={data.playlists}
|
||||
<ContextMenu
|
||||
x={albumMenu.x}
|
||||
y={albumMenu.y}
|
||||
openLeft={albumMenu.openLeft}
|
||||
onClose={() => (albumMenu = null)}
|
||||
onPlayNext={albumPlayNext}
|
||||
onAddToQueue={albumAddToQueue}
|
||||
items={[
|
||||
{ icon: ListPlus, label: 'Reproducir a continuación', onclick: albumPlayNext },
|
||||
{ icon: ListEnd, label: 'Añadir a la cola', onclick: albumAddToQueue }
|
||||
]}
|
||||
playlistAction={{
|
||||
action: '?/addAlbumToPlaylist',
|
||||
fields: { albumId: albumMenu.albumId },
|
||||
label: 'Añadir álbum a una playlist'
|
||||
}}
|
||||
playlists={data.playlists}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
import TrackMeta from '$lib/components/ui/TrackMeta.svelte';
|
||||
import TrackIndexCell from '$lib/components/ui/TrackIndexCell.svelte';
|
||||
import TrackTitleCell from '$lib/components/ui/TrackTitleCell.svelte';
|
||||
import TrackContextMenu from '$lib/components/TrackContextMenu.svelte';
|
||||
import ContextMenu from '$lib/components/ui/ContextMenu.svelte';
|
||||
import ListPlus from '@lucide/svelte/icons/list-plus';
|
||||
import { createTrackMenu } from '$lib/menus.svelte';
|
||||
import { mixItemKey, mixItemTarget } from '$lib/mixes';
|
||||
import {
|
||||
@@ -114,10 +115,19 @@
|
||||
</Page>
|
||||
|
||||
{#if trackMenu.state}
|
||||
<TrackContextMenu
|
||||
menu={trackMenu.state}
|
||||
playlists={data.playlists}
|
||||
<ContextMenu
|
||||
x={trackMenu.state.x}
|
||||
y={trackMenu.state.y}
|
||||
openLeft={trackMenu.state.openLeft}
|
||||
onClose={() => trackMenu.close()}
|
||||
onAddToQueue={() => trackMenu.playNext()}
|
||||
items={[
|
||||
{ icon: ListPlus, label: 'Reproducir a continuación', onclick: () => trackMenu.playNext() }
|
||||
]}
|
||||
playlistAction={{
|
||||
action: '?/addTrack',
|
||||
fields: { trackId: String(trackMenu.state.track.id) },
|
||||
label: 'Añadir a una playlist'
|
||||
}}
|
||||
playlists={data.playlists}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
import SectionHeading from '$lib/components/ui/SectionHeading.svelte';
|
||||
import EmptyState from '$lib/components/ui/EmptyState.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import TrackContextMenu from '$lib/components/TrackContextMenu.svelte';
|
||||
import ContextMenu from '$lib/components/ui/ContextMenu.svelte';
|
||||
import ListPlus from '@lucide/svelte/icons/list-plus';
|
||||
import { createTrackMenu } from '$lib/menus.svelte';
|
||||
import { HOME_CONTINUE_LIMIT, HOME_POPULAR_MAX } from '$lib/config';
|
||||
|
||||
@@ -423,10 +424,19 @@
|
||||
</div>
|
||||
|
||||
{#if trackMenu.state}
|
||||
<TrackContextMenu
|
||||
menu={trackMenu.state}
|
||||
{playlists}
|
||||
<ContextMenu
|
||||
x={trackMenu.state.x}
|
||||
y={trackMenu.state.y}
|
||||
openLeft={trackMenu.state.openLeft}
|
||||
onClose={() => trackMenu.close()}
|
||||
onAddToQueue={() => trackMenu.playNext()}
|
||||
items={[
|
||||
{ icon: ListPlus, label: 'Reproducir a continuación', onclick: () => trackMenu.playNext() }
|
||||
]}
|
||||
playlistAction={{
|
||||
action: '?/addTrack',
|
||||
fields: { trackId: String(trackMenu.state.track.id) },
|
||||
label: 'Añadir a una playlist'
|
||||
}}
|
||||
{playlists}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user