gestion_table_tournante_libre/src/interface/accueil/DossierTravail.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

140 lines
4.4 KiB
Svelte

<!-- © 2026 TechnoLibre (http://www.technolibre.ca)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
<script>
// Le dossier de travail sur la liste (§ 8.6, § 8.8), dans cet ordre : la
// question qui attend sa réponse — elle vient avant toute liste, et nomme
// le dossier, la cause et ce qu'il porte ; la proposition d'importer
// l'autre emplacement, quand le dossier retenu est neuf et vide — son
// compte, puis son chemin dans son propre nœud (data-autre-chemin) —, avec
// la phrase sur les originaux ; les avis de la détermination, non modaux ;
// puis le chemin du dossier, en entier, et la commande qui l'ouvre dans
// l'explorateur, ou, sous web, la phrase qui dit pourquoi elle manque.
//
// issue : la détermination { dossier, avis } de la façade ; racine : le
// dossier de travail de la séance, null tant qu'une question attend ;
// avis : ceux à dire, vides hors du premier accueil de la séance ;
// explorateur : { disponible, raison } de la façade ; repondre(choix) et
// importerDepuisAutre(), les gestes de l'accueil ; reponseEnCours : vrai
// pendant une réponse, qui retire les réponses offertes ; importAutre : les
// comptes du dernier import, ou null ; lignesPresentes : le dossier retenu
// porte déjà des événements, et l'import de l'autre emplacement ne se
// propose plus.
import { getContext } from 'svelte';
import Commande from '../primitives/Commande.svelte';
import { reponsesDe, surLaListe } from './modele.js';
let {
issue,
racine,
avis,
explorateur,
repondre,
reponseEnCours,
importerDepuisAutre,
importAutre,
lignesPresentes,
} = $props();
const t = getContext('t');
const facade = getContext('facade');
const uid = $props.id();
const question = $derived(issue.dossier.question);
const autre = $derived(issue.dossier.autre);
const reponses = $derived(question === null ? [] : reponsesDe(question));
</script>
<section class="dossier" data-dossier>
{#if question !== null}
<div class="question" role="group" data-question={question.code} aria-labelledby={`${uid}-question`}>
<p id={`${uid}-question`}>{t(question.code, question)}</p>
{#if !reponseEnCours}
<div class="reponses">
{#each reponses as { choix, cle } (choix)}
<Commande {cle} executer={() => repondre(choix)} />
{/each}
</div>
{/if}
</div>
{/if}
{#if autre !== null && !lignesPresentes}
<div class="autre" data-autre>
<p>{t('accueil.autre.proposition', { evenements: autre.evenements })}</p>
<p class="donnee" data-autre-chemin>{autre.racine.chemin}</p>
<p>{t('accueil.autre.originaux')}</p>
<Commande cle="accueil.autre.importer" nom="importerAutre" executer={importerDepuisAutre} />
</div>
{/if}
{#if importAutre !== null}
<p class="avis" role="status" data-avertissement="accueil.autre.resultat">{t('accueil.autre.resultat', importAutre)}</p>
{/if}
{#each avis as { code, details }, rang (rang)}
<p class="avis" role="status" data-avertissement={code}>{t(code, details)}</p>
{/each}
{#if question === null && racine !== null}
<div class="chemin">
<h2 id={`${uid}-titre`}>{t('accueil.dossier.titre')}</h2>
<p data-dossier-travail>{racine.chemin}</p>
{#if explorateur.disponible}
<Commande cle="accueil.dossier.explorateur" executer={() => surLaListe(() => facade.ouvrirExplorateur())} />
{:else}
<p class="avis" data-avertissement={explorateur.raison}>{t(explorateur.raison)}</p>
{/if}
</div>
{/if}
</section>
<style>
.dossier {
display: flex;
flex-direction: column;
gap: var(--espace-3);
}
h2,
p {
margin: 0;
}
h2 {
font-size: var(--taille-titre);
}
.question,
.autre {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--espace-2);
padding: var(--espace-3);
border: 2px solid var(--couleur-avis);
border-radius: var(--rayon-2);
}
.reponses {
display: flex;
flex-wrap: wrap;
gap: var(--espace-2);
}
.avis {
padding: var(--espace-1) var(--espace-2);
border-left: 3px solid var(--couleur-avis);
}
.chemin {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: var(--espace-2) var(--espace-3);
}
[data-dossier-travail],
.donnee {
overflow-wrap: anywhere;
}
</style>