codex/estilos-web-publica
codex/redisenio-dominio-musical
master
${ noResults }
27 Commits (34668a80e368dc9ed4a87d2a195fc8cf5a39ff36)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
34668a80e3 |
El panel se va a su propio dominio y su propio proceso
Estaba mal hecho y el síntoma era el `if` sobre `/admin` que acabó metido en el layout de la web pública: la web sabiendo que existe el panel, al revés de como debe ser. Ahora son dos aplicaciones del mismo repositorio. Lo que las separa son tres líneas de `vite.config.ts`: con `APP=panel`, las rutas salen de `src/panel/rutas`, los hooks de `src/panel/hooks.server.ts` y el resultado va a `build-panel/`. El servidor público se compila sin las rutas del panel, así que en `senzapaura.es` no es que `/admin` esté protegido: no existe, y hay una prueba que lo comprueba pidiéndolo. Comparten `src/lib` —esquema, consultas, acceso—, que es lo que evita mantener las migraciones por duplicado. Para que eso funcione, dos cosas que resolvían rutas del sitio salen de en medio: la navegación, a `$lib/navegacion`, y los tipos ambientales, que ahora son dos porque el `PageData` del sitio lleva carrito y favoritos y el del panel no. El precio de otro dominio es que el panel necesita su propia página de entrar: la cookie se emite para el host y no para el dominio padre, que es justo lo que hace que la sesión del panel no viaje en las peticiones de la web. Usa el mismo código de `$lib/server/auth`, con una diferencia: solo manda código a una cuenta que ya administre, y contesta lo mismo exista o no. Si dijera «esa cuenta no administra», el formulario sería una forma cómoda de averiguar cuál sí. Y con dominio propio, el 404 de ayer pasa a ser un 403 con el motivo escrito: esconder el panel de quien ya está en `admin.senzapaura.es` no engaña a nadie, y a esa rama solo llega alguien que administraba y ha dejado de administrar. Dos servidores en las pruebas, uno por proyecto, con su `baseURL`: una prueba del panel no puede pedir por accidente una página del sitio. Aparte, la prueba de contacto otra vez. El arreglo de ayer no valía —comprobar que el texto está escrito no impide que lo borren un instante después—, así que el layout marca con `data-hidratado` el momento en que Svelte toma el control y la prueba espera a eso. Quince pasadas con cuatro trabajadores, sin un fallo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
3981f33867 |
La puerta del panel, y una portada que dice qué falta
Fase 6. Está lo que todo lo demás necesita: quién entra y por dónde. El rol vive en `usuario.rol`, con un CHECK que impide inventarse uno, y se da con `npm run db:admin`. En una variable de entorno con correos habría sido más rápido, pero entonces revocar a alguien pide un despliegue y a la pregunta «quién administra esto» solo sabe contestar quien pueda leer la configuración del servidor. La guarda está en el `+layout.server.ts` de la carpeta y no en cada ruta: una pantalla nueva queda protegida por el hecho de estar dentro. Sin sesión, a entrar con la vuelta puesta; con sesión y sin el rol, 404 y no 403, porque un 403 confirma que el panel existe y dónde vive. Los tres casos, comprobados contra la aplicación de verdad. La portada contesta «qué falta» y no «cuánto hay». Cada sección trae lo que tiene, lo que está a medias y los nombres de lo que está a medias: decir «1 género sin ficha» obliga a ir a buscar cuál, y esa búsqueda ya la ha hecho la consulta. Dos viajes a la base para las siete filas. Fuera Sveltia CMS y `static/admin/`. Editaba los Markdown de `src/content/`, que desde la fase 4 no lee nadie: guardaba cambios que no salían en pantalla, y además tapaba la ruta nueva. Y de paso, la prueba de contacto que fallaba en la tanda completa y pasaba a solas. No era aislamiento: `page.goto` vuelve al cargar, no al hidratar, y al hidratar Svelte reescribe el valor de cada `input` con el del componente. Lo tecleado antes de ese instante se perdía, y solo le pasaba al primer campo y solo con la máquina cargada. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
174cf828e7 |
El punto del mapa ya no lo tapa el pais de al lado
Cada punto se dibujaba dentro del grupo de su pais, y en un SVG no hay `z-index`: manda el orden en que esta escrito. El relleno del pais siguiente se pintaba encima y el punto salia mordido por un lado. Ahora hay dos pasadas, primero todas las tierras y luego todos los puntos, y el que enciende cada uno se anota en `bajoPuntero` y `conFoco`, porque desde la capa de arriba ningun selector alcanza al pais de debajo. De paso, tres cosas que se veian mal y no daban error: - El radio salia de dividir por el ancho de la caja, pero con `max-height` el dibujo se ajusta al alto y en una ventana baja America se pintaba a 0,57 en vez de a 0,70. El punto de Mexico media doce pixeles y el de España quince. Ahora la escala sale del lado que primero se queda corto. - De España ya no se dibujan las islas: Canarias caia fuera del recuadro y las Baleares eran cuatro pixeles sueltos al este. - Un solo verde para todo pais con generos. El segundo tono servia para separar la cuna de lo adoptado y lo unico que conseguia era que España, que solo adopto el bolero, saliera de otro color que el resto. Esa diferencia se cuenta en la lista de al lado. La Peninsula, cuarenta pixeles a la izquierda; en movil no, que ahi su columna mide noventa y se metia encima de America. `e2e/mapa.e2e.ts` fija las cuatro: orden de pintado, tamaño del punto, color unico y España sin islas. Ninguna daba error, el mapa salia igual, solo que mal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
22d7174965 |
Géneros entra en la navegación principal
Sin esto la sección solo se alcanzaba desde el taller, que es justo lo contrario de sacarla a su propio sitio. La prueba del menú en móvil pasa a comprobar los nombres en vez de la cuenta: así dice cuál falta en lugar de que el número no cuadra. Y las cuatro páginas nuevas entran en la medida de desbordamiento a 320, 375, 768 y 1440. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
d74700f9b0 |
Las fichas de género salen del taller y tienen su propia sección
Con lo que pediste: portada con mapa de Iberoamérica, buscador y un aside que empieza por Inicio, Los principios, Glosario y Letristas antes de la lista de géneros. El mapa es interactivo de verdad: cada país se pinta según lo que tenga —marcado si es cuna de algún género, tenue si solo lo adoptó, apagado si no hay nada—, y al pulsarlo la lista de abajo se parte en «nació aquí» y «también se canta ahí». Esa diferencia es lo que un mapa cuenta mejor que una lista. Los contornos son de `BlankMap-Americas.svg` de Wikimedia, en dominio público, recortados a los veinte países de Iberoamérica en América. De 640 KB a 36 KB comprimidos, y solo en esta ruta: coordenadas a un decimal y fuera los 134 islotes que a este tamaño miden menos de un píxel. Va por script y no pegado a mano, para poder rehacerlo. Cada país lleva además un punto de agarre calculado —el promedio de los vértices de su costa, no el centro de su rectángulo, que en Cuba cae en el mar—: sin él, Puerto Rico mide cuatro píxeles y una isla alargada no hay quien la acierte. «Letristas» es nueva: las mismas personas que salen repartidas en nueve fichas, aquí juntas, con su papel en cada género y sus obras. La página del capítulo pasa a `$lib/components/Capitulo.svelte` y la usan las dos secciones: son setecientas líneas, y copiarlas habría sido dos sitios donde arreglar cada cosa. Las direcciones viejas redirigen con 301 —`/taller/bolero` a `/generos/bolero`— resolviendo contra el catálogo de capítulos, no contra una lista escrita a mano que alguien tenga que ampliar. Un enlace compartido no puede empezar a dar 404 porque hayamos reordenado el menú. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
71c39db5db |
El glosario del taller, con su globo en el texto
Lo que se pidió: «cada vez que aparezca un término del glosario en el texto, estará marcado para visualizarse con un popup con la explicación». Veintinueve términos con acepciones numeradas —«clave» es el patrón rítmico y el instrumento de percusión, y con una sola definición una de las dos sería falsa—, más las formas con las que cada palabra aparece de verdad: plurales, femeninos, con tilde y sin ella. El marcado va sobre el HTML ya compuesto y no sobre el Markdown: antes habría que esquivar la sintaxis, y un término dentro de un enlace o de un bloque de código es justo donde un reemplazo de texto se equivoca en silencio. Se marca una vez por término y por apartado, no en cada aparición: nueve «compás» subrayados no hay quien los lea. La pieza tiene más casos raros que cualquier otra del sitio y ninguno se ve mirando la página —el fallo es que un globo no salga, y nadie echa en falta lo que no sabe que existía—, así que va separada de la base y con doce pruebas. Dos las escribí creyendo que ya pasaban: - Marcaba «sinalefas» del final del párrafo en vez de la «sinalefa» de la primera línea, porque probaba forma por forma en orden de longitud. - Con las formas sin ordenar marcaba «rima» y no «rima asonante». Salía bien solo porque la consulta las devolvía ordenadas; ahora el desempate está en la función, que no puede depender de cómo se la llame. El globo es un botón y no un `title`: un tooltip nativo no se abre con teclado y en un móvil no existe. Se cierra con Escape devolviendo el foco, y se coloca debajo del término o encima si no cabe, porque tapar lo que se acaba de pulsar es lo peor que podría hacer. El glosario entero tiene además su página, donde sí cabe la ampliación que en un globo taparía el texto. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
62a8d79866 |
La barra de música es una pieza, y su dorado es el de los botones
Eran dos cajas con un hueco entre ellas: el campo de búsqueda por un lado y el conmutador de vista por otro, cada uno con su canto. Buscar y elegir cómo se ve son el mismo gesto —acotar lo que hay en pantalla— y separados parecían dos controles sin relación. Ahora el borde es de la barra y dentro no hay más línea que la que separa lo que se escribe de lo que se pulsa; el foco lo acusa la pieza entera. Y el activo llevaba un dorado plano al lado de un botón dorado de verdad, así que se notaba que no era el mismo. El aspecto sale de `.btn--primary` a una clase `.oro` que comparten los dos: degradado, filo de luz arriba y el barrido al pasar el puntero. Copiarlo habría sido garantizar que un día uno de los dos se quedara atrás. Dos cosas que aparecieron al montarlo: - Svelte añade su clase de ámbito a todo lo que escribe en el componente, así que un `.vista` de la página le gana por especificidad al `.oro` general y el botón activo se quedaba con la letra gris encima del oro. Va con `:not(.oro)`. - En columna, `flex-basis` mide el alto: las doce rem que dan ancho al campo lo convertían, apilado en un móvil, en un cajón de casi doscientos píxeles. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
91bfd48c0d |
La prueba del aviso iba con el texto anterior
Comprobaba «pendientes de revisión» literal, y al reescribir el aviso pasó a decirse en singular. Ahora comprueba lo que importa: que el aviso está y que nombra los versos. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
6797c03809 |
Ejemplos de versos en la ficha, y dónde escuchar cada obra
La ficha decía que el bolero va en octosílabo y endecasílabo alternados sin enseñar nunca uno. Un taller que describe la métrica y no la muestra está pidiendo que se la imaginen. `verso` es la estrofa y no el verso suelto —la rima y la alternancia de medidas no se ven en menos de dos versos— y `verso_linea` lleva cada uno con su escansión: `silabas` es la métrica y no la del diccionario, así que la sinalefa mete dos palabras en una casilla —«za⁀a»—, que es justo lo que en un texto corrido no se ve. `medida` va aparte porque un verso agudo suma una sílaba y uno esdrújulo resta una: «yo respondo con el son» tiene siete casillas y es un octosílabo. Los diez ejemplos son originales, escritos para enseñar, y entran marcados con `fuente = 'ejemplo'`. Ninguno es cita: para eso está `obra_referencia.cita`, y dos CHECK lo sostienen —un verso «cita» sin obra, o uno «propio» sin canción, no entran—. La escansión se comprueba antes de cargarla, contra la ley del acento final, y el sembrador aborta si algo no cuadra. Un ejemplo mal contado enseña a contar mal y eso no lo detecta ningún tipo ni ningún lint: por eso la comprobación está en su propio módulo, con nueve pruebas. `obra_referencia_enlace` sustituye a la columna `enlace`, que era texto suelto y solo daba sitio para uno; una obra está en Spotify **y** en YouTube. Comparte el vocabulario `PLATAFORMAS` con los enlaces de las canciones. De momento son búsquedas y no grabaciones concretas: una URL inventada manda a un 404 con pinta de dato bueno, y los enlaces exactos llegarán en el JSON de la ficha. De paso, dos cosas que se vieron al montarlo: - El orden de la ficha cambia. Primero lo que se usa para escribir —ejemplos, rasgos, temática— y después lo que sitúa el género. Es un taller: quien abre la página viene a escribir una letra. - `repeat(auto-fit, minmax(24rem, 1fr))` desbordaba ochenta píxeles en un móvil de 320, porque la rejilla pone la columna aunque no quepa. Ahora es `min(24rem, 100%)`, en los tres sitios donde estaba. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
8e57950820 |
El taller lee de PostgreSQL, y la ficha enseña lo que en un .md no cabía
Es la primera área que deja `src/content/**`. Se eligió esta porque es donde estaban los datos que no cabían en el frontmatter de un archivo, y porque es la que menos rutas toca si algo sale mal. La ficha de género gana lo que pedía el artefacto y no estaba: - Países con su relación: la cuna se distingue del país que lo adoptó, y va primero aunque alfabéticamente no le toque. - Instrumentación con el peso de cada instrumento y su papel. Sin el peso, el tres cubano y una trompeta ocasional pesarían igual. - Letristas con país, años y papel, de la tabla `persona`, la misma que firma las canciones del catálogo. - Obras de referencia fechadas, acreditadas y con su cita, con el aviso de por qué se puede reproducir un fragmento. - Linaje en las dos direcciones, distinguiendo derivar de fusionar. No enlaza a un género sin capítulo: el bolero-son existe en la base porque el bolero y el son confluyen en él, pero nadie ha escrito su ficha, y enlazarlo mandaba a un 404. - El aviso de lo que no ha revisado nadie. Mira la ficha entera y no solo la fila del género: en los ocho que ya existían la prosa la escribió el titular y lo que vino de un modelo son los datos de alrededor, así que mirando solo el género el aviso callaba justo donde hacía falta. Todo va debajo de la prosa y a todo lo ancho, no en una barra lateral. Lo único al lado del texto es el índice del propio capítulo, que es lo que cubre el ancho que la prosa no puede cubrir sola. El sitemap deja de listar los capítulos desde los archivos: si no, un género nuevo en la base no aparecería. Y `$lib/content` pierde los lectores del taller —los archivos siguen ahí, son de donde salió el volcado— para que nadie edite un .md que ya no pinta nada en pantalla. Ocho pruebas nuevas, una por cada bloque que antes no existía. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
be28a29693 |
El capítulo del taller cubre el ancho, con su índice al lado
La queja era justa y va por la tercera vez, así que esta vez queda medida y con prueba: la franja de datos, el índice del capítulo y los bloques de abajo terminan los tres en el mismo borde. Lo que no se puede hacer es ensanchar el texto. Para llenar novecientos píxeles con prosa legible haría falta letra de veinticuatro puntos; a menos de eso salen ciento veinte caracteres por línea y el ojo pierde el renglón. Ya se midió al hacer las páginas legales: estirado daba 129. Así que lo que cubre ese ancho es lo que va al lado, y no es la lista de compás y tempo que se quitó —esa subió a la franja—: es el índice de apartados del propio capítulo, el mismo recurso que llevan los textos legales. Y las columnas miden lo suyo con el sobrante en el corredor, porque con anchos fijos quedaban ciento veinte píxeles muertos al final de la fila, que es exactamente el hueco que se ve como un fallo. Además, la semilla de géneros: países, veintiún instrumentos, veintiuna personas, obras de referencia y el linaje del bolero-son, que deriva de dos. Entra marcada como importada y sin revisar, porque la escribió un modelo y se publica con el nombre del titular. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
e0a979bf5d |
La ficha de género pierde la barra lateral y gana su franja de datos
Los datos del género —compás, metro, tempo, rima— pasan de una lista de definiciones apretada en una columna estrecha a la derecha a una franja a todo lo ancho encima del texto. El compás y la métrica de un género se leen juntos o no se leen, y en la lateral quedaban en letra pequeña con el texto escorado. La estructura, la temática y los rasgos bajan debajo de la prosa como bloques a lo ancho: la temática en rejilla —son etiquetas disfrazadas de frase— y los rasgos en lista, que son frases de verdad. Es el sitio donde entrarán los instrumentos, los letristas, las obras de referencia y el linaje cuando tengan datos. Y el volcado de medios: 55 archivos a la tabla `medio` con su huella, su peso y su duración MEDIDA, no escrita. De ahí salen dos cosas que no se veían: el mismo audio está copiado bajo doce nombres distintos, y las duraciones del catálogo dicen 252 segundos donde el archivo dura 6. La clave de un medio lleva su almacén delante, porque `singles/dorina.mp3` existe en audio y en muestras y sin eso serían la misma fila. Es además la ruta con la que se servirán desde m.senzapaura.es/archives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
3f1a651006 |
El marino es el modo por defecto, no solo si el sistema lo pide
El color forma parte de lo que cuenta el sitio, y seguir a `prefers-color-scheme` hacía que media parte de las visitas viera una versión que no es la de la marca —un portátil configurado en claro no tiene nada que decir sobre el aspecto de un catálogo de canciones—. Al revés que en una herramienta de trabajo, aquí nadie va a pasar ocho horas seguidas leyendo. El claro sigue entero y a un clic, y la elección se recuerda. Lo que se deja de hacer es decidirlo por nadie. La prueba de contraste emulaba el esquema del sistema, así que con este cambio habría pasado a comprobar dos veces lo mismo sin que nadie lo notara: ahora pone `data-tema` a mano. Y la medida de claridad convierte el `oklch()` pintándolo en un lienzo, porque desmontar la cadena a mano daba NaN. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
da47ba08e2 |
El dominio es senzapaura.es
Cambia las referencias al dominio de trabajo: la URL canónica, los correos de los textos legales, las direcciones de retorno de Google y Facebook, y lo que espera la suite. El `robots.txt` pasa de archivo estático a ruta generada. Llevaba el dominio escrito a mano y se quedó anunciando el anterior: un mapa del sitio mal anunciado no da ningún error, simplemente no lo encuentra nadie. Ahora sale de `site.url`, igual que el mapa y las etiquetas de cada página. De paso deja fuera del rastreo lo que depende de quién mira —cuenta, carrito, favoritos, entrar, descargas—, que no es contenido. Y el Nginx queda listo para el dominio, con los tres pasos que hay que dar fuera del servidor: los registros A a 89.46.247.16, la redirección de los puertos 80 y 443 a 192.168.18.171, y Certbot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
d3cc4e3488 |
Entrar con Google o con Facebook
Detrás de la cuenta hay compras y facturación, y un código por correo apoya toda esa puerta en el buzón: quien entre ahí, entra aquí. Delegar la identidad en un proveedor que ya tiene doble factor la sostiene mejor. Es el flujo de código de autorización con PKCE, escrito a mano porque son cien líneas y las partes que importan son tres, mejor a la vista que detrás de una dependencia: comparar el `state`, mandar el `code_verifier` y exigir que el correo venga verificado antes de enlazar nada. Lo que NO hace, a propósito: verificar la firma del `id_token`. La identidad no se saca de lo que trae el navegador, sino de una llamada nuestra al proveedor por TLS, así que no hay firma ajena que comprobar. Y no guarda ningún token: se usa una vez para preguntar quién es y se tira. El enlazado por correo verificado es lo delicado, y por eso está separado en `usuarioParaPerfil` con su explicación: sin exigir la verificación, cualquiera podría poner la dirección de otro en un perfil suyo y quedarse con su cuenta y sus compras. El código por correo se queda debajo, como alternativa. Sin credenciales puestas, los botones no se pintan y la ruta contesta 503: un botón que solo lleva a un error es peor que no tenerlo. Y los textos legales al día, que ahora sí hay terceros: qué se manda a Google y a Facebook, cuándo, qué se guarda y cómo revocarlo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
383d0ce913 |
Acceso en un diálogo de dos mitades y arregla el apilamiento del carrusel
El acceso deja de ser un salto de página: «Entrar» abre un diálogo con la imagen de marca a la izquierda y el formulario a la derecha, y al entrar se vuelve a donde se estaba en vez de aterrizar en /cuenta. `/entrar` sigue existiendo con el mismo formulario y la misma estampa, para quien llegue por un enlace directo o sin JavaScript. Tres cosas que salieron de probarlo, no de suponerlo: - `showModal()` enfocaba el campo trampa contra envíos automáticos: está fuera de pantalla y fuera del recorrido de tabulación, pero se puede enfocar. Ahora el campo se enfoca a mano. - Una regla de `display` en el diálogo le gana a la del navegador, que es hoja de usuario. El diálogo cerrado se pintaba igual: una pantalla de vacío al final de todas las páginas del sitio. - Los enlaces legales navegaban por debajo del modal. Van en pestaña aparte: se consultan y se vuelve con lo escrito intacto. Y aparte, el carrusel de la portada. Cada lámina lleva su fondo con `z-index: -1`, pero con `opacity: 1` la lámina no crea contexto de apilamiento, así que ese fondo se escapaba y se pintaba detrás del carrusel entero. Al pasar de lámina asomaba la foto de la de al lado y el fondo de la que entraba saltaba hacia atrás al terminar el fundido. Parecía que el shader se desincronizaba; lo que se movía era el orden de pintado. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
f248ad57da |
Llena el ancho de las páginas de texto en vez de ensancharlas
El ancho útil vuelve a 74rem (1184px). Se había subido a 88rem para aprovechar los monitores anchos y salió al revés: la prosa tiene una medida de lectura y no crece con el contenedor, así que lo único que creció fue el hueco a su derecha. Un vacío al lado de un texto no se tapa estirando el texto —probado: 129 caracteres por línea, ilegible— sino poniendo algo al lado: - Los textos legales van a tres columnas: los otros documentos, el que se lee y sus apartados. El índice de apartados sale del Markdown en bruto y las anclas las pone un plugin al compilarlo, así que hay pruebas de que las dos formas de calcularlas siguen coincidiendo. - El índice legal pasa de lista de renglones a rejilla de tarjetas, como el taller y los estilos; era el único listado que no se veía como los demás. - La bio lleva al lado lo que hay publicado —temas, discos y estilos, con sus enlaces—, sacado del catálogo y no escrito a mano, para que no se contradiga sola el día que se suba una canción. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
5c3d3371f0 |
Textos legales, fuentes propias y ajustes de botones
Cinco páginas legales en /legal, enlazadas desde el pie de todas las páginas: información legal, condiciones de uso, privacidad, cookies y condiciones de venta. Son borradores con los datos del titular marcados entre corchetes y un aviso de que hace falta revisión de un abogado antes de vender: cubren lo que pide la ley española, no son un documento validado. La política de cookies y la de privacidad están escritas mirando el código, no copiadas de una plantilla: dos cookies, las dos necesarias, y dos terceros —Stripe y Resend— que reciben lo imprescindible. Y eran tres, porque las tipografías venían de Google: cada visita mandaba la IP del visitante a un tercero sin pedirlo y sin que aportara nada. Ahora se sirven desde el propio dominio. Cargar la web ya no contacta con ningún dominio ajeno, y hay una prueba que lo comprueba. Aparte: el símbolo de marca registrada en el aviso de derechos, los botones de reproducir de las tarjetas pasan de 48 a 36 píxeles —eran casi una quinta parte de la portada, y cambiaban de proporción según la tarjeta— y el de ver el carrito solo aparece cuando hay algo dentro. De paso se arregla un fallo de tipos que estaba latente: `resolve()` tiene una sobrecarga por ruta y no acepta una unión, así que la navegación dejaba de compilar en cuanto se añadían rutas. Ahora se resuelve en `site.ts`, una a una. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
e929e8c5a9 |
Arregla el contraste del botón dorado y unifica la letra de los botones
El texto del botón dorado se aclaraba al pasar el puntero y quedaba en 1,67 de contraste sobre el oro. La causa no era el color del botón: `.btn:hover` pone `color: inherit` —para que la regla general de los enlaces no tiña de dorado los secundarios— y le gana por especificidad. Ahora el dorado repite su color ahí. De paso, el dorado se parte en dos tokens porque hacía dos trabajos incompatibles: de relleno tiene que ser claro para que encima se lea el marino —7,6 de contraste en el tema claro— y escrito tiene que ser hondo para leerse sobre el fondo —5,3—. Con un solo valor, el tema claro se quedaba en 4,4, por debajo del mínimo. Y encima del oro va marino, no blanco, en los dos temas. Los botones tenían tres tamaños distintos: el dorado a 16px con relleno 8/16 y el de al lado a 14px con 12/24. Dos botones juntos con distinta letra se ven como un descuido. Ahora hay una sola escala, y los 15px son los del menú. El botón de ver el carrito solo aparece cuando hay algo dentro, con la cuenta: uno que lleva a una página vacía gasta el sitio de una llamada a la acción para decir que no hay nada. Tres pruebas nuevas lo fijan, incluida la del contraste con el puntero encima, que es donde estaba el fallo y donde una captura en reposo no lo enseña. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
afa8fd4be5 |
Arregla el hover de los botones y da estado a los enlaces que no lo tenían
El botón dorado se quedaba en un rectángulo oscuro con el borde de oro al pasar el puntero. La causa: `.btn:hover` usaba el atajo `background`, que reinicia también `background-image` y se llevaba el degradado por delante. Las reglas base pasan a `background-color`, que es la longhand que no pisa lo que no le toca. De comprobarlo salió que no había ningún `a:hover` global: cualquier enlace sin regla propia —el del feed, los del pie— no daba ninguna señal de ser pulsable. Ahora todos responden con el dorado, que es el color de lo accionable aquí. Tampoco la tenía el conmutador de vista de la página de música. El botón secundario acusa el puntero con el fondo y el canto, no tiñendo el texto de dorado: sería una señal doble y competiría con el botón dorado que suele tener al lado. Seis pruebas nuevas cubren la respuesta al puntero de cada tipo de control. Es lo que faltaba: un estado de hover roto no se ve en una captura en reposo, y así fue como se coló. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
da127119c6 |
Pack de diez por un café, fotos en las láminas y oro con reflejo
El pack pasa de cinco a diez canciones por el mismo 1,50 €: diez canciones por lo que cuesta un café. Es la propuesta, así que el número y el importe se leen juntos en todas partes. Las pruebas de la tienda estaban escritas con el cinco metido a mano y hubo que reescribirlas enteras. Ahora dicen la regla en términos del propio tamaño del pack, y el helper de las pruebas de extremo a extremo añade lo que haya a la venta hasta llenarlo en vez de nombrar los temas uno a uno: así cambiar el tamaño otra vez no obliga a tocar nada. Las dos láminas de llamada estrenan foto propia con su velo, más cubriente que el de la textura: sobre una imagen clara el texto blanco no se lee. Y el dorado deja de ser plano en los botones. Un metal refleja, y lo que lo hace parecer metal es la banda de luz que lo cruza; el fondo se pinta más alto que el botón para que al acercar el puntero la luz recorra la pieza en vez de limitarse a aclararla. El acento sube un punto de croma y baja uno de claridad, que es lo que lo separa de un amarillo de rotulador. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
ba72469710 |
Ondas animadas de fondo en la cabecera
Un shader de ondas en los azules de marca, sobre la imagen de la portada. Es WebGL a pelo: un fondo así es un triángulo y un programa de fragmentos, y traerse una biblioteca 3D para eso sería medio mega de dependencia en la primera pantalla del sitio. El dibujo es domain warping —ruido que desplaza el dominio de otro ruido—, con la escala horizontal mayor que la vertical para que las formas se tumben en bandas en vez de quedarse redondas. La paleta va en RGB lineal, que es en lo que mezcla el shader. El primer intento usó los cuatro fondos de `app.css` tal cual y salió una plancha lisa: caben en un pelo de claridad, y sin recorrido de color el ruido no se ve por bien que esté calculado. Con `prefers-reduced-motion` no se monta; se para al salir de pantalla y al cambiar de pestaña; y si no hay WebGL o el programa no compila, debajo queda la imagen de siempre. Solo lo lleva la cabecera: en las tres láminas serían tres shaders pintando lo mismo a la vez. De paso resuelve el tema claro, que no tenía imagen propia: lo pinta en azules pálidos, así que el clip de relleno se va. Las pruebas arrancan Chromium con SwiftShader para poder comprobar el efecto y no solo su ausencia. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
a69bf0479a |
Deja de repetir el fondo de la portada, las migas y las etiquetas
Tres piezas estaban copiadas en varios sitios y ahora se escriben una vez: el fondo a sangre de la portada, las migas de pan y la pastilla de una etiqueta. El fondo ya había divergido entre la cabecera y las láminas de llamada: el degradado era distinto por descuido y no por decisión, que es lo que pasa con el marcado duplicado. Las migas pasan a ser una lista ordenada, que es su marcado correcto: un lector de pantalla anuncia cuántos escalones hay y en cuál se va, y el último deja de ser un enlace a donde ya estás. Tres cosas salieron de hacerlo, ninguna cosmética: - Con el texto como clave del bucle, un disco y un tema que se llaman igual —«Como si nada» es las dos cosas— daban claves duplicadas y tumbaban la ficha al hidratar. El SSR salía bien, así que solo se veía en el navegador. - Al compartir el fondo, las tres láminas montaban el clip de vídeo. En tema claro eso eran tres copias del mismo vídeo en la portada. Ahora lo pide solo la cabecera. - La lista de temas de un disco no tenía nombre, así que no se distinguía de ninguna otra lista de la página. Ahora se llama «Temas». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
361cd162e1 |
Cierra una redirección abierta, quita código muerto y afina el responsive
El campo `volverA` de los formularios se comprobaba en tres sitios con tres copias del mismo filtro, y las tres dejaban pasar `/\otro-dominio.com`: el navegador convierte la barra invertida en barra normal al resolver, así que eso es `//otro-dominio.com` con otra ropa. En la pantalla de entrar eso es phishing servido: enlace a nuestro propio acceso, y quien escribe su correo acaba fuera. Ahora hay un solo `destinoSeguro`, que no compara prefijos sino que resuelve la URL y solo acepta lo que sigue en el origen. Con pruebas de cada disfraz. Fuera siete funciones exportadas que no llamaba nadie. Las escribí "por si acaso" y una API que no se usa no es una API: es código que leer y mantener sin que nada dependa de ella. Del repaso responsive salen dos fallos reales. Los puntos del carrusel medían 8×8 píxeles, la tercera parte del mínimo para acertarles con el dedo; ahora el punto se ve igual y el botón mide 24×24. Y el hueco reservado bajo el contenido para la barra de reproducción estaba escrito a mano en 88 píxeles cuando la barra mide 97 en escritorio y 145 apilada en un móvil: se comía el pie. Ahora la barra se mide sola y publica su alto. Todo ello fijado en `responsive.e2e.ts`, que recorre diez páginas a cuatro anchos. Sobre rendimiento, nada que hacer: parecía que las páginas tardaban 215 ms, pero eran de la resolución de `localhost` por IPv6 en la medición. Por IPv4 se renderizan en 5-9 ms, así que memorizar el catálogo habría sido optimizar un problema inexistente. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
e1884864cf |
Carrusel en la portada y letras a dos columnas
La portada abre con tres láminas: el disco en el tocadiscos, una invitación al taller y otra a la tienda. Un carrusel mal hecho es de las piezas más hostiles que hay —cambia mientras lees, no se para, y para un lector de pantalla es un cajón que aparece y desaparece—, así que este se para al pasar el puntero o al entrar el foco, tiene botón de pausa, no gira solo con `prefers-reduced-motion` y deja las láminas ocultas con `inert`, fuera del orden de tabulación. Las letras que no están en español se enfrentan con su traducción en dos columnas, verso a verso. Cada columna declara su `lang`, que es lo que impide que un lector de pantalla lea el inglés con voz española, y la traducción se pinta con `pre-line`: es verso, y perder los cortes la deja inservible para seguir la original. El nombre del idioma sale de `Intl.DisplayNames`. Sobre el reproductor: ya sobrevivía a la navegación, porque vive en el layout raíz fuera de `main`. Lo que faltaba era comprobarlo de verdad; el test decía que la barra seguía visible, no que siguiera sonando. Ahora mira que la posición avance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
4c65a5b719 |
Portada por estilos, tarjetas con otro movimiento, y fuera la palabra «segmento»
La palabra se va del proyecto entero, interfaz e identificadores. Venía del encargo inicial pero no es la del oficio y se colaba en la interfaz: lo que hay son estilos, discos y temas. Lo que agrupa un estilo con su obra pasa a ser `EstiloConObra`, y el componente que lo pinta, `BloqueDeEstilo`. La portada cuenta el catálogo en tres pasos: el estilo principal a fila completa, sus discos debajo, y el resto en una rejilla donde cada tarjeta dice cuánto hay y de qué se habla. Las etiquetas de un estilo no se declaran: salen de sus temas, así que no hay dos sitios que mantener. La página de un estilo estrena su propio `h1` —antes heredaba un `h2` del listado, y se quedaba sin encabezado de nivel uno— y pierde el botón de reproducir suelto en la cabecera, que no decía qué iba a sonar. Los demás estilos la acompañan en una barra lateral que ahora vive en el layout de la sección, así que la llevan también la portada de música y cualquier página que se añada. Las tarjetas se mueven de otra manera: reflejo que nace bajo el puntero, borde dorado, portada que recupera el color, subrayado que crece y respuesta al pulsar. Nada usa la curva por defecto. Dos rarezas del minificador de CSS, ambas comprobadas en el build y ambas dejaban efectos muertos: junta las funciones de un filtro sin el espacio que las separa, y borra `backdrop-filter` sin prefijo si se declara también la versión `-webkit-`. Y la canción real estrena su vídeo de YouTube. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
c25d432d30 |
Web de Senza Paura: catálogo, taller, blog y tienda
Sitio del letrista y compositor, con SvelteKit 2 y Svelte 5. El catálogo es contenido, no base de datos: estilos, álbumes, canciones y capítulos son Markdown en `src/content/`, validados al compilar y compilados dentro del bundle, así que recorrer la música no hace ni una consulta. La base de datos guarda solo lo que generan las personas: cuentas, carritos, pedidos, compras, valoraciones y favoritos. Lo que hay: - Música agrupada por estilos, con página propia para cada estilo, álbum y tema, buscador y tabla ordenable. - Reproductor persistente que sobrevive a la navegación. Suena un fragmento; el archivo completo solo se obtiene comprando. - Taller de letras: los principios del oficio y una ficha de creación por estilo hispanoamericano. - Blog con feed RSS, y etiquetas que cruzan blog y catálogo. - Tienda con cuentas por código de correo, carrito, Stripe y descargas protegidas. - Panel de contenido en `/admin` que escribe los mismos Markdown. - Tema oscuro de marca y su inversión clara, aplicado antes de pintar. Lo que falta y no es código: las claves de Stripe y de correo, el tratamiento del IVA, las páginas de condiciones y privacidad, y el material real. Las canciones de ejemplo son inventadas y están para sustituirse; el audio son marcadores salvo un tema. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |