Crea src/lib/components/ui/ContextMenu.svelte, que sustituye
TrackContextMenu y AlbumContextMenu (109 y 119 líneas, 90% idénticas):
misma función de posicionamiento (contextMenuPosition, exportada del
módulo, usando MENU_WIDTH/SUBMENU_WIDTH movidas a config.ts), mismo
backdrop, mismo Escape, mismo submenú "Añadir a playlist" genérico vía
{items, playlistAction, playlists}. Usa MenuItem para las acciones
(antes reimplementaban sus clases a mano) y Artwork size="xs" para las
miniaturas de playlist.
menus.svelte.ts (createTrackMenu) se adapta a la nueva
contextMenuPosition; se migran Inicio, Explorar (menú de pista y de
álbum) y Mezcla.
AccountMenu: panelClass (clases Tailwind libres) pasa a prop
width: 'sm'|'md'; añade cierre con Escape (mejora de accesibilidad,
antes no cerraba); TopBar y MobileHeader dejan de envolverlo en un
div.relative duplicado (su propio root ya lo es). z-index del panel
pasa a z-(--z-menu), al mismo nivel que ContextMenu (antes z-20 en
TopBar / sin z explícito en MobileHeader).
Verificado con npm run check/build; sin QA visual autenticada (Docker
no disponible en esta sesión).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
953 B
Svelte
49 lines
953 B
Svelte
<script lang="ts">
|
|
import type { LucideIcon } from '@lucide/svelte';
|
|
|
|
interface Props {
|
|
icon: LucideIcon;
|
|
label: string;
|
|
href?: string;
|
|
target?: string;
|
|
type?: 'button' | 'submit';
|
|
reload?: boolean;
|
|
onclick?: (event: MouseEvent) => void;
|
|
class?: string;
|
|
}
|
|
|
|
let {
|
|
icon: Icon,
|
|
label,
|
|
href,
|
|
target,
|
|
type = 'button',
|
|
reload = false,
|
|
onclick,
|
|
class: klass = ''
|
|
}: Props = $props();
|
|
|
|
const classes = $derived(
|
|
`flex w-full items-center gap-3 rounded-control px-2 py-2.5 text-left text-sm font-medium text-fg-2 transition hover:bg-hover ${klass}`
|
|
);
|
|
</script>
|
|
|
|
{#if href}
|
|
<a
|
|
{href}
|
|
{target}
|
|
rel={target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
data-sveltekit-reload={reload ? '' : undefined}
|
|
{onclick}
|
|
class={classes}
|
|
>
|
|
<Icon class="size-icon-md shrink-0" />
|
|
{label}
|
|
</a>
|
|
{:else}
|
|
<button {type} {onclick} class={classes}>
|
|
<Icon class="size-icon-md shrink-0" />
|
|
{label}
|
|
</button>
|
|
{/if}
|