Ajoute la fonctionnalite quiz autonome/plein ecran a la boite a quiz
Build and deploy / test-python (push) Successful in 12m10s
Build and deploy / test-js (push) Successful in 1m27s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

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:
william
2026-09-13 15:07:23 +02:00
co-authored by Claude Sonnet 5
parent 559331f9cf
commit 7db4803b93
26 changed files with 3173 additions and 60 deletions
+97
View File
@@ -0,0 +1,97 @@
import json
# Réglages "❓ Boîte à quiz" propres au quiz AUTONOME/plein écran (demande
# explicite : "étendre les fonctionnalités de la boîte à quiz pour les RH
# qui veulent juste faire un quiz") — DISTINCT de "🎨 Style"
# (dialogue_box_style.py, partagé avec dialogue_box/score_widget) : ce
# fichier ne gère QUE plein écran/minuteur/modèle, jamais police/couleur.
#
# DEUX catégories de modèles bien distinctes (demande explicite, précisée
# après coup — les 5 premiers modèles construits avant cette précision
# étaient tous de la première catégorie) :
# - "dialog_template" (modèles "boîte de dialogue", visibles SEULEMENT
# quand fullscreen=False) : variantes de forme/couleur/interaction sur
# une structure HTML qui reste globalement la même que "Classique".
# - "page_template" (modèles "page de quiz", visibles SEULEMENT quand
# fullscreen=True) : thème complet et autonome — police, formes,
# couleurs ET structure HTML totalement propres à CHAQUE modèle,
# aucune structure partagée entre eux ni avec les modèles "boîte".
# Les deux réglages sont conservés INDÉPENDAMMENT (jamais écrasés l'un par
# l'autre) : activer/désactiver le plein écran change juste lequel des
# deux s'applique, sans jamais perdre le choix de l'autre.
DEFAULT_QUIZ_BOX_CONFIG = {
"fullscreen": False,
"timer_mode": "aucun",
"timer_seconds": 20,
"dialog_template": "defaut",
"page_template": "classique",
}
# "aucun" : pas de minuteur (réglage par défaut, jamais imposé — demande
# explicite du créateur). "question" : redémarre à chaque question.
# "quiz" : un seul compte à rebours pour l'ensemble du quiz.
TIMER_MODES = ["aucun", "question", "quiz"]
# "defaut" (Classique) = le CSS/HTML déjà existant, AUCUN changement
# visuel pour un quiz non reconfiguré (voir quiz_box_templates.py) —
# "Verre dépoli"/"Néon"/"Minimal"/"Ludique" ont été retirés (demande
# explicite : "supprime tous les modele de boite sauf le base").
# "manga_dialogue" (Manga) : pendant, en petite carte flottante (jamais
# plein écran), du modèle "page de quiz" "Manga" — validé par le créateur
# via une maquette interactive avant intégration (voir
# screens/rendering/quiz_box_templates.py::render_quiz_box_manga_dialogue).
# Clé DIFFÉRENTE du modèle "page" "manga" (registre d'effets JS partagé
# entre les deux catégories, voir static/js/play/quiz-box-templates.js)
# — reste proche de la structure de "Classique" (demande explicite :
# les modèles "boîte" ne changent que forme/couleur/interaction).
QUIZ_BOX_DIALOG_TEMPLATES = ["defaut", "manga_dialogue"]
QUIZ_BOX_DIALOG_TEMPLATE_LABELS = {
"defaut": "Classique",
"manga_dialogue": "Manga",
}
# "classique" (Classique) : modèle de PAGE DE QUIZ de base — sobre/
# professionnel, reprend les couleurs par défaut du modèle "boîte de
# dialogue" de base (demande explicite : "respecte les couleurs du modele
# de boite de base pour le modele de page de base") plutôt que sa propre
# palette, contrairement à "manga" qui est un thème pleinement autonome.
# "manga" : thème/typographie/structure entièrement dédiés, validé par le
# créateur via une maquette interactive avant intégration (voir
# screens/rendering/quiz_box_templates.py::render_quiz_box_page_manga).
QUIZ_BOX_PAGE_TEMPLATES = ["classique", "manga"]
QUIZ_BOX_PAGE_TEMPLATE_LABELS = {
"classique": "Classique",
"manga": "Manga",
}
_MIN_TIMER_SECONDS = 3
_MAX_TIMER_SECONDS = 600
def sanitize_quiz_box_config(raw_config):
config = dict(DEFAULT_QUIZ_BOX_CONFIG)
if not isinstance(raw_config, dict):
return config
config["fullscreen"] = bool(raw_config.get("fullscreen"))
if raw_config.get("timer_mode") in TIMER_MODES:
config["timer_mode"] = raw_config["timer_mode"]
try:
config["timer_seconds"] = max(_MIN_TIMER_SECONDS, min(_MAX_TIMER_SECONDS, int(raw_config.get("timer_seconds"))))
except (TypeError, ValueError):
pass
if raw_config.get("dialog_template") in QUIZ_BOX_DIALOG_TEMPLATES:
config["dialog_template"] = raw_config["dialog_template"]
if raw_config.get("page_template") in QUIZ_BOX_PAGE_TEMPLATES:
config["page_template"] = raw_config["page_template"]
return config
def resolve_quiz_box_config(obj):
raw = (obj.get("attributes") or {}).get("_quiz_box_config")
if not raw:
return dict(DEFAULT_QUIZ_BOX_CONFIG)
try:
parsed = json.loads(raw)
except (TypeError, ValueError):
return dict(DEFAULT_QUIZ_BOX_CONFIG)
return sanitize_quiz_box_config(parsed)