From 3a75eb768dc1a019d149334a915b234df615175b Mon Sep 17 00:00:00 2001 From: dev Date: Sat, 12 Sep 2026 23:18:30 +0200 Subject: [PATCH] Simplify header logo colors --- e2e/navegacion.e2e.ts | 18 +++++--- e2e/responsive.e2e.ts | 57 +++++------------------- src/lib/assets/senza-paura-logo.svg | 4 +- src/lib/components/Cabecera.svelte | 43 +++--------------- src/lib/components/LogoSenzaPaura.svelte | 47 +++++++++++++------ 5 files changed, 67 insertions(+), 102 deletions(-) diff --git a/e2e/navegacion.e2e.ts b/e2e/navegacion.e2e.ts index c7c2ce4..302ce6e 100644 --- a/e2e/navegacion.e2e.ts +++ b/e2e/navegacion.e2e.ts @@ -41,17 +41,25 @@ test.describe('Navegación', () => { await expect(ultimo).toHaveAttribute('aria-label', /tema/); }); - test('el logo conserva el mismo metal al cambiar al tema claro', async ({ page }) => { + test('el logo de cabecera usa blanco plano en oscuro y azul plano en claro', async ({ page }) => { await page.goto('/'); - const logo = page.locator('header .nombre-marca'); - const oroOscuro = await logo.evaluate((elemento) => getComputedStyle(elemento).backgroundImage); + const marca = page.locator('header .marca'); + const nombre = page.locator('header .nombre-marca'); + const simbolo = page.locator('header [data-logo-senza-paura]'); + await expect(marca).toHaveCSS('color', 'rgb(255, 255, 255)'); + await expect(nombre).toHaveCSS('background-image', 'none'); + await expect(simbolo).toHaveCSS('fill', 'rgb(255, 255, 255)'); await page.getByRole('button', { name: 'Cambiar al tema claro' }).click(); await expect(page.locator('html')).toHaveAttribute('data-tema', 'claro'); - const oroClaro = await logo.evaluate((elemento) => getComputedStyle(elemento).backgroundImage); - expect(oroClaro).toBe(oroOscuro); + const azul = await page + .locator('body') + .evaluate((elemento) => getComputedStyle(elemento).color); + await expect(marca).toHaveCSS('color', azul); + await expect(nombre).toHaveCSS('background-image', 'none'); + await expect(simbolo).toHaveCSS('fill', azul); }); test('el símbolo de marca aparece en la cabecera y en el pie', async ({ page }) => { diff --git a/e2e/responsive.e2e.ts b/e2e/responsive.e2e.ts index e647176..5ac1eac 100644 --- a/e2e/responsive.e2e.ts +++ b/e2e/responsive.e2e.ts @@ -188,7 +188,7 @@ test.describe('Respuesta al puntero', () => { }); }); -test.describe('Contraste del dorado', () => { +test.describe('Contraste y color de marca', () => { // El dorado hace dos trabajos y no puede ser el mismo valor en los dos: de // relleno tiene que ser claro para que encima se lea el marino, y escrito // tiene que ser hondo para leerse sobre el fondo. Esto lo fija. @@ -278,58 +278,25 @@ test.describe('Contraste del dorado', () => { await expect(page.locator('html')).toHaveAttribute('data-tema', 'claro'); }); - /* - * El símbolo ya es un SVG vectorial autocontenido: el disco negro y el oro - * viajan dentro del propio recurso. Por eso el tema no debe teñirlo. Además - * de comprobar que siempre carga el mismo SVG, se mide cada parada del oro - * contra el disco sobre el que realmente se dibuja. - */ + /* El identificador de cabecera es monocromo y no depende de degradados. */ for (const modo of ['oscuro', 'claro'] as const) { - test(`el logo conserva su oro y contraste en tema ${modo}`, async ({ page }) => { + test(`el logo plano conserva el contraste en tema ${modo}`, async ({ page }) => { await page.goto('/'); await page.evaluate((m) => { document.documentElement.dataset.tema = m; }, modo); - const peor = await page.evaluate(async () => { - const logo = document.querySelector('header [data-logo-senza-paura]')!; - const respuesta = await fetch(logo.src); - const documento = new DOMParser().parseFromString(await respuesta.text(), 'image/svg+xml'); - const colores = [...documento.querySelectorAll('linearGradient stop')].map((stop) => - stop.getAttribute('stop-color') - ); - const fondo = documento.querySelector('circle')?.getAttribute('fill'); - - const pincel = document.createElement('canvas').getContext('2d')!; - const aRgb = (c: string | null) => { - if (!c) return [0, 0, 0]; - pincel.fillStyle = c; - pincel.fillRect(0, 0, 1, 1); - const d = pincel.getImageData(0, 0, 1, 1).data; - return [d[0], d[1], d[2]]; - }; - const lum = (rgb: number[]) => { - const f = (v: number) => { - v /= 255; - return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; - }; - return 0.2126 * f(rgb[0]) + 0.7152 * f(rgb[1]) + 0.0722 * f(rgb[2]); - }; - const contraste = (c: string | null) => { - const [a, b] = [lum(aRgb(c)), lum(aRgb(fondo))].sort((m, n) => n - m); - return (a + 0.05) / (b + 0.05); - }; - - return { - recurso: new URL(logo.src).pathname, - cuantas: colores.length, - minimo: Math.min(...colores.map(contraste)) - }; + const resultado = await page.evaluate(() => { + const logo = document.querySelector('header [data-logo-senza-paura]')!; + const fondo = document.querySelector('header')!; + const color = getComputedStyle(logo).color; + const base = getComputedStyle(fondo).backgroundColor; + return { color, base, etiqueta: logo.tagName, relleno: getComputedStyle(logo).fill }; }); - expect(peor.recurso).toMatch(/senza-paura-logo.*\.svg$/); - expect(peor.cuantas).toBeGreaterThanOrEqual(3); - expect(peor.minimo).toBeGreaterThan(MINIMO); + expect(resultado.etiqueta).toBe('svg'); + expect(resultado.relleno).toBe(resultado.color); + expect(resultado.color).not.toBe(resultado.base); }); } diff --git a/src/lib/assets/senza-paura-logo.svg b/src/lib/assets/senza-paura-logo.svg index 6b62ec1..30354aa 100644 --- a/src/lib/assets/senza-paura-logo.svg +++ b/src/lib/assets/senza-paura-logo.svg @@ -1,4 +1,4 @@ - + Senza Paura Monograma dorado SP dentro de un disco negro @@ -11,5 +11,5 @@ - + diff --git a/src/lib/components/Cabecera.svelte b/src/lib/components/Cabecera.svelte index ccaa52a..ad23e53 100644 --- a/src/lib/components/Cabecera.svelte +++ b/src/lib/components/Cabecera.svelte @@ -88,7 +88,7 @@
- + {site.nombre} @@ -258,10 +258,14 @@ font-weight: 600; line-height: 1.15; letter-spacing: 0.01em; - color: var(--c-marca-oro); + color: #fff; text-decoration: none; } + :global(:root[data-tema='claro']) .marca { + color: var(--c-text); + } + /* * La caja tipográfica sí queda centrada con `align-items`, pero Newsreader * concentra más tinta por encima de la línea base. Este pequeño ajuste @@ -273,41 +277,6 @@ transform: translateY(0.07em); } - /* - * El mismo oro de los botones, aquí recortado sobre las letras. - * - * Va dentro de un `@supports` y el color plano se queda fuera a propósito: - * `color: transparent` sin el recorte dejaría el nombre invisible, que es - * mucho peor que dejarlo dorado y liso. Es el mismo cuidado que tiene el - * botón, que guarda un color de reserva por si el degradado no llega a - * pintar. - * - * Las cinco paradas, el ángulo y el alto del fondo son los suyos, para que - * sea el mismo metal y no un dorado parecido. Y como en el botón, al pasar - * el puntero la banda de luz recorre las letras en vez de aclararlas. - */ - @supports (background-clip: text) or (-webkit-background-clip: text) { - .nombre-marca { - background-image: var(--oro-escrito); - background-size: 100% 240%; - background-position: 0 22%; - -webkit-background-clip: text; - background-clip: text; - color: transparent; - transition: background-position 0.6s var(--sal); - } - - .marca:hover .nombre-marca { - background-position: 0 78%; - } - } - - @media (prefers-reduced-motion: reduce) { - .nombre-marca { - transition: none; - } - } - .nav .principal { display: flex; gap: var(--sp-5); diff --git a/src/lib/components/LogoSenzaPaura.svelte b/src/lib/components/LogoSenzaPaura.svelte index a7278fa..3489b3f 100644 --- a/src/lib/components/LogoSenzaPaura.svelte +++ b/src/lib/components/LogoSenzaPaura.svelte @@ -5,9 +5,11 @@ interface Props { lado?: number; + /** Usa solo el trazo del símbolo y hereda un único color del contexto. */ + plano?: boolean; } - let { lado = 36 }: Props = $props(); + let { lado = 36, plano = false }: Props = $props(); const reproduciendo = $derived(reproductor.sonando); @@ -16,18 +18,33 @@ animación está asignada incluso en pausa para conservar el ángulo alcanzado; solo cambia `animation-play-state`, de modo que nunca salta al origen. --> - +{#if plano} + +{:else} + +{/if}