{# Carte d'une présentation Slidia (bibliothèque) — même coque que les cartes Moodia et Scormia, désormais partagée via _organisms/entity-card : liseré d'accent au survol, corps, pied daté, emplacement du menu contextuel. Slidia ne fournit que son contenu. Requiert : presentation, slideCount, sdColor. CONTRAT DU PARTAGE PUBLIC — LIRE AVANT DE TOUCHER AU CONTENEUR : le bouton « Partager » ne vit PAS dans cette carte mais dans le menu contextuel PARTAGÉ de la page (.sd-menu, cf. index.html.twig). shared--share-link#writeBack() retrouve donc la carte par `document.querySelector('.sdl-pres-card[data-uuid="…"]')`, puis y réécrit data-shared / data-share-download / data-share-url et bascule [data-share-badge]. La classe `sdl-pres-card` et ces quatre attributs de données forment un contrat : les renommer casse le partage EN SILENCE. Ces attributs passent par le paramètre `attr` d'entity-card (attributs bruts, jamais des -param Stimulus : un -param JSON-parserait "1"/"0" en nombres et casserait les comparaisons === '1' de list_controller.js#toggleMenu et de share_link_controller.js). #} {% set templateName = presentation.template is not null ? presentation.template.name : 'Sans masque' %} {# ── Métriques du corps de carte, sur le modèle de scormia/_module_card.html.twig ── Scormia annonce « N parties · N écrans » puis une rangée de méta (quiz, réussite, langue). Slidia n'a pas ces dimensions : ses faits vérifiables sont le nombre de slides, les notes d'intervenant, l'ORIGINE de la présentation et le profil de génération. Tous sont lus sur l'entité ou sur `slidesData` — rien n'est inventé. `s.notes|default('')` et non `s.notes` : sous `strict_variables` (activé en test), une clé absente d'un tableau lève une erreur, et `notes` n'existe que sur les slides produites par l'IA. Le filtre `default` est compilé spécialement par Twig et tolère l'accès manquant — c'est son emploi normal. #} {% set slides = presentation.slidesData ?? [] %} {% set notesCount = slides|filter(s => s.notes|default('')|trim is not empty)|length %} {# L'origine se DÉDUIT, elle n'est pas stockée : `sourceHash` n'est renseigné que par l'import de document (SlidiaController::createSubmit), et `brief` que par la saisie. Une présentation sans l'un ni l'autre vient de « Rédiger manuellement ». #} {% set origin = presentation.sourceHash ? { label: 'Depuis un document', icon: 'document' } : (presentation.brief ? { label: 'Depuis un brief', icon: 'magic-stick' } : { label: 'Rédaction manuelle', icon: 'edit' }) %} {# TOUT ce que les blocs ci-dessous utilisent doit figurer dans le `with {}` : l'embed est rendu sous `only`, les blocs ne voient donc QUE ce contexte-là — jamais les variables posées plus haut dans ce fichier. En omettre une lève une RuntimeError sous `strict_variables`, soit un 500 sur la bibliothèque entière. (Et pas de commentaire Twig À L'INTÉRIEUR du `with {}` : le lexer n'y attend qu'une expression, un `{#` y produit une SyntaxError que `lint:twig` signale, mais seulement si on le relance après coup.) #} {% embed '_organisms/entity-card/entity-card.html.twig' with { href: presentation.uuid ? path('app_slidia_editor', {uuid: presentation.uuid}) : '#', accent: sdColor.primary, class: 'sdl-pres-card', attr: { 'data-title': presentation.title|lower, 'data-presentation-id': presentation.id, 'data-template-id': presentation.template ? presentation.template.id : '', 'data-uuid': presentation.uuid, 'data-shared': presentation.isShared ? '1' : '0', 'data-share-download': presentation.isShareDownloadEnabled ? '1' : '0', 'data-share-url': presentation.isShared ? url('app_public_slidia_present', {token: presentation.shareToken}) : '' }, presentation: presentation, slideCount: slideCount, templateName: templateName, notesCount: notesCount, origin: origin } only %} {# Pastille du masque, suivie du tag « Partagé ». Les deux restent à gauche, jamais alignés à droite : le menu ⋯ (absolute top-3 right-3) passerait par-dessus. Le tag est TOUJOURS rendu (pas de {% if %}) : shared--share-link#save()/revoke() bascule son display sans recharger la page — le rendre conditionnellement empêcherait toute activation à chaud. Gris neutre volontaire (variante du badge) : il ne doit pas concurrencer la couleur du masque. #} {% block badge %}