Repository navigation
Stores de estado
English · Español
Todo el estado del frontend vive en stores de Zustand. Siete stores globales en src/stores/ cubren el mazo abierto, el plan de páginas, el estado de pantalla y las preferencias, el trabajo largo en marcha, la máquina de estados de la actualización de la app, la carta que se diseña con cambios sin guardar y la vista de la mesa de juego; unos cuantos stores de área viven junto a su feature. Los stores nunca calculan maquetación ni hacen trabajo pesado: guardan lo que devolvió Rust, llaman a Rust mediante call() y exponen acciones a los componentes.
| Store (hook) | Fichero | Persistencia | Papel en una línea |
|---|---|---|---|
useDeck |
src/stores/deck-store.ts |
Rust (SQLite) mediante deck_save, autoguardado con debounce |
El mazo abierto, el historial de deshacer/rehacer, el estado de guardado. |
usePlan |
src/stores/plan-store.ts |
ninguna (derivado) | El PagePlan que calcula Rust para el mazo abierto. |
useUi |
src/stores/ui-store.ts |
clave de localStorage proxybuilder.preferencias (solo el subconjunto de preferencias) |
Vista, zoom, selección, diálogo abierto, tutorial abierto, última acción, preferencias de la lista. |
useTrabajo |
src/stores/trabajo-store.ts |
ninguna | El único trabajo largo en curso (resolver una lista, exportar un PDF, completar un idioma de diseño o preparar la mesa de juego). |
useActualizacion |
src/stores/actualizacion-store.ts |
ninguna | Máquina de estados de la actualización dentro de la app. |
useEdicion |
src/stores/edicion-store.ts |
ninguna | La carta que se diseña, cuando tiene cambios sin guardar, y cómo guardarla. |
useMesa |
src/stores/mesa-store.ts |
ninguna (la partida vive en Rust) | La vista de la mesa de juego tal como la manda Rust, parcheada en el sitio, y lo que es solo de pantalla: selección, carta bajo el ratón, inspección y registro. |
usePantalla |
src/features/mesa/pantalla.ts |
ninguna | Estado de pantalla de la mesa: el diálogo de la mesa abierto, el modo de elegir objetivo, el arrastre en curso y la zona bajo el ratón. |
useTemasInstalados |
src/lib/temas-instalados.ts |
clave de localStorage proxybuilder.temasInstalados (espejo) |
Temas de tweakcn instalados; véase Temas y skins. |
useIconos |
src/stores/iconos-store.ts |
ninguna (Rust guarda los elegidos en disco) | Datos de los iconos de Iconify que no van incluidos, pedidos por tandas con iconos_datos; véase Iconos. |
useBiblioteca, usePrefsBiblioteca, useFiltrosBiblioteca
|
src/features/library/store.ts, preferencias.ts
|
Rust para los datos; proxybuilder.biblioteca para las preferencias de vista; los filtros no se persisten |
Datos y vista de la biblioteca; véase Biblioteca de mazos. |
useMarcosOriginales, usePacksDescargables
|
src/features/disenar/marcos-originales.ts, packs-descargables.ts
|
ninguna | Estado y progreso de descarga de los packs de marcos descargables; véase Packs de marcos. |
El estado del tema y del idioma no es de Zustand: son contextos de React (ThemeProvider, LanguageProvider) respaldados por localStorage; véanse Temas y skins e Internacionalización.
flowchart LR
UI["Componentes"] -->|"aplicar / setCartas / setAjustes"| DS["useDeck (deck-store)"]
DS -->|"subscribe: cambió version"| AG["iniciarAutoguardado (800 ms)"]
AG -->|"call deck_save"| R["Rust: SQLite + blobs"]
DS -->|"subscribe: cambió cards / settings / defaultBack"| PS["iniciarPlan (100 ms)"]
PS -->|"call compute_page_plan"| R
R -->|"PagePlan"| PL["usePlan"]
PL --> PV["PreviewPane / pie"]
UI -->|"seleccionar, abrir, setZoom"| UIS["useUi"]
UIS -->|"localStorage proxybuilder.preferencias"| LS[("localStorage")]
UI -->|"empezar / avanzar / terminar"| TS["useTrabajo"]
R -->|"eventos resolve:// export://"| LT["lanzarTrabajo (lib/trabajos.ts)"]
LT --> TS
UPD["useActualizacion"] -->|"call update_check / update_download / update_install"| R
UPD -->|"guardarAhora antes de instalar"| DS
DSG["DisenarScreen"] -->|"poner({ guardar }) mientras hay cambios sin guardar"| ED["useEdicion"]
ED -->|"pendiente.guardar()"| DSG
CC["ConfirmarCierre / AppShell"] -->|"pendientes() lee trabajo, paso, edicion"| TS
CC --> UPD
CC --> ED
CC -->|"partida: useMesa.activa"| MS
R -->|"Channel MensajeMesa: Vista / Parche"| MS["useMesa (mesa-store)"]
UI -->|"hacer(accion): call mesa_accion"| R
CC -->|"guardarAhora al cerrar"| DS
Hay dos bucles derivados que se arrancan una sola vez, desde useDeckInicial() (src/features/shell/use-deck-inicial.ts): iniciarAutoguardado() e iniciarPlan(). Ambos se suscriben a useDeck fuera de React y devuelven una función de parada que se usa al desmontar.
Forma: { deck: Deck | null, guardado: EstadoGuardado, errorGuardado, version: number, pasado: Instantanea[], futuro: Instantanea[] } más las acciones.
Deck es el tipo generado (src/bindings/Deck.ts): id, name, decklistText, cards: DeckCard[], settings: PrintSettings, defaultBack, schemaVersion (detalles del modelo en Modelo del mazo).
EstadoGuardado = "saved" | "saving" | "dirty" | "error" (lo pinta src/features/shell/save-indicator.tsx, con las etiquetas «Guardado / Guardando… / Sin guardar / Error al guardar»).
| Acción | Comportamiento |
|---|---|
cargar(deck) |
Sustituye el mazo y restablece guardado: "saved", pasado/futuro: [], version: 0. |
aplicar(cambio) |
La única vía de mutación con historial. cambio(deck) devuelve un Partial<Deck>; la Instantanea anterior (cards, settings, defaultBack) se empuja a pasado (con tope MAX_HISTORIAL = 100), futuro se vacía, guardado = "dirty", version++. |
setCartas(f), setAjustes(f)
|
Envoltorios de conveniencia sobre aplicar para la lista de cartas y para PrintSettings. |
setSinHistorial({ name?, decklistText? }) |
Cambios que se guardan pero no se pueden deshacer (el nombre del mazo, el texto de la lista). Incrementa version, marca como sucio, sin instantánea. |
refrescarCartas(antes, nuevas) |
Para actualizaciones de cartas iniciadas por el sistema que no son ediciones del usuario (miniaturas de diseño vueltas a renderizar, rehacerMiniaturas en src/features/disenar/renumerar.ts). Sustituye solo las cartas cuyo objeto actual sigue siendo la misma referencia que en antes, de modo que una edición del usuario hecha mientras tanto gana. Sin historial; marca como sucio. |
deshacer() / rehacer()
|
Sacan de pasado / de futuro (por delante), intercambiando con la instantánea actual; marcan como sucio. No tocan name ni decklistText. |
_marcarGuardado(estado, error?) |
Interna: la usan el autoguardado y guardarAhora. |
Invariantes:
- Nunca se llama a
deck_savedesde una pantalla. Toda la persistencia pasa poriniciarAutoguardado()(oguardarAhora()justo antes de abandonar el mazo). - Todo cambio debe pasar por
aplicar/setSinHistorial/refrescarCartaspara queversionse incremente; los dos bucles derivados se guían por ella. - El historial guarda referencias a arrays
cardscompletos (compartición estructural), no copias profundas, así que 100 entradas son baratas. Por tanto, las ediciones deben ser inmutables (usa los helpers puros desrc/lib/deck-ops.ts:mover,moverGrupo,duplicar,quitar,insertar,actualizar,huecos).
- Se suscribe a
useDeck; cuandoversioncambió yguardado === "dirty", (re)inicia un temporizador de 800 ms (debounce). - Al dispararse,
guardar()lee{ deck, version }; si ya hay un guardado en vuelo, ponependiente = truey retorna (solo hay undeck_saveen vuelo). - Pone
"saving", haceawait call("deck_save", { deck })y pone"saved"solo siuseDeck.getState().version === version(no llegó ningún cambio durante el guardado); si no,"dirty". - Si falla:
"error", con el error guardado enerrorGuardado(el tooltip del indicador muestramensaje(error)). El reintento ocurre con el siguiente cambio (el suscriptor necesitaguardado === "dirty", que poneaplicar); no hay bucle de reintento automático. - En
finally: sipendienteo el estado es"dirty", programa otra ronda con la versión más reciente.
Helpers relacionados en el mismo fichero:
| Función | Uso |
|---|---|
abrirDeckInicial(nombreNuevo) |
Arranque: lee el ajuste de la app last_deck_id (app_setting_get), intenta deck_open, recurre a deck_create, escribe last_deck_id y luego cargar. Un id obsoleto (mazo borrado) recurre en silencio a un mazo nuevo. |
guardarAhora() |
Vuelca al instante los cambios pendientes (deck_save, y luego "saved" si la versión no se movió). Se usa antes de cambiar de mazo (abrirDeck), antes de cargar la biblioteca (useBiblioteca.cargar), antes de instalar una actualización y en cada petición de cierre de la ventana (ConfirmarCierre, para que no se pierda un cambio hecho dentro de los 800 ms de espera del autoguardado; si falla, pasa a ser una razón para preguntar, véase Ajustes y shell). |
abrirDeck(id) |
guardarAhora() y luego deck_open, recuerda last_deck_id, cargar. |
Los atajos de deshacer (Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z) se registran en useDeckInicial y se saltan los inputs/textareas/contenteditable con foco para que los campos de texto conserven su propio deshacer.
Lado de la persistencia: deck_save es el comando de Rust de src-tauri/src/commands/library.rs que devuelve SaveResult { updatedAt }; el almacenamiento se describe en Almacenamiento y blobs.
Forma: { plan: PagePlan | null, error: unknown, deDeck: Deck | null }. deDeck es el objeto de mazo exacto a partir del cual se calculó el plan, para que los consumidores puedan asociar el índice de una celda con la carta que existía cuando Rust hizo el cálculo.
iniciarPlan(retardoMs = 100):
- Se suscribe a
useDeck. Si el objeto del mazo es el mismo, no hace nada. Si cambió el id del mazo o pasó anull/no nulo, pide el plan de inmediato (programar(true)). En otro caso lo pide tras 100 ms solo sicards,settingsodefaultBackcambiaron por referencia (el nombre y el texto de la lista no afectan a la maquetación). - Un contador creciente
peticionimplementa «gana la última petición»: una respuesta tardía de una petición anterior se descarta. Si hay error, solo se fijaerror; elplananterior sigue visible. - Comando de Rust:
compute_page_plan({ deck })(src-tauri/src/commands/layout.rs); la geometría está en Motor de maquetación. Nada en pantalla recalcula posiciones;PagePlanva en milímetros y la vista previa los multiplica por el zoom (véase Vista previa en vivo).
Dos grupos de campos en un mismo store.
Solo de sesión (no se persisten):
| Campo | Significado |
|---|---|
vista: "deck" | "biblioteca" | "disenar" | "mesa" / setVista
|
Qué vista principal muestra AppShell. |
disenando: string | null / disenar(id)
|
Id de la carta que se está diseñando; disenar(id) también cambia vista a "disenar". |
verReversos: boolean / setVerReversos
|
La vista previa muestra los reversos de las cartas. |
tutorial: Vista | null / abrirTutorial(v)
|
La pantalla cuyo tutorial está abierto. abrirTutorial(v) además añade v a tutorialesVistos (una vez) y guarda; abrirTutorial(null) lo cierra. Véase Tutoriales. |
seleccion: string[], ancla: string | null / seleccionar(ids, ancla?)
|
Ids de las cartas seleccionadas y la última carta pulsada (ancla para los rangos con Shift). |
dialogo: Dialogo | null / abrir(d)
|
El diálogo global abierto, una unión discriminada por tipo: editar, variante, vincular (cada uno con id), vincularLote (ids?, soloSeleccion?), anadir (en? posición de inserción), moverA (ids), fichas, sets, estadisticas, colecciones, recursosDiseno, disenarDeck, exportarPng. |
ultimaAccion: string | null / anunciar(texto)
|
Mensaje del pie («PDF guardado ({n} páginas)»). |
Preferencias (type Preferencias, persistidas):
| Campo | Valor por defecto | Significado |
|---|---|---|
lang |
"en" |
Idioma con el que se piden las impresiones de las cartas (código de idioma de Scryfall: en es fr de it pt ja ko ru zhs zht, la lista IDIOMAS_SCRYFALL de src/lib/idiomas.ts). No es el idioma de la interfaz (ese es proxybuilder.lang, véase Internacionalización). Se envía como ResolveOptions.lang y lo usa el diálogo de añadir carta. |
imagePolicy |
"withImage" |
ImagePolicy = bestAvailable / withImage / highresOnly: qué impresión se elige cuando la lista no indica set. |
addTokens |
false |
Añade las fichas relacionadas al resolver una lista. |
calidadVista |
488 |
Ancho de la miniatura de la vista previa (AnchoMiniatura; el selector ofrece 244 / 488 / 672 / 745). Solo pantalla; el PDF usa siempre la resolución de exportación. |
pedirConfirmacionAlCargar |
true |
Pregunta antes de sustituir las cartas existentes al cargar una lista. |
zoom |
0.8 |
Zoom de la vista previa, limitado a [ZOOM_MIN 0.4, ZOOM_MAX 2.5] y redondeado a 0.01 en setZoom. |
infoCarta |
false |
Muestra insignias de información por carta en la vista previa. |
actualizarSola |
true |
Comprueba/descarga actualizaciones automáticamente (véase Ajustes y shell). |
tutorialesVistos |
[] |
Pantallas (Vista) cuyo tutorial ya ha salido; useTutorialInicial solo abre solo el recorrido de una pantalla que no esté en la lista. Véase Tutoriales. |
mesa |
MESA_DE_FABRICA |
PreferenciasMesa, los ajustes de la mesa de juego (tamaño de las cartas, calidad, vista grande, panel de estado, animaciones, sombras, contador de fotogramas, sonidos de las cartas, del turno y del chat, mantener pulsado para el menú, ofrecer el bono, fantasma, contadores de jugador, movimiento en vivo en red, seguir el turno en una partida local y la disposición de los tableros por número de jugadores). Se cambian con setMesa(parcial); al leerse se funden sobre MESA_DE_FABRICA, así un campo nuevo sale con su valor de fábrica. Véase Mesa de juego. |
Persistencia: leer() mezcla el JSON guardado sobre PREDETERMINADAS, así que añadir una preferencia nueva nunca rompe objetos guardados antiguos; guardar() escribe solo las claves de Preferencias (nunca vista, la selección ni el diálogo) y lo llaman setZoom, setInfoCarta, setPreferencia(k, v), setMesa y abrirTutorial. Ambas están envueltas en try/catch (modo privado, almacenamiento bloqueado): la app simplemente funciona con los valores por defecto durante la sesión. setVerReversos deliberadamente no se persiste.
Protección: src/stores/__tests__/ui-store.test.ts (valores por defecto, mezcla sobre lo guardado, JSON roto, almacenamiento bloqueado, límites del zoom, el conjunto exacto de claves guardadas, un tutorial que se apunta como visto una vez y se recuerda mientras que el abierto no, y los ajustes de la mesa fundidos con los de fábrica).
actual: EstadoTrabajo | null, donde EstadoTrabajo = { tipo: TipoTrabajo, jobId: number | null, fase: string, hechas, total }. Acciones: empezar(tipo, fase), setId(jobId), avanzar(fase, hechas, total), terminar(). Solo un trabajo a la vez: resolver() en src/features/decklist/acciones.ts lanza { code: "Busy" } si actual está fijado; fase ya es texto traducido. El pie del panel izquierdo y el botón de exportar lo leen; TipoTrabajo es "resolver" | "exportar" | "idioma" | "mesa"; "mesa" es preparar una partida (mesa_empezar, mesa_retomar, véase Mesa de juego); "idioma" es el trabajo design_complete_lang que lanza completarIdioma (src/features/disenar/renumerar.ts) cuando el deck pasa a un idioma de diseño que les falta a sus diseños, o antes de exportar PNG en ese idioma (véase Interfaz del diseñador). cancelarTrabajo() (src/features/decklist/acciones.ts) llama a export_cancel con "exportar" y a job_cancel con los demás, con jobId. El jobId es null hasta que lanzarTrabajo retorna (véase Arquitectura del frontend). En el lado de Rust, la guarda equivalente es AppState::ocupado(), que además hace que update_install devuelva Busy, de modo que una actualización nunca mate una exportación de PDF; también es verdadera mientras hay una partida abierta en la mesa.
Otras operaciones largas (identificar en bloque, exportar PNG de diseños, descarga de marcos originales) mantienen su propio estado de progreso local en vez de useTrabajo.
Estado: soportada: boolean | null, actual (versión en ejecución), paso, info: ActualizacionInfo | null, progreso: number | null (0 a 100), error.
stateDiagram-v2
[*] --> inactiva
inactiva --> buscando: buscar()
buscando --> alDia: sin versión más nueva
buscando --> disponible: update_check encontró una
buscando --> inactiva: error (sin info)
disponible --> bajando: bajar()
bajando --> lista: update_download ok
bajando --> disponible: error de descarga
lista --> instalando: instalar()
instalando --> lista: error de instalación (se puede reintentar)
instalando --> [*]: la app se reinicia
(alDia es el valor "al-dia" en el código.)
| Acción | Comportamiento |
|---|---|
iniciar() |
Pregunta a Rust una vez (update_status) si esta compilación puede actualizarse (soportada es false en desarrollo o cuando el binario no vino de un instalador); los errores significan no soportada. |
buscar() |
Se ignora mientras está en buscando/bajando/instalando. Si ya está en lista, devuelve la info descargada (sin volver a descargar hasta el reinicio). Llama a update_check. |
bajar() |
Solo desde disponible. Se suscribe a update://progress ({ hecho, total }, total 0 = tamaño desconocido) para calcular progreso, llama a update_download({ version }) y siempre cancela la suscripción. |
instalar() |
Solo desde lista. con la mesa abierta (useMesa.activa) solo pone alSalirDeLaMesa (la instalación se hace al cerrarse la mesa, desde useAvisosActualizacion); si no, primero guardarAhora() (vuelca el mazo), luego update_install (un Busy motivo: partida también pone alSalirDeLaMesa); si tiene éxito, Rust reinicia la app y la promesa nunca se resuelve; si falla, vuelve a lista y relanza el error para que quien llama muestre un toast. |
El lado de Rust (src-tauri/src/actualizar.rs, src-tauri/src/commands/actualizar.rs) y el pipeline de releases están documentados en Versiones y actualizaciones automáticas; los consumidores de la UI (toasts, botón de la barra, puntito, sección de Ajustes) están en Ajustes y shell.
Estado: pendiente: { guardar: () => Promise<boolean> } | null y la acción poner(p). Es una ranura de registro diminuta, no una copia del borrador: DisenarScreen (la vista Diseñar) pone en ella un callback guardar mientras su borrador tiene cambios sin guardar y lo quita cuando se guardan, se descartan o la pantalla se desmonta (véase Interfaz del diseñador). guardar devuelve false cuando guardar falló; el fallo ya se mostró al usuario, así que quien llama simplemente no continúa.
Por qué un store: lo que puede interrumpir Diseñar (cambiar de vista en AppShell, cerrar la ventana en ConfirmarCierre) vive en otro sitio y debe poder decir «Guardar y continuar» sin saber cómo se guarda una carta (design_save, aplicarlo a las otras copias, anunciar «Diseño guardado»). pendiente !== null es además la señal de que hay algo que perder: lib/cierre.ts lo lee como la razón edicion. Sin persistencia ni historial.
La vista que manda Rust (mesa::vista::VistaMesa), normalizada por clave: cartas (Record<IdCarta, VistaCarta>), zonas (por claveZona(RefZona): "<jugador>:<zona>" o "c:<zona>"), jugadores, asientos (el orden de los asientos), general, y además version, yo, formato, variantes y opciones. Campos solo de pantalla que nunca viajan a Rust: activa (hay una partida abierta y la pantalla está suscrita), registro (los últimos MAX_REGISTRO = 500 eventos, para el registro), seleccion, sobre (la carta bajo el ratón, para la vista grande y los atajos) e inspeccion.
| Acción | Comportamiento |
|---|---|
recibirVista(v, registro?) |
Lo sustituye todo por desdeVista(v); conserva solo la selección y la carta bajo el ratón que sigan existiendo. Con registro (una vista entera por el canal: al suscribirse, deshacer o reiniciar) también sustituye el registro por los eventos que siguen contando; sin él (mesa_vista tras un salto) el registro se queda. |
recibirParche(p, evento) |
conParche(m, p): solo si p.version === version + 1; copia solo los mapas tocados y deja las cartas no tocadas como los mismos objetos (sus componentes memorizados no se repintan). Devuelve false si hay un salto, y entonces conexion.ts pide mesa_vista. Añade el evento a registro y quita las cartas que desaparecen de la selección y de debajo del ratón. |
cerrar() |
Vuelve a MESA_VACIA, activa: false. |
seleccionar, alternar, setSobre, inspeccionar
|
Estado de pantalla. |
Reglas: nunca recalcula lo que decide Rust (quién ve qué, posiciones); los selectores que pueden no devolver nada devuelven el array compartido NINGUNA (un [] nuevo parecería un cambio en cada lectura), y los que construyen una lista usan useShallow. Los helpers cartasDe(m, zona) y cuantasEn(m, zona) leen una zona. La suscripción vive en src/features/mesa/conexion.ts. Protección: src/stores/__tests__/mesa-store.test.ts, con unos datos que escribe el motor (src/stores/__tests__/fixtures/mesa-parches.json). Véase Mesa de juego.
-
useBiblioteca(src/features/library/store.ts):decks,detalles(detalles calculados por mazo),etiquetas; cada acción llama a Rust (deck_tags_set,deck_pin,deck_lang_set,deck_notes_set,deck_cover_set, CRUD de etiquetas) y después vuelve a leer (refrescar).cargar()empieza conguardarAhora()para que la biblioteca nunca muestre datos obsoletos del mazo abierto. Detalles en Biblioteca de mazos. -
usePrefsBiblioteca: vista (cuadricula/lista), orden, dirección, agrupación, tamaño de carta, barra lateral, favoritos primero; se persiste bajoproxybuilder.biblioteca.useFiltrosBiblioteca: filtros, a propósito no recordados. -
usePantalla(src/features/mesa/pantalla.ts): el diálogo de la mesa abierto (DialogoMesa, uno a la vez), el modo de elegir objetivo (adjuntar,flechaonota: atar una nota a la siguiente carta del campo que se pulse), el arrastre en curso (Arrastre, al que sigue la copia arrastrada sin esperar a Rust; mientras lo hay, la vista grande se oculta), la zona bajo el ratón (para que funcionen los atajos de la biblioteca) ytapeteCambiado, un contador que subeavisarTapete()cuando el diálogo del tapete guarda, para que el tablero vuelva a leer el tapete, yredimensionando, verdadero mientras el tablero cambia de tamaño (se apaga 200 ms después del último cambio) para que las cartas salten a su sitio nuevo en vez de deslizarse.pedirNumeroabre el diálogo de pedir un número. -
useChat(src/stores/chat-store.ts): el chat de la mesa solo en esta pantalla:silenciados(jugadores silenciados para mí; el evento sigue viajando),bocadillos(el último mensaje o aviso de cada jugador, duranteBOCADILLO_MS),sinLeer(contador de la pestaña) ylimpiar()al cerrar la mesa.useRepeticion(src/stores/repeticion-store.ts): la repetición en curso (activa:VistaRepeticiononull) y su reproducción (reproduciendo,velocidad); mientras está puesta la mesa es de solo lectura.usePantallaguarda además elpanellateral (registro,chato ninguno) yANCHO_PANEL. -
useMarcosOriginales/usePacksDescargables:info/lista,progresoy un contadorversionque se incrementa tras una descarga correcta para que las listas de packs se vuelvan a pedir.
| Dónde | Clave | Propietario |
|---|---|---|
app_settings de Rust |
last_deck_id |
deck-store.ts (abrirDeckInicial, abrirDeck) |
app_settings de Rust |
carpeta_importar, carpeta_exportar
|
commands/carpetas.rs mediante lib/dialogos.ts
|
localStorage |
proxybuilder.preferencias |
useUi |
localStorage |
proxybuilder.lang |
LanguageProvider |
localStorage |
proxybuilder.theme, .mode, .scale, .skin, .bg, .material, .blur, .noise, .shadow, .fxSidebar, .heraFiligree, .smoothScroll
|
ThemeProvider |
localStorage |
proxybuilder.temasInstalados |
lib/temas-instalados.ts |
localStorage |
proxybuilder.biblioteca |
usePrefsBiblioteca |
localStorage |
proxybuilder.paneles, proxybuilder.panel-lista, proxybuilder.paneles.disenar
|
disposiciones de react-resizable-panels
|
localStorage |
proxybuilder.seccion.<id> |
estado plegado de Seccion
|
localStorage |
proxybuilder.disenar.coleccion |
última colección usada para los borradores de diseño nuevos (features/disenar/use-borrador.ts) |
localStorage |
proxybuilder.mesa.nombre |
el nombre del jugador en la mesa de juego (features/mesa/entrada.tsx) |
app_settings de Rust |
mesa.tapete.<id del deck>, mesa.tapete
|
los tapetes de la mesa de juego (src-tauri/src/mesa/tapete.rs) |
Regla práctica: lo que dependa de un mazo va en el mazo (Rust); lo que sea una comodidad por máquina va en localStorage envuelto en try/catch; lo que Rust necesite recordar entre sesiones (último mazo, últimas carpetas) va en app_settings.
src/stores/__tests__/: deck-store.test.ts (cinco cambios rápidos provocan un solo guardado; deshacer tres veces y rehacer restauran el estado exacto; un guardado fallido deja error y reintenta con el siguiente cambio; los cambios sin historial se guardan pero no se pueden deshacer), deck-store-abrir.test.ts, plan-store.test.ts (primera petición inmediata, debounce, gana la última petición con call simulado), ui-store.test.ts, trabajo-store.test.ts, actualizacion-store.test.ts, mesa-store.test.ts (los parches sobre la primera vista dan la vista final, un salto de versión pide la vista, las cartas no tocadas conservan su identidad, la selección pierde las cartas que desaparecen, una vista con registro lo sustituye y una sin él lo conserva). La guarda de cierre, que lee useTrabajo, useActualizacion, useEdicion y useMesa, se prueba en src/lib/__tests__/cierre.test.ts (véase Tests y CI). Usan temporizadores falsos y simulan @/lib/ipc; localStorage se simula porque Vitest corre en el entorno node.
- Cambio nuevo del mazo que se pueda deshacer: llama a
useDeck.getState().setCartas(...)/setAjustes(...)con un helper puro; no mutes. Si no es una edición del usuario, usarefrescarCartas. - Preferencia nueva: añade la clave a
Preferenciasy aPREDETERMINADAS, y al objeto que se construye enguardar()deui-store.ts; léela conuseUi((s) => s.key). Un ajuste de la mesa de juego va enPreferenciasMesayMESA_DE_FABRICA. - Diálogo global nuevo: añade una variante de
Dialogoy monta el componente ensrc/App.tsx. - Trabajo largo nuevo: usa
lanzarTrabajoy refleja el progreso enuseTrabajosi el pie o el botón de exportar deben mostrarlo.
Use and build · Uso y desarrollo
- User-Guide · Guía de usuario
- Development-Setup · Preparación del entorno de desarrollo
- Testing-and-CI · Tests y CI
- Releases-and-Auto-Updates · Versiones y actualizaciones automáticas
- Conventions · Convenciones
Architecture · Arquitectura
- Architecture · Arquitectura
- IPC-and-Error-Handling · IPC y manejo de errores
- Rust-App-Layer · Capa de aplicación Rust
Data · Datos
- Deck-Model · Modelo del mazo
- Storage-and-Blobs · Almacenamiento y blobs
- Deck-Package-Format · Formato del paquete de mazo
- Deck-Library · Biblioteca de mazos
Getting cards · Conseguir cartas
- Decklist-Parsing · Parseo de la lista del mazo
- Scryfall-Integration · Integración con Scryfall
- External-Sources · Fuentes externas
- Card-Identification-and-OCR · Identificación de cartas y OCR
Layout, images, PDF · Maquetación, imagen y PDF
- Layout-Engine · Motor de maquetación
- Imaging-and-PDF · Imagen y PDF
- Export · Exportación
- Live-Preview · Vista previa en vivo
- Statistics · Estadísticas
Card designer · Diseñador de cartas
- Designer-Overview · Visión general del diseñador
- Designer-Engine · Motor del diseñador
- Designer-Composition · Composición del diseñador
- Frame-Packs · Packs de marcos
- Designer-App-Layer · Capa de aplicación del diseñador
- Designer-UI · Interfaz del diseñador
- Card-Editor-Dialog · Diálogo Editar carta
Game table · Mesa de juego
Frontend · Frontend
- Frontend-Architecture · Arquitectura del frontend
- State-Stores · Stores de estado
- Internationalization · Internacionalización
- Themes-and-Skins · Temas y skins
- Icons · Iconos
- Settings-and-Shell · Ajustes y shell
- Tutorials · Tutoriales
- Decklist-Panel · Panel de la lista del mazo
- Add-Card-and-Variants · Añadir carta y variantes
- Set-Browser · Explorador de sets
Reference · Referencia