Lo que bloqueaba la fase 4 era el cliente, no las rutas: el catálogo viajaba en el paquete de JavaScript y las tarjetas, el carrito, la cuenta y el reproductor lo consultaban por su cuenta. Baja por `page.data` desde el layout —veintiún kilobytes, medidos, menos de lo que ocupaba en el paquete— y `$lib/catalogo/cliente.svelte` lo ata a las mismas consultas que usa el servidor. La otra opción era pasar por props lo que cada componente busca solo, y eso obligaba a tocar la compra, el carrito y el reproductor a la vez. Siete rutas dejan de ser cargadores universales: música, estilo, álbum, canción, portada y las dos de etiquetas. La ficha del tema se resuelve entera en el servidor, incluida la letra, que se pide sola y no viaja con el catálogo. Faltaba dónde guardar dos textos: la introducción de cada estilo y las notas de cada disco eran el cuerpo de su Markdown y el volcado se quedó solo con el frontmatter. Migración 0010 y `npm run db:completar` los rellena. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>master
parent
771e97c4e5
commit
0b823d44b4
@ -0,0 +1,9 @@
|
|||||||
|
-- El texto de los estilos y de los discos.
|
||||||
|
--
|
||||||
|
-- La introducción de cada estilo y las notas de cada disco eran el cuerpo de
|
||||||
|
-- su Markdown, y el volcado se quedó solo con el frontmatter: no había columna
|
||||||
|
-- donde ponerlas. Se vio al ir a cambiar las rutas, que las pedían como
|
||||||
|
-- componente compilado.
|
||||||
|
|
||||||
|
ALTER TABLE "album" ADD COLUMN "cuerpo" text DEFAULT '' NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "estilo" ADD COLUMN "cuerpo" text DEFAULT '' NOT NULL;
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* El catálogo en el navegador.
|
||||||
|
*
|
||||||
|
* Las mismas consultas de `./consultas`, atadas a lo que baja por
|
||||||
|
* `page.data.catalogo`. Antes venían de `$lib/content`, que cargaba los
|
||||||
|
* archivos al construir y por eso podía consultarse desde cualquier parte sin
|
||||||
|
* pedir nada: el catálogo entero viajaba en el paquete de JavaScript.
|
||||||
|
*
|
||||||
|
* Con el catálogo en la base eso deja de valer, y hay dos formas de arreglarlo:
|
||||||
|
* que cada componente reciba por props lo que hoy busca solo, o que el catálogo
|
||||||
|
* baje una vez y siga estando a mano. Se eligió lo segundo porque son
|
||||||
|
* veintiún kilobytes —menos de lo que ocupaba en el paquete— y porque lo
|
||||||
|
* primero obligaba a tocar la compra, el carrito y el reproductor a la vez.
|
||||||
|
*
|
||||||
|
* Es `.svelte.ts` porque `page` es estado con runes: lo que se lee aquí dentro
|
||||||
|
* es reactivo donde se use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { page } from '$app/state';
|
||||||
|
import * as q from './consultas';
|
||||||
|
import type { Catalogo } from './consultas';
|
||||||
|
import type { Cancion } from '$lib/types';
|
||||||
|
|
||||||
|
const VACIO: Catalogo = { estilos: [], albumes: [], canciones: [] };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lo que haya bajado, o nada.
|
||||||
|
*
|
||||||
|
* El vacío no es un caso hipotético: la página de espera no carga catálogo, y
|
||||||
|
* antes de que resuelva el `load` de la primera navegación tampoco hay. Sin
|
||||||
|
* este respaldo, una tarjeta reventaba en vez de pintarse sin portada.
|
||||||
|
*/
|
||||||
|
function cat(): Catalogo {
|
||||||
|
return (page.data.catalogo as Catalogo | undefined) ?? VACIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const estilos = () => cat().estilos;
|
||||||
|
export const albumes = () => cat().albumes;
|
||||||
|
export const canciones = () => cat().canciones;
|
||||||
|
|
||||||
|
export const obtenerEstilo = (slug: string) => q.obtenerEstilo(cat(), slug);
|
||||||
|
export const estiloPrincipal = () => q.estiloPrincipal(cat());
|
||||||
|
export const obtenerAlbum = (slug: string) => q.obtenerAlbum(cat(), slug);
|
||||||
|
export const obtenerCancion = (slug: string) => q.obtenerCancion(cat(), slug);
|
||||||
|
export const albumesDeEstilo = (estiloSlug: string) => q.albumesDeEstilo(cat(), estiloSlug);
|
||||||
|
export const estilosConObra = () => q.estilosConObra(cat());
|
||||||
|
export const etiquetas = () => q.etiquetas(cat());
|
||||||
|
export const etiquetasDeEstilo = (estiloSlug: string, cuantas = 4) =>
|
||||||
|
q.etiquetasDeEstilo(cat(), estiloSlug, cuantas);
|
||||||
|
export const obtenerEtiqueta = (slug: string) => q.obtenerEtiqueta(cat(), slug);
|
||||||
|
export const portadaDeCancion = (cancion: Cancion) => q.portadaDeCancion(cat(), cancion);
|
||||||
|
|
||||||
|
/* Estas dos no necesitan catálogo: son de la propia canción. */
|
||||||
|
export const albumDeCancion = q.albumDeCancion;
|
||||||
|
export const slugSingles = q.slugSingles;
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import {
|
||||||
|
albumesDeEstilo,
|
||||||
|
estiloPrincipal,
|
||||||
|
estilosConObra,
|
||||||
|
etiquetasDeEstilo,
|
||||||
|
leerCatalogo,
|
||||||
|
obtenerAlbum,
|
||||||
|
obtenerEstiloConObra
|
||||||
|
} from '$lib/server/catalogo';
|
||||||
|
import { heroe } from '$lib/site';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La portada cuenta el catálogo en tres pasos: el estilo principal, sus discos
|
||||||
|
* y el resto de estilos. No lleva selecciones ni novedades: el catálogo es
|
||||||
|
* pequeño y repetir las mismas tarjetas tres veces lo hace parecer aún más
|
||||||
|
* corto de lo que es.
|
||||||
|
*/
|
||||||
|
export async function load() {
|
||||||
|
const principal = await estiloPrincipal();
|
||||||
|
const { albumes } = await leerCatalogo();
|
||||||
|
|
||||||
|
return {
|
||||||
|
/** El disco que se pone en el tocadiscos de la cabecera. */
|
||||||
|
heroe: (await obtenerAlbum(heroe.album)) ?? (await obtenerAlbum(albumes[0]?.slug ?? '')),
|
||||||
|
|
||||||
|
bloquePrincipal: principal ? await obtenerEstiloConObra(principal.slug) : undefined,
|
||||||
|
/** De qué se habla en el estilo principal, sacado de sus temas. */
|
||||||
|
etiquetasPrincipal: principal ? await etiquetasDeEstilo(principal.slug, 6) : [],
|
||||||
|
|
||||||
|
/** Lo demás, como tarjetas: cuánto hay en cada uno y de qué va. */
|
||||||
|
otrosBloques: (await estilosConObra()).filter((b) => b.estilo.slug !== principal?.slug)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se importa para que quede claro que no hace falta: la portada no lo usa.
|
||||||
|
void albumesDeEstilo;
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import {
|
|
||||||
albumes,
|
|
||||||
estiloPrincipal,
|
|
||||||
estilosConObra,
|
|
||||||
etiquetasDeEstilo,
|
|
||||||
obtenerAlbum,
|
|
||||||
obtenerEstiloConObra
|
|
||||||
} from '$lib/content';
|
|
||||||
import { heroe } from '$lib/site';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* La portada cuenta el catalogo en tres pasos: el estilo principal, sus discos
|
|
||||||
* y el resto de estilos. No lleva selecciones ni novedades: el catalogo es
|
|
||||||
* pequeno y repetir las mismas tarjetas tres veces lo hace parecer aun mas
|
|
||||||
* corto de lo que es.
|
|
||||||
*/
|
|
||||||
export function load() {
|
|
||||||
const principal = estiloPrincipal();
|
|
||||||
const bloquePrincipal = principal ? obtenerEstiloConObra(principal.slug) : undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
/** El disco que se pone en el tocadiscos de la cabecera. */
|
|
||||||
heroe: obtenerAlbum(heroe.album) ?? obtenerAlbum(albumes[0]?.slug ?? ''),
|
|
||||||
|
|
||||||
bloquePrincipal,
|
|
||||||
/** De que se habla en el estilo principal, sacado de sus temas. */
|
|
||||||
etiquetasPrincipal: principal ? etiquetasDeEstilo(principal.slug, 6) : [],
|
|
||||||
|
|
||||||
/** Lo demas, como tarjetas: cuanto hay en cada uno y de que va. */
|
|
||||||
otrosBloques: estilosConObra().filter((b) => b.estilo.slug !== principal?.slug)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { notasDeAlbum, obtenerAlbum, obtenerEstilo } from '$lib/server/catalogo';
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
const album = await obtenerAlbum(params.slug);
|
||||||
|
if (!album) error(404, 'Ese album no existe.');
|
||||||
|
|
||||||
|
return {
|
||||||
|
album,
|
||||||
|
estilo: await obtenerEstilo(album.estilo),
|
||||||
|
// Un álbum de singles no existe como fila, así que tampoco tiene notas.
|
||||||
|
notas: album.sintetico ? '' : await notasDeAlbum(params.slug)
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { error } from '@sveltejs/kit';
|
|
||||||
import { cuerpoAlbum, obtenerAlbum, obtenerEstilo } from '$lib/content';
|
|
||||||
|
|
||||||
export function load({ params }) {
|
|
||||||
const album = obtenerAlbum(params.slug);
|
|
||||||
if (!album) error(404, 'Ese album no existe.');
|
|
||||||
|
|
||||||
return {
|
|
||||||
album,
|
|
||||||
estilo: obtenerEstilo(album.estilo),
|
|
||||||
// Un album de singles no tiene archivo propio, asi que tampoco notas.
|
|
||||||
Notas: album.sintetico ? undefined : cuerpoAlbum(params.slug)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import { error } from '@sveltejs/kit';
|
|
||||||
import {
|
|
||||||
albumDeCancion,
|
|
||||||
cuerpoCancion,
|
|
||||||
obtenerAlbum,
|
|
||||||
obtenerCancion,
|
|
||||||
obtenerEstilo,
|
|
||||||
portadaDeCancion
|
|
||||||
} from '$lib/content';
|
|
||||||
|
|
||||||
export function load({ params, data }) {
|
|
||||||
const cancion = obtenerCancion(params.slug);
|
|
||||||
if (!cancion) error(404, 'Ese tema no existe.');
|
|
||||||
|
|
||||||
// El album completo hace de contexto de reproduccion: darle al play aqui
|
|
||||||
// deja sonando el disco entero, no solo este tema. En un single suelto, el
|
|
||||||
// contexto es el album de singles de su estilo.
|
|
||||||
const album = obtenerAlbum(albumDeCancion(cancion));
|
|
||||||
const hermanas = album?.canciones ?? [cancion];
|
|
||||||
const posicion = hermanas.findIndex((c) => c.slug === cancion.slug);
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Las valoraciones vienen de `+page.server.ts`; lo demas, del catalogo.
|
|
||||||
...data,
|
|
||||||
cancion,
|
|
||||||
album,
|
|
||||||
estilo: obtenerEstilo(cancion.estilo),
|
|
||||||
portada: portadaDeCancion(cancion),
|
|
||||||
hermanas,
|
|
||||||
anterior: posicion > 0 ? hermanas[posicion - 1] : undefined,
|
|
||||||
siguiente: posicion < hermanas.length - 1 ? hermanas[posicion + 1] : undefined,
|
|
||||||
/** Cuerpo del Markdown: la letra, o las notas si es instrumental. */
|
|
||||||
Cuerpo: cuerpoCancion(params.slug)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { etiquetas } from '$lib/server/catalogo';
|
||||||
|
|
||||||
|
export async function load() {
|
||||||
|
return { etiquetas: await etiquetas() };
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { etiquetas } from '$lib/content';
|
|
||||||
|
|
||||||
export function load() {
|
|
||||||
return { etiquetas: etiquetas() };
|
|
||||||
}
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { obtenerEtiqueta } from '$lib/server/catalogo';
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
const etiqueta = await obtenerEtiqueta(params.etiqueta);
|
||||||
|
if (!etiqueta) error(404, 'Esa etiqueta no existe.');
|
||||||
|
|
||||||
|
return { etiqueta };
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { error } from '@sveltejs/kit';
|
|
||||||
import { obtenerEtiqueta } from '$lib/content';
|
|
||||||
|
|
||||||
export function load({ params }) {
|
|
||||||
const etiqueta = obtenerEtiqueta(params.etiqueta);
|
|
||||||
if (!etiqueta) error(404, 'Esa etiqueta no existe.');
|
|
||||||
|
|
||||||
return { etiqueta };
|
|
||||||
}
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { estilosConObra } from '$lib/server/catalogo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Los estilos se cargan una vez para toda la sección: la portada de música los
|
||||||
|
* necesita para pintar los bloques y cada página de estilo, para la barra
|
||||||
|
* lateral. Al resolverlo aquí, cambiar de estilo no vuelve a calcularlos.
|
||||||
|
*/
|
||||||
|
export async function load() {
|
||||||
|
return { bloques: await estilosConObra() };
|
||||||
|
}
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { estilosConObra } from '$lib/content';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Los estilos se cargan una vez para toda la seccion: la portada de musica los
|
|
||||||
* necesita para pintar los bloques y cada pagina de estilo, para la barra
|
|
||||||
* lateral. Al resolverlo aqui, cambiar de estilo no vuelve a calcularlos.
|
|
||||||
*/
|
|
||||||
export function load() {
|
|
||||||
return { bloques: estilosConObra() };
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { estilosConObra } from '$lib/content';
|
|
||||||
|
|
||||||
export function load() {
|
|
||||||
return { bloques: estilosConObra() };
|
|
||||||
}
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { obtenerEstiloConObra, textoDeEstilo } from '$lib/server/catalogo';
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
const bloque = await obtenerEstiloConObra(params.estilo);
|
||||||
|
if (!bloque) error(404, 'Ese estilo no existe.');
|
||||||
|
|
||||||
|
// El texto llega compuesto: antes era un componente que compilaba mdsvex.
|
||||||
|
return { bloque, introduccion: await textoDeEstilo(params.estilo) };
|
||||||
|
}
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { error } from '@sveltejs/kit';
|
|
||||||
import { cuerpoEstilo, obtenerEstiloConObra } from '$lib/content';
|
|
||||||
|
|
||||||
export function load({ params }) {
|
|
||||||
const bloque = obtenerEstiloConObra(params.estilo);
|
|
||||||
if (!bloque) error(404, 'Ese estilo no existe.');
|
|
||||||
|
|
||||||
return {
|
|
||||||
bloque,
|
|
||||||
/** Texto introductorio del estilo; el cuerpo del .md, si lo tiene. */
|
|
||||||
Introduccion: cuerpoEstilo(params.estilo)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue