Skip to content
Pablo Martínez López edited this page Oct 29, 2026 · 1 revision

Iconos

English · Español

Todos los iconos de la app son iconos de Iconify que pinta un único componente, <Icono icon="prefijo:nombre">. Hay dos clases: los que el código escribe tal cual (van dentro de la app desde la compilación, se pintan al momento y sin red) y los que elige la persona con el selector de iconos (por ahora, el icono de una etiqueta de la biblioteca), que Rust baja una vez de la API de Iconify y guarda en disco para que se vean sin red.

La única excepción es src/components/ui/: las primitivas de shadcn/judlex son de solo lectura y siguen importando lucide-react (las flechas de los selectores y los menús, la cruz de cerrar de los diálogos, la marca de las casillas). Todo lo que está fuera de esa carpeta usa <Icono>.

Ficheros

Fichero Responsabilidad
src/components/icono.tsx Icono({ icon, size, ... }): un <svg> con el viewBox y el cuerpo del icono. Los incluidos salen de INCLUIDOS; cualquier otro id se pide con useIconos().pedir(id) y su hueco (24 px de fábrica, o la clase size-*) se guarda vacío hasta que llega, así nada salta. Un id vacío no pinta nada.
src/lib/iconos/incluidos.ts Generado por scripts/iconos.mjs (no se edita a mano, fuera de Biome): INCLUIDOS: Record<id, { body, vb }>, los datos de cada id de icono escrito tal cual en src/.
scripts/iconos.mjs Recorre src/**/*.{ts,tsx} (sin node_modules, bindings, assets, __tests__ ni los ficheros de test), encuentra cada prefijo:nombre entre comillas, lo busca en las colecciones de @iconify/json (con los alias resueltos por getIconData/iconToSVG de @iconify/utils) y escribe incluidos.ts. Las cadenas entre comillas que no son iconos (16:9, pbimg:…) se caen solas porque su prefijo no es una colección; un id cuya colección existe pero cuyo nombre no, es un error. --check falla si el fichero no está al día.
src/components/selector-icono.tsx SelectorIcono({ valor, onChange, quitable }): el selector de iconos.
src/stores/iconos-store.ts useIconos: datos (los iconos que Rust ya devolvió en esta sesión), pedir(id) (junta los ids pedidos en un mismo pintado, 16 ms, en un único iconos_datos; si falla, se pueden volver a pedir) y recibir.
src-tauri/src/iconos.rs El cliente de Iconify: catálogo, búsqueda, datos de iconos, iconos elegidos, limpieza del SVG.
src-tauri/src/commands/iconos.rs Los cinco comandos de abajo.

Dependencias: @iconify/utils (dependencia de ejecución, la usa el script) y @iconify/json (dependencia de desarrollo con todas las colecciones; en ignoreDependencies de knip.json porque solo la lee el script desde node_modules).

Iconos incluidos (pnpm iconos)

flowchart LR
    SRC["src/**/*.tsx<br/>&quot;game-icons:crown&quot;"] -->|pnpm iconos| GEN["src/lib/iconos/incluidos.ts"]
    JSON["@iconify/json"] --> GEN
    GEN --> ICONO["&lt;Icono&gt;"]
    ICONO -->|id no incluido| STORE["useIconos.pedir"] -->|iconos_datos| RUST["iconos.rs"]
Loading

Tras añadir o cambiar un id de icono en el código, pnpm iconos. pnpm check ejecuta pnpm check:iconos (node scripts/iconos.mjs --check), así que olvidarse de regenerarlo falla en local y en el CI. Por qué generarlo en vez de importar icono a icono: un solo componente para las dos clases de icono (escritos y elegidos), sin red para los iconos propios de la app, y en el paquete solo entran los iconos que se usan.

Un id montado con una plantilla (`lucide:${x}`) no lo ve el script: hay que escribir los ids enteros en algún sitio del código (una tabla) para que entren. No incluido quiere decir bajado de la red al usarlo, y los iconos propios de la app nunca deben necesitarla.

Qué colección: lucide:* para los iconos generales de la interfaz (la misma familia que usaba la app antes), game-icons:* para los conceptos de juego de las pantallas de «Jugar» y del registro de la partida: veneno (frasco), monarca (corona), iniciativa (puerta de mazmorra), bendición de la ciudad (castillo), cementerio (lápida), el sol y la luna del día/noche, «no se endereza» (candado), fuera de fase (portal), notas temporales (reloj de arena), etc. Deducido: otras colecciones valen cuando encajan, siempre que el id se escriba tal cual.

Iconos elegidos (el selector)

