{# # PAGE: SCORMIA — BIBLIOTHÈQUE DE MODULES SCORM # Liste des modules de l'utilisateur : créer, ouvrir, renommer, dupliquer, supprimer. # La création se fait sur une page dédiée (app_scormia_new). # DONNÉES REQUISES (ScormiaController::index) : modules #} {% extends 'base.html.twig' %} {% block title %}Scormia — Modules SCORM{% endblock %} {% block body %} {% set scColor = tool_color_details['scormia'] %}
{# En-tête (pattern Moodia : icône produit + titre + action) #}
{% include '_atoms/icon/icon.html.twig' with { name: 'bubul-scormia', size: '3xl', colorPrimary: 'current', colorSecondary: 'current' } only %}

Scormia

{% if 'scormia' in new_tool_codes|default([]) %} {% include '_atoms/badge/badge.html.twig' with { label: 'BETA', variant: 'warning', customColor: scColor.primary, size: 'sm' } only %} {% endif %}

Créez des modules e-learning SCORM interactifs, à votre image.

{# Coût médian d'un module. Markup repris à l'identique de `_organisms/tool-header`, que Moodia et Slidia consomment : le jour où cet en-tête adoptera l'organisme, la ligne disparaîtra sans rien changer à l'écran. Masquée tant qu'aucune génération n'a eu lieu — annoncer « ~0 tokens » serait faux. #} {% if medianTokenCost|default(0) > 0 %} {% endif %}
{# Même design que le bouton Moodia « Créer un cours » (atom button), aux couleurs Scormia. #}
{% include '_atoms/button/button.html.twig' with { label: 'Créer un module', variant: 'custom-gradient', gradientFrom: scColor.primary, gradientTo: scColor.secondary, size: 'lg', icon: 'plus', iconSize: 'lg', href: path('app_scormia_new'), radius: 'lg', class: 'flex-shrink-0' } only %}
{# totalGlobal, et non typeStats.all : ce dernier est conditionné au partage ET à la recherche. L'utilisateur qui a des modules mais aucun de partagé — ou dont la recherche ne ramène rien — ne doit pas se voir proposer de « créer son premier module ». C'est une autre question : a-t-il déjà créé quelque chose, un jour ? #} {% if totalGlobal == 0 and not activeJob %}
{% include '_atoms/icon/icon.html.twig' with { name: 'bubul-scormia', size: '2xl', colorPrimary: 'current', colorSecondary: 'current' } only %}

Créez votre premier module

À la main, depuis un PDF ou un simple sujet — l'IA génère un module complet, puis vous l'affinez à votre image.

{% include '_atoms/button/button.html.twig' with { label: 'Créer un module', variant: 'custom-gradient', gradientFrom: scColor.primary, gradientTo: scColor.secondary, size: 'lg', icon: 'plus', iconSize: 'lg', href: path('app_scormia_new'), radius: 'lg' } only %}
{% else %} {# Filtres par type (façon Moodia, aux couleurs de l'outil) + recherche, sur une même ligne. items-stretch : la recherche prend EXACTEMENT la hauteur des tabs (h-full), quel que soit le padding interne de la molécule. #} {# Paramètres à propager d'un contrôle à l'autre. Le type et le partage sont ORTHOGONAUX : chaque contrôle ne réécrit QUE sa propre dimension et reconduit les autres — c'est ce qui permet de demander « les modules avec quiz partagés », et ce qui conserve la recherche en cours quand on touche à l'un ou à l'autre. #} {% set qp = search is not empty ? {'q': search} : {} %} {% set sharedParam = sharedOnly ? {'shared': '1'} : {} %} {% set typeParam = typeFilter != 'all' ? {'type': typeFilter} : {} %}
{# Onglets de TYPE : trois valeurs mutuellement exclusives. Leurs liens reconduisent l'état du partage (sharedParam) au lieu de l'écraser. #} {% include '_molecules/filter-tabs/filter-tabs.html.twig' with { filters: [ { id: 'all', label: 'Tous', count: typeStats.all, href: path('app_scormia', qp|merge(sharedParam)) }, { id: 'quiz', label: 'Module + Quiz', count: typeStats.quiz, href: path('app_scormia', qp|merge(sharedParam)|merge({type: 'quiz'})) }, { id: 'noquiz', label: 'Module SCORM', count: typeStats.noquiz, href: path('app_scormia', qp|merge(sharedParam)|merge({type: 'noquiz'})) } ], active: typeFilter, name: 'moduleType' } only %}
{# Contrôle « Partagés » : INDÉPENDANT des onglets, à côté d'eux et non dedans. Même molécule (donc mêmes pilule, ombre et état actif que la barre), mais dans son propre groupe : la barre de type garde ainsi un et un seul onglet actif, et le JS peut lire les deux dimensions séparément. Bascule : le lien reconduit le type courant et ajoute — ou retire — le partage. Cliquer dessus quand il est actif le désactive. `active` vaut '' et non null quand le filtre est inactif : la molécule remplace un `active` null par l'id du PREMIER filtre — le contrôle se serait affiché actif en permanence. #}
{% include '_molecules/filter-tabs/filter-tabs.html.twig' with { filters: [ { id: 'shared', label: 'Partagés', icon: 'share', count: typeStats.shared, href: path('app_scormia', qp|merge(typeParam)|merge(sharedOnly ? {} : {'shared': '1'})), attr: { 'data-share-filter': sharedOnly ? '1' : '0', 'title': sharedOnly ? 'Retirer le filtre « Partagés »' : 'N\'afficher que les modules partagés' } } ], active: sharedOnly ? 'shared' : '', name: 'shareState' } only %}
{% include '_atoms/icon/icon.html.twig' with { name: 'search', size: 'sm', color: 'current' } only %} {# data-turbo-permanent : le champ garde le focus/valeur pendant la frappe malgré les visites Turbo. #}
{# Génération IA en cours : carte au FORMAT module + animation de chargement. Sondée en JS (jobCard/jobStep/jobBar) ; la page est rechargée à la fin. #} {% if activeJob %}
{# Barre de progression = bordure supérieure animée (accent Scormia) #}
Génération…
{# Titre réel du module en cours #}

{{ activeJob.title }}

{# Étape en cours (mise à jour en JS) #}

{{ activeJob.step ?: 'Génération en cours…' }}

{# Métadonnées à venir (parties/écrans, quiz…) → skeleton pulsant #}
{% include '_atoms/skeleton/skeleton.html.twig' with { variant: 'text', width: '1/2' } only %} {% include '_atoms/skeleton/skeleton.html.twig' with { variant: 'text', width: '2/3' } only %}
{# Footer (date + conso à venir) → skeleton, même gabarit que la carte module #}
{% include '_atoms/skeleton/skeleton.html.twig' with { variant: 'text', width: '1/3' } only %} {% include '_atoms/skeleton/skeleton.html.twig' with { variant: 'text', width: '1/4' } only %}
{% endif %} {% for module in modules %} {% include 'scormia/_module_card.html.twig' with { module: module, scColor: scColor } only %} {% endfor %}
{# Aucun résultat (recherche ou catégorie vide) — rendu côté serveur, sur l'ensemble des modules. #} {% if modules is empty and not activeJob %}

{# Les filtres se COMBINANT, le message doit se combiner aussi : sous « Partagés », dire « aucun module ne correspond à votre recherche » serait faux dès qu'il en existe qui correspondent mais ne sont pas partagés — l'utilisateur chercherait la mauvaise cause. #} {% if search is not empty %} Aucun module {{ sharedOnly ? 'partagé ' : '' }}ne correspond à votre recherche. {% elseif sharedOnly %} Aucun module partagé{{ typeFilter != 'all' ? ' dans cette catégorie' : '' }} pour le moment. {% else %} Aucun module dans cette catégorie. {% endif %}

{% endif %} {% if totalPages > 1 %} {# Style pagination Moodia, recoloré aux couleurs de l'outil (issues de la DB) via les variables CSS + l'ombre. #}
{# baseUrl : les DEUX filtres doivent voyager avec la page. Sans `shared`, la page 2 retomberait sur une liste simplement typée — et la pagination, calculée sur l'intersection, pointerait à côté. #} {% include '_molecules/pagination/pagination.html.twig' with { currentPage: currentPage, totalPages: totalPages, baseUrl: path('app_scormia', qp|merge(typeParam)|merge(sharedParam)), variant: 'moodia' } only %}
{% endif %} {% endif %} {# ===== Modal : renommer un module (organisme partagé, bouton aux couleurs de l'outil) ===== #} {% include '_organisms/rename-modal/rename-modal.html.twig' with { title: 'Renommer le module', placeholder: 'Titre du module...', confirmLabel: 'Enregistrer', color: scColor, modalAttr: {'data-scormia--library-target': 'renameModal', 'data-action': 'keydown.esc@window->scormia--library#closeRenameModal'}, inputAttr: {'data-scormia--library-target': 'renameInput', 'data-action': 'keydown.enter->scormia--library#confirmRename'}, cancelAttr: {'data-action': 'click->scormia--library#closeRenameModal'}, confirmAttr: {'data-action': 'click->scormia--library#confirmRename'} } only %} {# ===== Modal : confirmation de suppression (organisme partagé, façon Moodia) ===== #} {% embed '_organisms/delete-modal/delete-modal.html.twig' with { modalAttr: {'data-scormia--library-target': 'deleteModal', 'data-action': 'keydown.esc@window->scormia--library#closeDeleteModal'}, cancelAttr: {'data-action': 'click->scormia--library#closeDeleteModal'}, confirmAttr: {'data-action': 'click->scormia--library#confirmDelete'} } only %} {% block titleBlock %}

Supprimer « » ?

{% endblock %} {% block description %}

Cette action est irréversible. Le module et tous ses écrans, blocs et médias seront supprimés définitivement.

{% endblock %} {% endembed %} {# ===== Modal : ajouter un module dans un cours Moodia (sélecteur partagé) ===== #} {% include '_molecules/add-to-moodia/add-to-moodia.html.twig' with { submitLabel: 'Ajouter ici', submitIcon: 'scormia', sourceIcon: 'bubul-scormia', sourceLabel: 'Module SCORM', sourceColorPrimary: 'current', sourceColorBg: scColor.bg, } only %} {# ===== Modal : partage public (molécule partagée avec Slidia) ===== #} {% include '_molecules/share-link/share-link-modal.html.twig' with { endpoint: path('app_scormia_share_update', {uuid: '__UUID__'})|replace({'__UUID__': '{uuid}'}), accentHex: tool_color_details['scormia'].primary } only %}
{% endblock %}