diff --git a/e2e/musica.e2e.ts b/e2e/musica.e2e.ts index 34ca3d6..e0eeb96 100644 --- a/e2e/musica.e2e.ts +++ b/e2e/musica.e2e.ts @@ -10,6 +10,74 @@ test.describe('Página de música', () => { await expect(lateral.getByRole('link', { name: /Clásica/ })).toBeVisible(); }); + test('buscar y elegir vista son una sola pieza', async ({ page }) => { + /* + * Eran dos cajas con un hueco entre ellas y parecían dos controles sin + * relación. El borde es de la barra: dentro, el campo y los botones no + * tienen canto propio y llegan al mismo alto. + */ + await page.setViewportSize({ width: 1100, height: 800 }); + await page.goto('/musica'); + + const medidas = await page.evaluate(() => { + const campo = document.querySelector('input[type="search"]')!; + const activo = document.querySelector('.vista.oro')!; + const barra = document.querySelector('.barra')!.getBoundingClientRect(); + return { + bordeDelCampo: getComputedStyle(campo).borderTopWidth, + altoCampo: Math.round(campo.getBoundingClientRect().height), + altoBoton: Math.round(activo.getBoundingClientRect().height), + altoBarra: Math.round(barra.height), + dentro: activo.getBoundingClientRect().right <= barra.right + 1 + }; + }); + + expect(medidas.bordeDelCampo).toBe('0px'); + expect(medidas.altoCampo).toBe(medidas.altoBoton); + // Sin hueco: la barra mide lo que miden sus piezas, más su propio canto. + expect(medidas.altoBarra).toBeLessThanOrEqual(medidas.altoCampo + 2); + expect(medidas.dentro).toBe(true); + }); + + test('la vista activa lleva el oro de los botones, no un color plano', async ({ page }) => { + await page.goto('/musica'); + + const oro = page.locator('.vista.oro'); + await expect(oro).toHaveText('Tarjetas'); + + // El degradado es lo que se pedía: al lado hay un botón dorado de verdad + // y se notaba que el conmutador no era el mismo oro. + const pintura = await oro.evaluate((e) => { + const s = getComputedStyle(e); + return { imagen: s.backgroundImage, filo: s.boxShadow, color: s.color }; + }); + expect(pintura.imagen).toContain('linear-gradient'); + expect(pintura.filo).toContain('inset'); + + // Y la letra es la del botón dorado, no el gris del inactivo: el `.vista` + // de la página le ganaba por especificidad al `.oro` general. + const inactivo = await page + .getByRole('button', { name: 'Tabla' }) + .evaluate((e) => getComputedStyle(e).color); + expect(pintura.color).not.toBe(inactivo); + + // Y cambia con la vista. + await page.getByRole('button', { name: 'Tabla' }).click(); + await expect(page.locator('.vista.oro')).toHaveText('Tabla'); + }); + + test('en un móvil la barra se apila sin estirar el campo', async ({ page }) => { + // En columna, `flex-basis` mide el alto: las doce rem que dan ancho al + // campo lo convertían en un cajón de doscientos píxeles. + await page.setViewportSize({ width: 360, height: 800 }); + await page.goto('/musica'); + + const alto = await page + .locator('input[type="search"]') + .evaluate((e) => Math.round(e.getBoundingClientRect().height)); + expect(alto).toBeLessThan(60); + }); + test('la tabla ordena por la columna que se pulsa', async ({ page }) => { await page.goto('/musica'); await page.getByRole('button', { name: 'Tabla' }).click(); diff --git a/src/app.css b/src/app.css index 62a1286..a102913 100644 --- a/src/app.css +++ b/src/app.css @@ -379,14 +379,22 @@ button { color: inherit; } -.btn--primary { +/* + * El aspecto dorado, aparte del botón que lo estrenó. + * + * Lo lleva también el conmutador de vista de la página de música, que no es un + * `.btn` —va dentro de una barra y no puede tener canto ni esquinas propias— + * pero sí tiene que ser el mismo oro. Copiarlo era garantizar que un día uno de + * los dos se quedara plano. + */ +.btn--primary, +.oro { /* El color plano queda de reserva: si el degradado no se pintara, el botón sigue siendo dorado y legible, no transparente. */ background-color: var(--c-accent-superficie); background-image: var(--oro); background-size: 100% 240%; background-position: 0 22%; - border-color: var(--c-accent-sombra); color: var(--c-accent-text); /* El filo de luz de arriba. Sin él, el degradado se ve pintado, no biselado. */ box-shadow: inset 0 1px 0 color-mix(in oklab, white 45%, transparent); @@ -395,12 +403,18 @@ button { border-color 0.2s var(--suave); } +/* El canto sí es del botón: dentro de una barra no hay borde que teñir. */ +.btn--primary { + border-color: var(--c-accent-sombra); +} + /* * Al acercar el puntero, la luz recorre la pieza. El color de fondo se repite * aquí porque `.btn:hover` lo cambia por el gris de los botones normales: sin * esto, un dorado que no llegara a pintar el degradado se vería oscuro. */ -.btn--primary:hover { +.btn--primary:hover, +.oro:hover { background-color: var(--c-accent-superficie); background-position: 0 78%; border-color: var(--c-accent); @@ -414,7 +428,8 @@ button { } @media (prefers-reduced-motion: reduce) { - .btn--primary { + .btn--primary, + .oro { transition: none; } } diff --git a/src/routes/musica/+page.svelte b/src/routes/musica/+page.svelte index d363ea9..e9dc7ad 100644 --- a/src/routes/musica/+page.svelte +++ b/src/routes/musica/+page.svelte @@ -70,23 +70,39 @@
+