gestion_table_tournante_libre/src/interface/plan/Infobulle.svelte
Mathieu Benoit 811cd16b76 [ADD] interface: plan keyboard, tooltip, side panels, person menu, lists
Every gesture the pointer offers on the plan is reachable from the
keyboard (§ 7.3): one stop enters the plan, arrows move between tables and
seats, and the table and place panels choose a seat and keep the focus.
A tooltip names who sits where; a per-person menu moves, assigns or
reserves without dragging; the reserve and the work lists choose a person
to designate on the plan. Escape, a tour change and the executed command
forget the choice, and a click never moves the view.
Checked: 2537 node, 466 browser (one expected failure kept), 60 node-long.

--- FR ---

[ADD] interface : clavier du plan, infobulle, panneaux, menu, listes

Chaque geste que le pointeur offre sur le plan s'atteint au clavier
(§ 7.3) : un seul arrêt entre dans le plan, les flèches vont de table en
table et de siège en siège, et les panneaux de table et de place
choisissent un siège en gardant le focus. Une infobulle nomme qui est
assis où ; un menu par personne déplace, assigne ou réserve sans glisser ;
la réserve et les listes de travail choisissent une personne à désigner
sur le plan. Échap, un changement de tour et la commande exécutée
oublient le choix, et un clic ne déplace jamais la vue.
Vérifié : 2537 node, 466 navigateur (un échec attendu gardé), 60 node-long.

Assisted-by: Claude Opus 5.5
2026-10-07 11:08:59 -04:00

74 lines
2.3 KiB
Svelte

<!-- © 2026 TechnoLibre (http://www.technolibre.ca)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
<script>
// L'infobulle du plan (§ 7.1, § 7.3) : un seul élément [role=tooltip],
// toujours présent dans la surface du plan, hors du <svg data-plan>, caché
// tant qu'aucune table en conflit n'est désignée. Plan.svelte l'ouvre par
// trois déclencheurs — le survol, le focus du clavier, la pression longue —
// et lui passe le détail des conflits (detailConflits, modele.js) et sa
// position dans la surface, en px. Elle énonce la table et son nombre de
// violations, puis chaque règle violée et ses groupes : chaque nom occupe
// son propre nœud, relié à l'autre nom d'une paire par « et », séparé du
// groupe suivant.
//
// infobulle : null, ou {detail, x, y} ; id : l'identifiant que la racine
// du plan désigne par aria-describedby quand l'infobulle s'ouvre par le
// focus.
import { getContext } from 'svelte';
let { infobulle, id } = $props();
const t = getContext('t');
</script>
<div
class="infobulle"
role="tooltip"
{id}
hidden={infobulle === null}
style:left={infobulle === null ? null : `${infobulle.x}px`}
style:top={infobulle === null ? null : `${infobulle.y}px`}
>
{#if infobulle !== null}
<p class="entete">{t('plan.infobulle.entete', { numero: infobulle.detail.numero, nombre: infobulle.detail.nombre })}</p>
{#each infobulle.detail.regles as regle, rang (rang)}
<p>
<span>{t(regle.cle)}</span>{#each regle.groupes as groupe, g (g)}{#if g > 0}<span
>{t('plan.infobulle.separateur')}</span
>{/if}{#each groupe as nom, n (n)}{#if n > 0}<span>{t('plan.infobulle.et')}</span>{/if}<span class="donnee"
>{nom}</span
>{/each}{/each}
</p>
{/each}
{/if}
</div>
<style>
.infobulle {
position: absolute;
z-index: 2;
box-sizing: border-box;
max-width: 24rem;
padding: var(--espace-2);
border: 1px solid var(--couleur-page-filet);
border-radius: var(--rayon-1);
background: var(--couleur-page-fond);
color: var(--couleur-page-texte);
box-shadow: var(--ombre-1);
font-size: var(--taille-texte);
pointer-events: none;
}
.infobulle[hidden] {
display: none;
}
p {
margin: 0;
}
.entete {
font-weight: 700;
}
</style>