SelectorIcono es un botón con el icono actual (o un hueco) que abre un popover, como el IconPicker de la web del proyecto, pero cada petición pasa por Rust porque la vista web nunca sale a internet:

  • Elegir colección: todas las colecciones visibles de Iconify (iconos_colecciones, por categoría y nombre, con cuántos iconos tiene cada una) más «Todas las colecciones», que busca por nombre en todas (iconos_buscar). Se abre en la colección del icono actual, o en game-icons si no hay.
  • Filtro: dentro de una colección, un filtro local sobre sus nombres (iconos_nombres); en «todas las colecciones», el texto de búsqueda («Buscar en todas (2 letras o más)…»: dos letras como mínimo).
  • Páginas: 240 iconos cada vez (PAGINA) y un botón «Mostrar más» para los siguientes; los que se ven se piden juntos por useIconos.
  • Elegir llama a iconos_elegir(id), que guarda los datos del icono para verlo sin red, y devuelve el id entero (game-icons:crown) a onChange. Con quitable, «Sin icono» lo quita.

Las colecciones, nombres y búsquedas ya cargados se guardan además en variables del módulo durante el resto de la sesión.

Lado de Rust (iconos.rs)

Comando Hace
iconos_colecciones() GET api.iconify.design/collections → Vec<ColeccionIconos { prefijo, nombre, total, categoria }>, sin las colecciones ocultas ni los prefijos raros.
iconos_nombres(prefijo) GET /collection?prefix=… → todos los nombres (con y sin categoría), ordenados.
iconos_buscar(texto) GET /search?query=…&limit=999 (el máximo de la API); el texto va en minúsculas, cortado a 40 caracteres, solo letras, cifras, espacios y guiones. Los resultados se guardan en memoria por búsqueda.
iconos_datos(ids) BTreeMap<id, DatosIcono { body, vb }>, de memoria, de los elegidos en disco o de GET /<prefijo>.json?icons=a,b,… (120 por petición, como mucho 2.000 ids por llamada).
iconos_elegir(id) Como iconos_datos con un id, y luego lo escribe en el fichero de elegidos. NotFound si el icono no existe.
  • Red: por fuentes::Externo con la entrada nueva de la lista de permitidos ("api.iconify.design", "/"), así cada redirección se vuelve a comprobar y las respuestas tienen tope de tamaño (8 MiB de JSON, MAX_JSON). Véase Fuentes externas.
  • Ids: partir solo acepta prefijo:nombre con letras ASCII minúsculas, cifras, - y _, hasta 64 caracteres cada parte; a una URL nunca llega nada más (los_ids_raros_no_llegan_a_la_url). id_valido lo usa la biblioteca para rechazar un icono de etiqueta malo.
  • Alias: resolver sigue hasta 6 saltos de alias, hereda la medida y suma giros y volteos; a_svg hace lo mismo que iconToSVG de @iconify/utils (las transformaciones en un <g>, ancho y alto cambiados a 90°/270°), así los incluidos y los bajados se ven igual.
  • Limpieza (seguro): el cuerpo se mete en la página tal cual (dangerouslySetInnerHTML), así que se descarta cualquier cuerpo con <script, foreignObject, javascript:, <image, <iframe, <!entity, un manejador on…= o un href/url( que no sea un #id local (el_svg_peligroso_se_rechaza). Los incluidos salen de @iconify/json al compilar y son de fiar.
  • Dónde se guarda: el catálogo (la lista de colecciones y los nombres de cada una) en la caché, app_cache_dir/iconos/ (colecciones.json, <prefijo>.json), renovado a los 7 días (RENOVAR); se puede borrar. Los datos de los iconos vistos en el selector, solo en memoria. Los elegidos, a los que apunta algo guardado, van a app_data_dir/iconos/elegidos.json (escrito de forma atómica), así el icono de una etiqueta se ve sin red o tras borrar la caché. Véase Almacenamiento y blobs.

Dónde se usan los iconos elegidos

Tests

  • Rust: iconos::tests (se rechazan los ids que podrían romper una URL, se rechaza el SVG peligroso y no url(#a) ni los nombres que contienen «on», un alias hereda de su padre y se voltea).
  • pnpm check:iconos mantiene incluidos.ts al día con el código.

Véase también

Documentation · Documentación

Language: English · Español

Use and build · Uso y desarrollo

Architecture · Arquitectura

Data · Datos

Getting cards · Conseguir cartas

Layout, images, PDF · Maquetación, imagen y PDF

Card designer · Diseñador de cartas

Game table · Mesa de juego

Frontend · Frontend

Reference · Referencia

Clone this wiki locally