Ajoute la fonctionnalite quiz autonome/plein ecran a la boite a quiz
Introduit la double categorie de modeles (boite de dialogue / page de quiz plein ecran) avec plein ecran, minuteur, score integre et ecran de resultat pour les modeles page ; ajoute les modeles "Manga" (boite et page) et "Classique" (page), pilotables aussi par l'assistant IA Ruby. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
559331f9cf
commit
7db4803b93
+110
-4
@@ -274,9 +274,20 @@
|
||||
|
||||
<div class="builderTabPanel active" data-tab-panel="screen">
|
||||
<div class="canvasFrame">
|
||||
<div class="canvas" id="canvas" style="width:{{ world_width }}px; height:{{ world_height }}px; aspect-ratio:auto; margin:0 auto; position:relative; overflow:hidden; background:#1a1d24;"
|
||||
<!-- Un quiz plein écran fait disparaître la notion de caméra
|
||||
(demande explicite) — pas seulement le cadre "🎥 Champ de la
|
||||
caméra" (déjà masqué plus bas), mais le CANEVAS lui-même :
|
||||
sans ce cas particulier, il restait dimensionné en pixels
|
||||
fixes (world_width/world_height, une notion de caméra/scène
|
||||
nominale) — .canvasElement.isQuizFullscreenPreview a beau
|
||||
remplir 100% de CE canevas, le canevas restait lui-même de la
|
||||
taille de la caméra, laissant une bande vide visible autour.
|
||||
width/height:100% (voir la règle .canvas déjà prévue pour ça
|
||||
dans static/style.css) fait remplir tout .canvasFrame à la
|
||||
place, indépendamment de toute taille de scène/caméra. -->
|
||||
<div class="canvas" id="canvas" style="{{ 'width:100%; height:100%;' if any_quiz_box_fullscreen else 'width:' + world_width|string + 'px; height:' + world_height|string + 'px;' }} aspect-ratio:auto; margin:0 auto; position:relative; overflow:hidden; background:#1a1d24;"
|
||||
ondragover="onCanvasDragOver(event)" ondrop="onCanvasDrop(event)">
|
||||
{% if world_width > screen.scene_width or world_height > screen.scene_height %}
|
||||
{% if not any_quiz_box_fullscreen and (world_width > screen.scene_width or world_height > screen.scene_height) %}
|
||||
<!-- "🎥 Champ de la caméra" : le monde (ce canevas, voir
|
||||
world_width/world_height ci-dessus, routes/scenes/
|
||||
scene_edit_view.py) peut être plus grand que la scène
|
||||
@@ -286,11 +297,14 @@
|
||||
controller.js::forgeUpdateSceneCamera), pour que le monde
|
||||
agrandi reste lisible plutôt qu'une simple étendue grise
|
||||
sans repère. Purement visuel (pointer-events:none) : ne
|
||||
gêne jamais la sélection/le glisser d'un objet dessous. -->
|
||||
gêne jamais la sélection/le glisser d'un objet dessous.
|
||||
Masqué dès qu'un quiz PLEIN ÉCRAN existe sur cet écran
|
||||
(demande explicite : "la notion de caméra disparaît") —
|
||||
il n'a plus aucun sens une fois que ce widget couvre tout. -->
|
||||
<div class="sceneCameraFrame" style="width:{{ screen.scene_width }}px; height:{{ screen.scene_height }}px;" title="Champ de la caméra en jeu ({{ screen.scene_width }}×{{ screen.scene_height }} px)"></div>
|
||||
{% endif %}
|
||||
{% for o in objects %}
|
||||
<div class="canvasElement {{ 'selected' if o.id == selected_id else '' }}" id="el-{{ o.id }}"
|
||||
<div class="canvasElement {{ 'selected' if o.id == selected_id else '' }} {{ 'isQuizFullscreenPreview' if o.quiz_fullscreen else '' }}" id="el-{{ o.id }}"
|
||||
style="position:absolute; left:{{ o.x }}px; top:{{ o.y }}px; width:{{ o.width }}px; height:{{ o.height }}px;"
|
||||
onmousedown="onSceneObjectMouseDown(event, {{ o.id }})">
|
||||
<div class="canvasElementInner">{{ o.rendered_html|safe }}</div>
|
||||
@@ -562,6 +576,98 @@
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
{% if obj.kind == 'quiz_box' %}
|
||||
<!-- "⚙️ Options du quiz" (demande explicite : "étendre les
|
||||
fonctionnalités de la boîte à quiz pour les RH qui veulent
|
||||
juste faire un quiz") — voir screens/rendering/quiz_box_config.py,
|
||||
routes/scenes/scene_object_quiz_config.py. Plein écran/minuteur,
|
||||
DISTINCT de "🎨 Style" ci-dessus (couleurs/police, partagé avec
|
||||
dialogue_box/score_widget). -->
|
||||
<details class="propGroup" open>
|
||||
<summary>Options du quiz</summary>
|
||||
<div class="propGroupBody">
|
||||
<label class="checkbox is-small">
|
||||
<input type="checkbox" id="quiz-fullscreen" data-was-checked="{{ '1' if quiz_box_config.fullscreen else '0' }}" {{ 'checked' if quiz_box_config.fullscreen else '' }} onchange="saveQuizBoxConfig({{ obj.id }})">
|
||||
Plein écran
|
||||
</label>
|
||||
<div class="field mt-2">
|
||||
<label class="label is-small">Minuteur</label>
|
||||
<div class="control">
|
||||
<select class="input is-small" id="quiz-timer-mode" onchange="saveQuizBoxConfig({{ obj.id }})">
|
||||
{% for mode in quiz_box_timer_modes %}
|
||||
<option value="{{ mode }}" {{ 'selected' if quiz_box_config.timer_mode == mode else '' }}>
|
||||
{{ {'aucun': 'Aucun', 'question': 'Par question', 'quiz': 'Pour tout le quiz'}[mode] }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label is-small">Durée (secondes)</label>
|
||||
<div class="control">
|
||||
<input class="input is-small" type="number" id="quiz-timer-seconds" min="3" max="600" value="{{ quiz_box_config.timer_seconds }}" onchange="saveQuizBoxConfig({{ obj.id }})">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">Le plein écran et le minuteur ne s'appliquent qu'au jeu (jamais dans cet éditeur).</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- "🖼️ Modèles" — DEUX catégories bien distinctes (demande
|
||||
explicite), une SEULE des deux visible/modifiable à la fois
|
||||
selon "Plein écran" ci-dessus (les deux valeurs restent
|
||||
conservées indépendamment, voir screens/rendering/
|
||||
quiz_box_config.py) :
|
||||
- "boîte de dialogue" (hors plein écran) : variantes de forme/
|
||||
couleur sur une structure proche de "Classique" ;
|
||||
- "page de quiz" (plein écran) : thème complet et autonome,
|
||||
structure HTML propre à CHAQUE modèle (voir
|
||||
screens/rendering/quiz_box_templates.py,
|
||||
render_quiz_box_page_manga pour le premier).
|
||||
Ce <div> caché retient la valeur de CELUI des deux réglages
|
||||
qui n'a pas de galerie affichée ici, pour que saveQuizBoxConfig
|
||||
(scene-editor.js) ne l'écrase jamais par erreur en l'absence de
|
||||
sa grille. -->
|
||||
<div id="quizBoxTemplateMeta" data-dialog-template="{{ quiz_box_config.dialog_template }}" data-page-template="{{ quiz_box_config.page_template }}" style="display:none;"></div>
|
||||
|
||||
{% if quiz_box_config.fullscreen %}
|
||||
<details class="propGroup" open>
|
||||
<summary>Modèles — page de quiz</summary>
|
||||
<div class="propGroupBody">
|
||||
<p class="help mb-2">Visibles seulement en plein écran — un thème complet et autonome par modèle (police, formes, couleurs et structure propres à chacun).</p>
|
||||
<div class="quizTemplateGrid" id="quizPageTemplateGrid" data-object-id="{{ obj.id }}">
|
||||
{% for key in quiz_box_page_templates %}
|
||||
<button type="button" class="quizTemplateTile {{ 'is-selected' if quiz_box_config.page_template == key else '' }}"
|
||||
data-template="{{ key }}" onclick="selectQuizBoxPageTemplate({{ obj.id }}, '{{ key }}')">
|
||||
<span class="quizTemplatePreviewImg">
|
||||
<img src="{{ url_for('static', filename='quiz-templates/' + key + '.png') }}" alt="Aperçu du modèle « {{ quiz_box_page_template_labels[key] }} »" loading="lazy">
|
||||
</span>
|
||||
<span class="quizTemplateName">{{ quiz_box_page_template_labels[key] }}</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% else %}
|
||||
<details class="propGroup" open>
|
||||
<summary>Modèles — boîte de dialogue</summary>
|
||||
<div class="propGroupBody">
|
||||
<p class="help mb-2">Visibles seulement hors plein écran — un thème complet et autonome par modèle (police, formes, couleurs et structure propres à chacun).</p>
|
||||
<div class="quizTemplateGrid" id="quizDialogTemplateGrid" data-object-id="{{ obj.id }}">
|
||||
{% for key in quiz_box_dialog_templates %}
|
||||
<button type="button" class="quizTemplateTile {{ 'is-selected' if quiz_box_config.dialog_template == key else '' }}"
|
||||
data-template="{{ key }}" onclick="selectQuizBoxDialogTemplate({{ obj.id }}, '{{ key }}')">
|
||||
<span class="quizTemplatePreviewImg">
|
||||
<img src="{{ url_for('static', filename='quiz-templates/' + key + '.png') }}" alt="Aperçu du modèle « {{ quiz_box_dialog_template_labels[key] }} »" loading="lazy">
|
||||
</span>
|
||||
<span class="quizTemplateName">{{ quiz_box_dialog_template_labels[key] }}</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if obj.kind not in ('fond', 'dialogue_box', 'quiz_box', 'score_widget') %}
|
||||
<!-- Boîte de collision (voir screens/rendering/collision_settings.py,
|
||||
static/js/play/conditions.js::elementsOverlap) : posée AUTOMATIQUEMENT
|
||||
|
||||
Reference in New Issue
Block a user