gestion_table_tournante_libre/src/interface/plan/PlanDessin.svelte
Mathieu Benoit 134e7850b7 [ADD] interface: event list, open event, participants, import, plan
The working screens of an evening. The home screen lists the events of
the working folder, asks its question, loads demos, copies, renames,
imports and deletes, and shows what the trash holds. An open event frames
its mode, offers Modifier, Débloquer and a confirmed lock takeover, and
shows its warnings. Participants get a grid, a form and a file; an import
goes through a preview and a report; tables, the default and tours have
their screens; the plan draws tables, chairs, empty seats and names.
Checked: 2342 node, 356 browser, 60 node-long; the Electron start check.

--- FR ---

[ADD] interface : liste, événement, participants, import, tables, plan

Les écrans de travail d'une soirée. L'accueil liste les événements du
dossier de travail, pose sa question, charge les démonstrations, copie,
renomme, importe et supprime, et montre ce que tient la corbeille. Un
événement ouvert encadre son mode, offre Modifier, Débloquer et une
reprise de verrou confirmée, et montre ses avertissements. Les
participants ont une grille, un formulaire et une fiche ; un import passe
par un aperçu et un rapport ; tables, défaut et tours ont leurs écrans ;
le plan dessine tables, chaises, sièges vides et noms.
Vérifié : 2342 node, 356 navigateur, 60 node-long ; démarrage d'Electron.

Assisted-by: Claude Opus 5.5
2026-10-07 08:12:27 -04:00

87 lines
3.3 KiB
Svelte

<!-- © 2026 TechnoLibre (http://www.technolibre.ca)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
<svelte:options namespace="svg" />
<script>
// Le dessin du plan (§ 7.1, § 7.3 à § 7.7), enfant du groupe <g data-vue>
// que Plan.svelte transforme : les motifs, les tables — plateaux, chaises,
// poignées, pastilles —, puis les listes de noms, peintes par-dessus et
// transparentes au pointeur. Le composant ne lit k qu'à travers le modèle
// (modele.js), qu'il reçoit entier ; aucun attribut qu'il écrit ne dépend
// de k hors du franchissement d'un seuil — régime des cibles, K_LISTES.
//
// Les mesures du texte se relèvent sur une sonde : un <text> caché au
// style des listes, et un tspan en italique pour les titres. La hauteur
// d'une ligne est la hauteur d'encre du gabarit (mesure_texte.js) ; les
// listes paraissent une fois les mesures prises, et la largeur de leur
// bloc est LARGEUR_BLOC_NOMS_CM du registre. Aucun <canvas>.
//
// Un plan monté caché — un ancêtre en display: none — n'a pas de mise en
// page : ses largeurs mesurées vaudraient 0. Les mesures ne se prennent
// donc que sur une sonde rendue, au montage, puis à chaque changement de
// taille du <svg> qui porte le dessin, qu'un ResizeObserver signale : un
// plan qui se cache perd ses mesures, et ses listes, et les reprend en se
// montrant.
import { untrack } from 'svelte';
import { constante } from '../../geometrie/constantes.js';
import { TAILLE_TEXTE_LISTE_CM } from '../../geometrie/texte.js';
import ListeNoms from './ListeNoms.svelte';
import { creerMesureur, hauteurLigne, mesurable } from './mesure_texte.js';
import Motifs from './Motifs.svelte';
import TablePlan from './TablePlan.svelte';
let { modele } = $props();
const prefixe = $props.id();
const largeur = constante('LARGEUR_BLOC_NOMS_CM');
let sonde = $state(null);
let sondeItalique = $state(null);
let mesures = $state(null);
// Prend les mesures quand la sonde est rendue et qu'il n'y en a pas ; les
// oublie quand elle ne l'est plus.
function actualiserMesures() {
if (!mesurable(sonde)) mesures = null;
else if (mesures === null) {
mesures = { hauteur: hauteurLigne(sonde), mesurer: creerMesureur(sonde), mesurerItalique: creerMesureur(sondeItalique) };
}
}
$effect(() => {
const cible = sonde.ownerSVGElement ?? sonde;
untrack(actualiserMesures);
const observateur = new ResizeObserver(actualiserMesures);
observateur.observe(cible);
return () => observateur.disconnect();
});
</script>
<Motifs {prefixe} />
{#each modele.tables as table (table.id)}
<TablePlan {table} signaler={modele.signalerConflits} {prefixe} />
{/each}
<text class="sonde" font-size={TAILLE_TEXTE_LISTE_CM} aria-hidden="true" bind:this={sonde}
><tspan class="titre" bind:this={sondeItalique}></tspan></text
>
{#if modele.listesRendues && mesures !== null}
{#each modele.tables as table (table.id)}
<ListeNoms {table} {mesures} {largeur} />
{/each}
{/if}
<style>
/* La sonde a le style des listes (ListeNoms.svelte) ; elle ne se voit pas
et ne porte de texte que le temps d'une mesure. */
.sonde {
font-family: var(--police-interface);
white-space: pre;
visibility: hidden;
pointer-events: none;
}
.titre {
font-style: italic;
}
</style>