Skip to content

Tutoriales

Claude edited this page Oct 26, 2026 · 3 revisions

Tutoriales

English · Español

Cada una de las cuatro pantallas (Deck, Diseñar, Biblioteca, Jugar) tiene un recorrido guiado corto: oscurece la ventana menos una zona, la rodea y la explica en una tarjeta a su lado, paso a paso. Se abre solo la primera vez que el usuario entra en una pantalla y el botón de ayuda de la barra superior lo repite. Es solo de la pantalla (src/features/tutorial/): ni comandos de Rust, ni red, ni nada guardado en el deck.

Ficheros

Fichero Qué hace
src/features/tutorial/pasos.ts type Paso = { ancla?, titulo, texto } y PASOS: Record<Vista, Paso[]>, los pasos de cada pantalla.
src/features/tutorial/tutorial.tsx Tutorial (montado una vez), su Recorrido interno (la capa y la tarjeta), useTutorialInicial() (la apertura de la primera visita) y las ayudas zona (medir un ancla) y sitioTarjeta (colocar la tarjeta).
src/stores/ui-store.ts tutorial: Vista | null (el recorrido abierto), abrirTutorial(v) y la preferencia guardada tutorialesVistos: Vista[]. Véase Stores de estado.
src/features/shell/app-shell.tsx El botón de ayuda (icono CircleHelp, tooltip «Tutorial de esta pantalla»), <Tutorial /> y la llamada a useTutorialInicial(). Véase Ajustes y shell.
src/i18n/<código>/tutorial.json Las cadenas del recorrido, un área de i18n propia en los 15 idiomas. Véase Internacionalización.
src/index.css [data-slot="tutorial-tarjeta"] comparte la regla de los modales opacos. Véase Temas y skins.

Pasos y anclas

Un paso señala una zona con un ancla: el valor de un atributo data-tutorial en el elemento que se rodea. El recorrido lo busca con document.querySelector('[data-tutorial="…"]'), así que las pantallas no importan nada del tutorial ni el tutorial importa ningún componente de pantalla; mover un panel solo exige que el atributo se mueva con él. Un paso sin ancla (la presentación de cada recorrido) enseña su tarjeta centrada sobre la ventana oscurecida entera. titulo y texto son cadenas fuente en español envueltas en paraTraducir (la tabla vive fuera de React) y traducidas con t() al pintarse.

Pantalla (Vista) Ancla Título Elemento (fichero)
deck ninguna Te damos la bienvenida a Proxy Builder
pestanas Cuatro pantallas el ToggleGroup de vistas (shell/app-shell.tsx)
nombre-deck El nombre del deck el campo NombreDeck (shell/app-shell.tsx)
lista-cuadro La lista de cartas el panel del editor de la lista (decklist/decklist-panel.tsx)
lista-opciones Importar y opciones el panel de opciones (decklist/decklist-panel.tsx)
vista-barra La barra de la vista previa la barra (preview/preview-pane.tsx)
vista-hojas Las hojas la zona de las hojas (preview/preview-pane.tsx)
exportar-boton Exportar la cabecera y el botón de exportar (export/export-panel.tsx)
exportar-ajustes Cómo sale el papel las secciones de ajustes (export/export-panel.tsx)
ajustes Ajustes el botón de Ajustes (shell/app-shell.tsx)
ayuda Para repasar el botón de ayuda (shell/app-shell.tsx)
disenar ninguna Diseñar: el editor de cartas
disenar-lista Las cartas del deck ListaCartas (disenar/lista-cartas.tsx)
disenar-barra Herramientas del deck la barra de arriba (disenar/disenar-screen.tsx)
disenar-vista La vista previa VistaPrevia (disenar/vista-previa.tsx)
disenar-incidencias Avisos Incidencias (disenar/incidencias.tsx)
disenar-formulario Lo que se puede cambiar las Tabs del formulario (disenar/formulario.tsx)
disenar-pie Guardar el pie para guardar (disenar/disenar-screen.tsx)
biblioteca ninguna La biblioteca
biblioteca-barra Buscar y ordenar BarraHerramientas (library/barra-herramientas.tsx)
biblioteca-acciones Nuevo, importar y espacio su hueco de acciones (library/barra-herramientas.tsx)
biblioteca-lateral Etiquetas y favoritos BarraLateral (library/barra-lateral.tsx)
biblioteca-decks Tus decks la zona de los decks (library/library-screen.tsx)
mesa ninguna La mesa de juego
mesa-entrada Elige deck y formato la entrada (mesa/entrada.tsx)
mesa-solitario Solitario el botón «Solitario» (mesa/entrada.tsx)
mesa-barra La barra de la mesa BarraMesa (mesa/barra-mesa.tsx)
mesa-campo El campo la capa del campo (mesa/tablero.tsx)
mesa-mano La mano el rótulo de la mano (mesa/tablero.tsx)
mesa-biblioteca La biblioteca la zona de la biblioteca (mesa/tablero.tsx)
mesa-vida Tu vida VidaJugador (mesa/vida-jugador.tsx)
mesa-tablero Atajos el tablero entero (mesa/tablero.tsx)

Los textos cuentan lo que hace cada zona en la versión actual (por ejemplo los tamaños de carta en «Cómo sale el papel», o que las partidas, las Secuelas y las de doble cara tienen una ilustración por parte en el paso de la vista previa de Diseñar), así que un cambio que altere una zona también debe poner al día su paso.

