codex/estilos-web-publica
codex/redisenio-dominio-musical
master
${ noResults }
10 Commits (master)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
fa4de8b2f6 |
Una sola tabla de canciones, y la cola se puede llenar
Había dos listados: una tabla ordenable para el catálogo y una lista aparte para los discos. Cada arreglo había que hacerlo dos veces y el resultado era que la portada estaba en una y el año en la otra. Ahora es un solo componente, y lo que cambia son las columnas de contexto, que se encienden por props: dentro de un disco, la columna «Álbum» diría diez veces lo mismo. Solo recibe canciones. El estilo, el disco y la portada los resuelve contra el catálogo que ya baja en `page.data`, así que quien la usa no tiene que armar filas a mano, que era lo que obligaba a repetir código. Cada fila lleva su portada —con la ampliada al pasar el ratón—, y debajo del título van los géneros y las etiquetas en vez del primer verso: la letra está entera en la ficha, y aquí lo que sirve para elegir es de qué está hecho el tema. Las etiquetas se cortan por número, con un «+2» al final: recortarlas con un degradado dejaba «Autoengaño» en «Autoeng», que no parece una elección sino algo roto. La cola ya se puede llenar. Hasta ahora solo se podía sustituir —cada play la vaciaba y la llenaba con su contexto—, así que no había forma de armar una escucha cogiendo temas de discos distintos. `encolar()` es la otra mitad, y con la cola vacía arranca, porque un botón que no hace nada es peor que no tenerlo. Los géneros de una canción entran en el modelo: `cancion_genero` existía en la base y no llegaba a la web. Son cosa distinta del estilo —el estilo es cómo se ordena la obra aquí y es uno solo; los géneros son de qué está hecha la canción y pueden ser varios— y llevan al glosario. De paso: las letras largas van a dos columnas de 37ch, que es el mínimo que deja caber dos y a la vez el verso más largo del catálogo —importa afinarlo, porque en una letra dónde acaba cada verso es parte del texto—; la página baja de 2808 a 2023 píxeles. Contacto sale de la barra de menú y se queda solo en el pie. Y el titular pasa a «Letrista y creador musical». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
4d2a2072c2 |
Las páginas de error, a pantalla completa y desnudas
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) <noreply@anthropic.com> |
4 weeks ago |
|
|
623eaa9bea |
Las páginas de error, con su lámina y su tema
Cada una lleva la suya: la del 404 y la del 500, recortadas del original —traían una banda plana pegada a la derecha, de generarlas— y pasadas a webp, 95 y 70 KB. El encabezado no repite lo que la lámina ya lleva dibujado: dice lo mismo con otras palabras, para que no se lea dos veces seguidas y para que la página siga teniendo titular si la imagen no carga. La música suena con un botón, no sola. Los navegadores cortan el audio que empieza sin que el usuario haya tocado nada, y quien llega a un 404 desde un enlace roto no ha tocado nada: arrancarla al cargar no fallaría, es que no sonaría, y en silencio. Con `preload="none"`, además, el mp3 no se descarga hasta que se pide; sin eso, 686 KB a todo el que aterrice. Y suena una cosa cada vez. Al 404 no se puede llegar sin recarga entera —SvelteKit no enruta lo que no existe—, así que ahí nunca hay barra; al 500 sí, y entonces darle aquí pausa el tema, y darle al play de la barra para esto. Un 403 no es ninguna de las dos cosas: la página existe y el sitio funciona, es que no te toca. Esos salen sin ilustración, con su mensaje, en vez de con una lámina que miente. 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`, que es lo que sale cuando la aplicación no puede ni pintar su propia página de error. Va desnudo a propósito: sin hoja de estilos, sin fuentes, sin imagen y sin JavaScript, porque todo lo que pidiera fuera podría estar caído también. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
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 |
|
|
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> |
4 weeks 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 |
|
|
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 |