From 4d2a2072c2f367f8d18a96147d0cfe335e3a43e4 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 10 Sep 2026 02:52:11 +0200 Subject: [PATCH] =?UTF-8?q?Las=20p=C3=A1ginas=20de=20error,=20a=20pantalla?= =?UTF-8?q?=20completa=20y=20desnudas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Las láminas están dibujadas como carteles y venían armonizadas: el dibujo ocupa el 62,6 % de la izquierda y el resto es una banda lisa, que es el sitio del texto. Las recorté creyendo que sobraba y no: ahora va la lámina entera de fondo, pegada a la izquierda con el alto exacto de la pantalla, y lo que sobre a la derecha se pinta del color de la propia banda, así que en un monitor ancho la banda se alarga y no se ve dónde acaba la imagen. La columna del texto empieza a 0,88 × el alto, que es donde empieza la banda sea cual sea el ancho. Sin cabecera, sin pie y sin barra de reproducción. Un cartel a pantalla completa con el menú del sitio encima deja de ser un cartel, y de un error se sale por la puerta que pone la propia página. En vertical no vale ese reparto: al alto de un móvil el cartel se quedaría en una franja del centro con el número cortado por los lados. Ahí se apila, y con la otra versión del archivo —solo el dibujo, sin la banda—, con el panel del color del borde del dibujo, que es exactamente el color con el que la imagen termina. Un 403 no es ninguno de los dos casos: la página existe y el sitio funciona, es que no te toca. Esos salen sin ilustración. Y se descartan los mensajes que pone SvelteKit cuando no hay uno nuestro: «Internal Error» en un sitio en español es peor que no poner nada. Con `src/error.html`, desnudo a propósito, para cuando la aplicación no puede ni pintar su propia página de error. Co-Authored-By: Claude Opus 5 (1M context) --- e2e/navegacion.e2e.ts | 30 +- src/lib/components/Etiquetas.svelte | 33 +- src/lib/components/ListaCanciones.svelte | 204 +++++++++++- .../components/ListaCanciones.svelte.spec.ts | 25 +- .../components/TarjetaCancion.svelte.spec.ts | 1 + .../components/player/BarraProgreso.svelte | 12 + .../components/player/BarraReproductor.svelte | 24 +- .../components/player/ControlVolumen.svelte | 2 + src/lib/content/schema.ts | 3 + src/lib/player/player.svelte.ts | 37 ++- src/lib/server/catalogo.ts | 23 +- src/lib/types.ts | 6 + src/routes/+error.svelte | 291 +++++++++++------- src/routes/+layout.svelte | 14 +- src/routes/albumes/[slug]/+page.svelte | 1 - src/routes/canciones/[slug]/+page.svelte | 1 - static/errores/404-vertical.webp | Bin 0 -> 74458 bytes static/errores/404.webp | Bin 96796 -> 104870 bytes static/errores/500-vertical.webp | Bin 0 -> 55412 bytes static/errores/500.webp | Bin 71930 -> 75126 bytes 20 files changed, 557 insertions(+), 150 deletions(-) create mode 100644 static/errores/404-vertical.webp create mode 100644 static/errores/500-vertical.webp diff --git a/e2e/navegacion.e2e.ts b/e2e/navegacion.e2e.ts index eb392a5..898e8c9 100644 --- a/e2e/navegacion.e2e.ts +++ b/e2e/navegacion.e2e.ts @@ -106,17 +106,37 @@ test.describe('Navegación', () => { test.describe('La página de error', () => { test('lleva su lámina y sale del paso', async ({ page }) => { + const respuestas: Record = {}; + page.on('response', (r) => { + if (r.url().includes('/errores/')) respuestas[r.url().split('/').pop()!] = r.status(); + }); + await page.goto('/no-existe-esto'); - const lamina = page.locator('.lamina img'); - await expect(lamina).toHaveAttribute('src', '/errores/404.webp'); - // Que exista el archivo, no solo la etiqueta. - expect(await lamina.evaluate((i: HTMLImageElement) => i.naturalWidth)).toBeGreaterThan(0); + // La lámina es el fondo de la pantalla, no una imagen dentro del contenido. + const pantalla = page.locator('.pantalla'); + await expect(pantalla).toHaveCSS('background-image', /errores\/404\.webp/); + // Y el archivo existe de verdad, no solo la regla que lo nombra. + expect(respuestas['404.webp']).toBe(200); await page.getByRole('link', { name: 'Volver al inicio' }).click(); await expect(page).toHaveURL('/'); }); + /* + * Va desnuda: un cartel a pantalla completa con la barra del sitio encima + * deja de ser un cartel. De un error se sale por la puerta que pone la + * propia página. + */ + test('no lleva cabecera, ni pie, ni reproductor', async ({ page }) => { + await page.goto('/no-existe-esto'); + + await expect(page.locator('header')).toHaveCount(0); + await expect(page.locator('footer')).toHaveCount(0); + await expect(page.getByRole('region', { name: 'Reproductor' })).toHaveCount(0); + await expect(page.getByRole('link', { name: 'Volver al inicio' })).toBeVisible(); + }); + /* * Sin esto, todo el que aterrice en un 404 se traería 686 KB de mp3 que a lo * mejor no va a escuchar. Es la razón de ser del `preload="none"`. @@ -128,7 +148,7 @@ test.describe('La página de error', () => { }); await page.goto('/no-existe-esto'); - await expect(page.locator('.lamina img')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Poner música' })).toBeVisible(); expect(pedidos.some((u) => u.endsWith('.mp3'))).toBe(false); await page.getByRole('button', { name: 'Poner música' }).click(); diff --git a/src/lib/components/Etiquetas.svelte b/src/lib/components/Etiquetas.svelte index c66cbf3..041f127 100644 --- a/src/lib/components/Etiquetas.svelte +++ b/src/lib/components/Etiquetas.svelte @@ -28,13 +28,18 @@ * el píxel exacto. */ enlaces?: boolean; + /** + * Más pequeñas, para cuando van dentro de una fila de una lista y no en + * una ficha: ahí son un dato de apoyo y no deben pesar más que el título. + */ + menudas?: boolean; } - let { etiquetas, titulo = 'Etiquetas', enlaces = true }: Props = $props(); + let { etiquetas, titulo = 'Etiquetas', enlaces = true, menudas = false }: Props = $props(); {#if etiquetas.length > 0} -