El recorrido de Jugar mezcla dos pantallas: la entrada (sin partida abierta) y la mesa (con una partida abierta). Solo existen las anclas de la que se ve, así que las demás salen centradas; el recorrido se abre solo la primera vez que se entra en «Jugar», que normalmente es la entrada. Hay más anclas en la mesa para pasos futuros o para reutilizarlas (mesa-lista, el selector de lista para jugar de la entrada, mesa-pila, mesa-fantasma, mesa-pasar, mesa-cementerio, mesa-exilio, mesa-mando, mesa-banquillo). Las piezas de la mesa se describen en Mesa de juego.

La capa (Recorrido)

flowchart LR
  A["useUi().tutorial = vista"] --> B["Tutorial: Recorrido key=vista"]
  B --> C["zona(ancla): getBoundingClientRect"]
  C -->|está, al menos 4 x 4 px| D["anillo + box-shadow oscurece el resto"]
  C -->|no está o no se ve| E["todo oscuro, tarjeta centrada"]
  D --> F["sitioTarjeta: derecha, izquierda, debajo, encima, si no centro"]
  E --> F
Loading
  • Portal en document.body: una capa fixed inset-0 z-[100] (data-tutorial-capa) que tapa la ventana, así que los clics fuera de la tarjeta no hacen nada.
  • Resalte: una caja sin interacción 6 px (AIRE) más grande que la zona, con un anillo del color primario y una sombra negra de 0 0 0 9999px al 60 % que oscurece todo lo demás. Sin zona, una capa negra lisa al 60 %.
  • Tarjeta (data-slot="tutorial-tarjeta", role="dialog", aria-modal, rotulada por su título): 320 px de ancho (ANCHO). sitioTarjeta prueba, por orden, a la derecha de la zona, a la izquierda, debajo y encima, a 14 px (HUECO) y al menos a 16 px de los bordes de la ventana (MARGEN), ajustada en el otro eje; si no cabe en ningún lado, centrada. Su alto se mide tras cada pintado para colocarla con su tamaño real.
  • Volver a medir: en cada cambio de paso, con un ResizeObserver sobre el elemento del ancla y con el evento resize de la ventana, así que al arrastrar los paneles redimensionables o cambiar el tamaño de la ventana el resalte y la tarjeta se mueven con ellos.
  • Ancla que falta: si el elemento no está en el DOM o mide menos de 4 x 4 px (por ejemplo un panel de Diseñar que no se pinta mientras no hay carta elegida), el paso sale igual, centrado.
  • Controles: un contador «Paso {a} de {b}», Anterior (desde el paso 2), Siguiente (Terminar en el último) y una X («Cerrar el tutorial»). El botón principal toma el foco en cada paso, así que Intro avanza.
  • Teclado: un keydown en window en fase de captura atiende Escape (cerrar), flecha derecha (siguiente, o cerrar en el último paso) y flecha izquierda (anterior), y llama a preventDefault + stopPropagation con ellas. Por qué en captura: las pantallas tienen sus propias flechas (Alt+flechas en Diseñar, la selección en las hojas) y no deben reaccionar con el recorrido abierto. Las demás teclas pasan sin tocarse.
  • Tutorial pinta Recorrido con key={vista}, así que abrir el recorrido de otra pantalla empieza en el paso 1.

Cuándo se abre y qué se recuerda

  • abrirTutorial(v) pone tutorial y, si v no es nulo y aún no está en tutorialesVistos, lo añade; luego guarda las preferencias. Por eso un recorrido cuenta como visto en cuanto se abre, aunque el usuario lo cierre en el primer paso: se ofrece una vez, sin insistir. abrirTutorial(null) lo cierra.
  • tutorialesVistos se guarda con las demás preferencias en localStorage["proxybuilder.preferencias"]; el recorrido abierto (tutorial) es solo de la sesión.
  • useTutorialInicial() (lo llama AppShell) vigila useUi().vista. Si esa pantalla no está en tutorialesVistos y no hay un recorrido abierto, espera 700 ms (para que la pantalla esté pintada y sus anclas se puedan medir) y lo abre, pero solo si el usuario sigue en esa pantalla, no se ha abierto otro recorrido entretanto, useUi().dialogo está vacío y no hay ningún [role="dialog"] / [role="alertdialog"] en el DOM. Un recorrido nunca se abre encima de un diálogo; si había uno, se vuelve a ofrecer la próxima vez que el usuario entre en esa pantalla.
  • El botón de ayuda llama a abrirTutorial(vista) con la pantalla actual en cualquier momento.

Ampliarlo

  • Paso nuevo: añadir data-tutorial="<id>" al elemento, añadir un Paso a PASOS[vista] en su sitio y las dos cadenas a tutorial.json en los 15 idiomas (si no, pnpm idiomas falla). Conviene que el ancla esté en un elemento que siempre se pinte en esa pantalla, o aceptar que el paso salga centrado.
  • Pantalla nueva (Vista): PASOS es un Record<Vista, Paso[]>, así que TypeScript exige sus pasos; useTutorialInicial y el botón de ayuda funcionan sin cambios.
  • La tarjeta debe seguir opaca: depende de la regla de modales opacos de src/index.css, que también cubre los diálogos.

Tests

src/stores/__tests__/ui-store.test.ts: abrir un recorrido lo apunta como visto una sola vez y la lista se guarda, mientras que el recorrido abierto no (abrir un tutorial lo apunta como visto (una vez) y se recuerda; el abierto no), y las claves de preferencias guardadas incluyen tutorialesVistos. La capa no tiene test automático (depende de medidas de maquetación que el entorno node de Vitest no tiene).

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