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
|
|
|
import { sep } from 'node:path';
|
|
|
|
|
import { mdsvex } from 'mdsvex';
|
|
|
|
|
import remarkBreaks from 'remark-breaks';
|
|
|
|
|
import { defineConfig } from 'vitest/config';
|
|
|
|
|
import { playwright } from '@vitest/browser-playwright';
|
|
|
|
|
import adapter from '@sveltejs/adapter-node';
|
|
|
|
|
import { sveltekit } from '@sveltejs/kit/vite';
|
|
|
|
|
import type { PreprocessorGroup } from 'svelte/compiler';
|
|
|
|
|
import { conExtracto } from './src/lib/content/extracto.ts';
|
|
|
|
|
import { ancla } from './src/lib/content/anclas.ts';
|
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
|
|
|
|
|
|
|
|
/**
|
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
|
|
|
* Dos aplicaciones, un repositorio.
|
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
|
|
|
*
|
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
|
|
|
* `APP=panel` compila la administración; sin esa variable, la web pública. Cada
|
|
|
|
|
* una tiene su carpeta de rutas, sus hooks y su carpeta de salida, así que **el
|
|
|
|
|
* servidor público no lleva dentro ni una línea del panel**: no es que la
|
|
|
|
|
* esconda, es que ahí no existe. Cada una se sirve en su dominio y en su
|
|
|
|
|
* proceso, como los archivos en `m.senzapaura.es`.
|
|
|
|
|
*
|
|
|
|
|
* Comparten `src/lib`, que es donde están el esquema, las consultas y el
|
|
|
|
|
* acceso. Con dos repositorios habría que mantener las migraciones por
|
|
|
|
|
* duplicado, y el día que se desincronizaran nadie se enteraría hasta que el
|
|
|
|
|
* panel guardara en una columna que ya no existe.
|
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
|
|
|
*/
|
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
|
|
|
const esPanel = process.env.APP === 'panel';
|
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
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Escribe en el frontmatter de cada cancion los primeros versos de su letra.
|
|
|
|
|
*
|
|
|
|
|
* Tiene que correr ANTES que mdsvex: despues, el cuerpo ya es un componente
|
|
|
|
|
* compilado y el texto ha dejado de ser texto. Con esto, las tarjetas pueden
|
|
|
|
|
* ensenar unos versos sin que nadie mantenga a mano un campo de resumen.
|
|
|
|
|
*/
|
|
|
|
|
const inyectarExtracto: PreprocessorGroup = {
|
|
|
|
|
name: 'extracto-de-cancion',
|
|
|
|
|
markup({ content, filename }) {
|
|
|
|
|
// En Windows los nombres llegan con barras invertidas.
|
|
|
|
|
if (!filename?.split(sep).join('/').includes('/src/content/canciones/')) return;
|
|
|
|
|
const conFragmento = conExtracto(content);
|
|
|
|
|
return conFragmento === content ? undefined : { code: conFragmento };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Pone un `id` a cada encabezado de nivel 2 del Markdown.
|
|
|
|
|
*
|
|
|
|
|
* Hace falta para que el indice lateral de los textos largos pueda enlazar a
|
|
|
|
|
* sus apartados. Se escribe a mano en vez de traer `rehype-slug` porque son
|
|
|
|
|
* quince lineas, y porque el ancla tiene que salir de la misma funcion que usa
|
|
|
|
|
* el cargador al construir el indice: con dos implementaciones parecidas, un
|
|
|
|
|
* dia dejan de coincidir.
|
|
|
|
|
*/
|
|
|
|
|
type NodoHast = {
|
|
|
|
|
type: string;
|
|
|
|
|
tagName?: string;
|
|
|
|
|
value?: string;
|
|
|
|
|
properties?: Record<string, unknown>;
|
|
|
|
|
children?: NodoHast[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function textoDe(nodo: NodoHast): string {
|
|
|
|
|
if (nodo.type === 'text') return nodo.value ?? '';
|
|
|
|
|
return (nodo.children ?? []).map(textoDe).join('');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function anclasEnEncabezados() {
|
|
|
|
|
return (arbol: NodoHast) => {
|
|
|
|
|
const recorrer = (nodo: NodoHast) => {
|
|
|
|
|
if (nodo.tagName === 'h2') {
|
|
|
|
|
nodo.properties = { ...nodo.properties, id: ancla(textoDe(nodo)) };
|
|
|
|
|
}
|
|
|
|
|
for (const hijo of nodo.children ?? []) recorrer(hijo);
|
|
|
|
|
};
|
|
|
|
|
recorrer(arbol);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
|
* mdsvex 0.12 emite `<script context="module">` para exportar el frontmatter,
|
|
|
|
|
* sintaxis que Svelte 5 marca como obsoleta. El aviso apunta a los .md de
|
|
|
|
|
* contenido, donde no hay nada que corregir, y sale uno por archivo en cada
|
|
|
|
|
* compilacion.
|
|
|
|
|
*
|
|
|
|
|
* Se corrige la salida en lugar de silenciar el aviso: `sveltekit()` ignora
|
|
|
|
|
* `onwarn` cuando la configuracion viaja en el propio vite.config.ts.
|
|
|
|
|
*/
|
|
|
|
|
const corregirScriptDeMdsvex: PreprocessorGroup = {
|
|
|
|
|
name: 'mdsvex-script-module',
|
|
|
|
|
markup({ content, filename }) {
|
|
|
|
|
if (!filename?.endsWith('.md') && !filename?.endsWith('.svx')) return;
|
|
|
|
|
if (!content.includes('<script context="module">')) return;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
code: content.replaceAll('<script context="module">', '<script module>')
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default defineConfig({
|
|
|
|
|
plugins: [
|
|
|
|
|
sveltekit({
|
|
|
|
|
compilerOptions: {
|
|
|
|
|
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
|
|
|
|
|
runes: ({ filename }) =>
|
|
|
|
|
filename.split(/[/\\]/).includes('node_modules') ? undefined : true
|
|
|
|
|
},
|
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
|
|
|
/*
|
|
|
|
|
* Lo único que distingue a las dos aplicaciones: de dónde salen las
|
|
|
|
|
* rutas, qué hooks corren y dónde se escribe el resultado. Los `.svelte-kit`
|
|
|
|
|
* también van separados, porque ahí dentro está el manifiesto de rutas
|
|
|
|
|
* y con uno compartido cada build borraría el del otro.
|
|
|
|
|
*/
|
|
|
|
|
files: esPanel
|
|
|
|
|
? { routes: 'src/panel/rutas', hooks: { server: 'src/panel/hooks.server' } }
|
|
|
|
|
: undefined,
|
|
|
|
|
outDir: esPanel ? '.svelte-kit-panel' : '.svelte-kit',
|
|
|
|
|
adapter: adapter({ out: esPanel ? 'build-panel' : 'build' }),
|
Página de «muy pronto» para quien llega de fuera
Con `PROXIMAMENTE=1`, quien no esté en la lista acaba en una página de
espera con el mismo fondo animado que la portada. La red local entra
siempre sin configurar nada: encender el portón y quedarse uno mismo
fuera es la forma más rápida de no poder comprobar si funciona.
Tres decisiones que salieron de probarlo:
- **Redirige, no pinta la espera en la dirección pedida.** Se intentó lo
segundo, que conserva la dirección en la barra, y no vale: el HTML sale
compuesto para /proximamente y el navegador lo hidrata creyendo estar
en otra ruta, así que al terminar de cargar volvía a pintar la cabecera
y el pie que la espera no debe tener.
- **503, no 200.** La web existe pero todavía no atiende. Es lo que
impide que un buscador se lleve el cartel como si fuera el sitio. Y el
robots.txt pasa a cerrar el paso entero mientras dure: si no,
anunciaría un mapa lleno de direcciones que hoy contestan «muy pronto».
- **Rutas de recursos absolutas.** Con las relativas que SvelteKit usa por
defecto, la página servida en otra dirección pedía sus hojas de estilo
en un sitio donde no hay ninguna.
El reconocimiento de direcciones va aparte y con pruebas: una máscara mal
interpretada no da ningún error, solo deja pasar a quien no debía. Ahí
está el caso de `/0`, que en JavaScript se cuela porque el desplazamiento
de 32 bits es un no-op.
Y el portón está abierto mientras nadie diga lo contrario. Una web que se
esconde sola porque falta una variable es peor fallo que una que se ve
antes de tiempo: nadie mira una página que cree no publicada, así que
puede pasar semanas caída sin que se note.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4 weeks ago
|
|
|
paths: {
|
|
|
|
|
/*
|
|
|
|
|
* Rutas absolutas para los recursos —`/_app/…`— en vez de las
|
|
|
|
|
* relativas que SvelteKit usa por defecto.
|
|
|
|
|
*
|
|
|
|
|
* Hace falta por la página de espera: su HTML se sirve en la
|
|
|
|
|
* dirección que pidió quien llega, no en `/proximamente`. Con rutas
|
|
|
|
|
* relativas, un visitante en `/musica/baladas-romanticas` pedía sus
|
|
|
|
|
* hojas de estilo en `/musica/_app/…` y no encontraba ninguna.
|
|
|
|
|
*
|
|
|
|
|
* No se pierde nada: las relativas sirven para poder mover el sitio a
|
|
|
|
|
* un subdirectorio sin reconstruir, y este vive en la raíz de su
|
|
|
|
|
* dominio.
|
|
|
|
|
*/
|
|
|
|
|
relative: false
|
|
|
|
|
},
|
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
|
|
|
preprocess: [
|
|
|
|
|
inyectarExtracto,
|
|
|
|
|
mdsvex({
|
|
|
|
|
extensions: ['.svx', '.md'],
|
|
|
|
|
// Sin remark-breaks, Markdown junta los versos de una letra en un
|
|
|
|
|
// unico parrafo: en una cancion el salto de linea es contenido.
|
|
|
|
|
// mdsvex declara los plugins con una version antigua de los tipos de
|
|
|
|
|
// unified, incompatible con la de remark-breaks 4. En ejecucion
|
|
|
|
|
// encajan; lo que choca es solo la firma.
|
|
|
|
|
// @ts-expect-error tipos de unified desalineados entre mdsvex y remark-breaks
|
|
|
|
|
remarkPlugins: [remarkBreaks],
|
|
|
|
|
rehypePlugins: [anclasEnEncabezados]
|
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
|
|
|
}),
|
|
|
|
|
corregirScriptDeMdsvex
|
|
|
|
|
],
|
|
|
|
|
extensions: ['.svelte', '.svx', '.md'],
|
|
|
|
|
typescript: {
|
|
|
|
|
config: (config) => {
|
|
|
|
|
config.include.push('../drizzle.config.ts');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
test: {
|
|
|
|
|
expect: { requireAssertions: true },
|
|
|
|
|
projects: [
|
|
|
|
|
{
|
|
|
|
|
extends: './vite.config.ts',
|
|
|
|
|
test: {
|
|
|
|
|
name: 'client',
|
|
|
|
|
browser: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
provider: playwright(),
|
|
|
|
|
instances: [{ browser: 'chromium', headless: true }]
|
|
|
|
|
},
|
|
|
|
|
include: ['src/**/*.svelte.{test,spec}.{js,ts}'],
|
|
|
|
|
exclude: ['src/lib/server/**']
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
extends: './vite.config.ts',
|
|
|
|
|
test: {
|
|
|
|
|
name: 'server',
|
|
|
|
|
environment: 'node',
|
|
|
|
|
// Tambien las herramientas de `scripts/`: colocan archivos de audio
|
|
|
|
|
// segun una convencion de nombres, y equivocarla no da ningun error.
|
|
|
|
|
include: ['src/**/*.{test,spec}.{js,ts}', 'scripts/**/*.spec.mjs'],
|
|
|
|
|
exclude: ['src/**/*.svelte.{test,spec}.{js,ts}']
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
});
|