Refine playlist popup controls

codex/redisenio-dominio-musical
dev 4 weeks ago
parent ac231c7600
commit ac0119a16d

@ -14,11 +14,19 @@
let { cancionSlug, listas, tamano = 28 }: Props = $props();
const volverA = $derived(page.url.pathname + page.url.search);
const guardada = $derived(listas.some((lista) => lista.canciones.includes(cancionSlug)));
let abierto = $state(false);
let activador = $state<HTMLElement>();
function cerrar() {
abierto = false;
queueMicrotask(() => activador?.focus());
}
</script>
{#if page.data.usuario}
<details class="selector">
<details class="selector" bind:open={abierto}>
<summary
bind:this={activador}
class:guardada
title="Añadir a una lista de reproducción"
aria-label="Añadir a una lista de reproducción"
@ -28,6 +36,9 @@
<div class="panel">
<p class="titulo">Listas de reproducción</p>
<button class="cerrar" type="button" aria-label="Cerrar listas" onclick={cerrar}>
<Icono nombre="cerrar" tamano={18} />
</button>
{#if listas.length > 0}
<ul>
{#each listas as lista (lista.id)}
@ -50,7 +61,7 @@
<form class="nueva" method="POST" action="?/crearLista" use:enhance>
<label for="nombre-lista-{cancionSlug}">Nueva lista</label>
<div>
<div class="crear-lista">
<input
id="nombre-lista-{cancionSlug}"
name="nombre"
@ -123,11 +134,34 @@
}
.titulo {
margin: 0 0 var(--sp-2);
margin: 0 var(--sp-6) var(--sp-2) 0;
font-size: var(--fs-sm);
font-weight: 700;
}
.cerrar {
position: absolute;
top: var(--sp-2);
right: var(--sp-2);
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
color: var(--c-text-muted);
cursor: pointer;
}
.cerrar:hover,
.cerrar:focus-visible {
background: var(--c-bg);
color: var(--c-text);
}
ul {
list-style: none;
margin: 0;
@ -185,26 +219,39 @@
margin-bottom: var(--sp-1);
}
.nueva div {
.crear-lista {
display: flex;
gap: var(--sp-1);
align-items: stretch;
overflow: hidden;
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
background: var(--c-bg);
}
.crear-lista:focus-within {
border-color: var(--c-accent);
box-shadow: 0 0 0 1px var(--c-accent);
}
.nueva input {
min-width: 0;
width: 100%;
min-height: 2.75rem;
padding: var(--sp-2);
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
border: 0;
border-radius: 0;
outline: 0;
background: var(--c-bg);
color: var(--c-text);
font: inherit;
}
.nueva button {
min-height: 2.75rem;
padding-inline: var(--sp-3);
border: 1px solid var(--c-accent);
border-radius: var(--radius-boton);
border: 0;
border-left: 1px solid var(--c-accent);
border-radius: 0;
background: var(--c-accent-superficie);
color: var(--c-accent-text);
font: inherit;

@ -0,0 +1,37 @@
import { page } from 'vitest/browser';
import { describe, expect, it, vi } from 'vitest';
import { render } from 'vitest-browser-svelte';
import BotonListaReproduccion from './BotonListaReproduccion.svelte';
vi.mock('$app/state', () => ({
page: {
url: new URL('http://localhost/canciones/prometiste'),
data: { usuario: { id: 'usuario-prueba' } },
form: null
}
}));
describe('BotonListaReproduccion', () => {
it('integra el botón de crear y permite cerrar el selector', async () => {
render(BotonListaReproduccion, {
cancionSlug: 'prometiste',
listas: [{ id: 'favoritas', nombre: 'Favoritas', canciones: [] }]
});
const activador = page.getByLabelText('Añadir a una lista de reproducción');
await activador.click();
const nombre = page.getByPlaceholder('Nombre');
const crear = page.getByRole('button', { name: 'Crear' });
await expect.element(nombre).toBeVisible();
await expect.element(crear).toBeVisible();
const altoNombre = nombre.element().getBoundingClientRect().height;
const altoCrear = crear.element().getBoundingClientRect().height;
expect(altoCrear).toBe(altoNombre);
await page.getByRole('button', { name: 'Cerrar listas' }).click();
await expect.element(nombre).not.toBeVisible();
await expect.element(activador).toHaveFocus();
});
});
Loading…
Cancel
Save

Powered by TurnKey Linux.