Fusionne les 4 pages de création dans le dashboard, retire le titre/BDD
Suite de la demande précédente : les 4 pages autrefois listées dans la barre de navigation n'existent plus en tant que pages séparées — tout vit désormais dans les onglets du tableau de bord (commit précédent) ou, pour la création d'un objet, dans un panneau déplaçable. - screens_list.html + sa route (screens_list) : supprimés (l'onglet "Écrans du jeu" du dashboard couvre déjà tout : créer, réordonner, éditer, supprimer). screen_new/screen_move/screen_delete redirigent maintenant vers le dashboard (tab=screens) au lieu de cette page. - element_types.html : supprimé, mais la route element_types est conservée (GET redirige vers le dashboard, POST — utilisé par la barre de création repliable de l'onglet "Éléments de jeu" — continue de fonctionner). element_type_edit/element_type_delete redirigent aussi vers le dashboard. - game_variables.html + sa route (game_variables) : supprimés (l'onglet "Variables" du dashboard couvre déjà tout). create_global_var/ global_var_edit/global_var_delete redirigent vers le dashboard (tab=variables) au lieu de cette page. - object_form.html : supprimé. La route object_new (POST) est conservée pour traiter la soumission du panneau — voir plus bas — mais ne rend plus de page pour un GET (redirige vers le dashboard). Nouveau panneau déplaçable "Nouvel objet" sur le dashboard (bouton "+ Nouvel objet" de l'onglet Objets) : réutilise .floatPanel/ .floatPanelHeader/.floatPanelBody (déjà utilisées dans l'éditeur d'écran) avec une nouvelle variante centrée (.floatPanel--center) et son propre glisser-déposer minimal (pas de position persistée, contrairement aux panneaux de l'éditeur d'écran — inutile pour un panneau ouvert ponctuellement). Contenu et script (object_form.js) repris tels quels de l'ancienne page. base.html : la barre de navigation du jeu n'a donc plus que 2 liens — "📊 Tableau de bord" (nouveau) et "▶️ Jouer" (toujours en dernier). game_dashboard.html : titre du jeu et chemin de la base de données retirés (redondants avec le nom déjà visible dans l'onglet du navigateur/la barre de nav). Les liens "crée-en un"/"gérer les variables" dans l'éditeur d'écran (screen_edit.html) pointent maintenant vers le dashboard avec le bon onglet (?tab=...), lu et appliqué au chargement de la page (switchDashTab() côté JS). 2 tests (test_screens_and_elements.py) mis à jour : ils vérifiaient le contenu des pages supprimées (element-types, screens) — adaptés pour vérifier la même chose sur le dashboard, qui porte maintenant cette information. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
65450a5719
commit
d875557254
+10
-14
@@ -15,21 +15,17 @@
|
||||
</div>
|
||||
</nav>
|
||||
{% if game is defined and game %}
|
||||
<!-- Barre toujours visible entre les différents éditeurs d'UN MÊME jeu —
|
||||
sans elle, changer d'éditeur (écrans, éléments de jeu, variables,
|
||||
objets) obligeait à repasser par le tableau de bord du jeu à chaque
|
||||
fois. Remplace le fil d'Ariane (retiré, devenu redondant avec elle) :
|
||||
N'apparaît que si la route a mis un `game` dans le contexte du
|
||||
template (déjà fait par toutes les pages d'un jeu) — absente sur
|
||||
l'accueil (liste des jeux), où il n'y a pas de jeu courant. "Jouer"
|
||||
est délibérément le DERNIER lien (les autres sont des éditeurs, celui-
|
||||
ci ouvre l'aperçu jouable dans un nouvel onglet — une action à part,
|
||||
pas un éditeur de plus). -->
|
||||
<!-- Barre toujours visible entre les différentes pages d'UN MÊME jeu.
|
||||
Écrans/Éléments de jeu/Variables/Objets n'ont plus leur propre page —
|
||||
tout ça vit désormais dans les onglets du tableau de bord (voir
|
||||
game_dashboard.html) — donc un seul lien y mène. Remplace le fil
|
||||
d'Ariane (retiré, devenu redondant) : n'apparaît que si la route a mis
|
||||
un `game` dans le contexte du template (déjà fait par toutes les
|
||||
pages d'un jeu) — absente sur l'accueil (liste des jeux). "Jouer" est
|
||||
délibérément le DERNIER lien — une action à part (ouvre l'aperçu
|
||||
jouable dans un nouvel onglet), pas une page de gestion de plus. -->
|
||||
<nav class="gameNavBar" aria-label="Navigation du jeu">
|
||||
<a href="{{ url_for('screens_list', slug=game.slug) }}" class="gameNavLink {{ 'active' if request.path.startswith('/game/' ~ game.slug ~ '/screens') else '' }}" title="Créer et enchaîner les écrans jouables">🖥️ Écrans du jeu</a>
|
||||
<a href="{{ url_for('element_types', slug=game.slug) }}" class="gameNavLink {{ 'active' if request.path.startswith('/game/' ~ game.slug ~ '/element-types') else '' }}" title="Catalogue réutilisable (Personnage, Outil, IA...)">🧩 Éléments de jeu</a>
|
||||
<a href="{{ url_for('game_variables', slug=game.slug) }}" class="gameNavLink {{ 'active' if request.path.startswith('/game/' ~ game.slug ~ '/variables') else '' }}" title="Valeurs globales au jeu entier">🔧 Variables</a>
|
||||
<a href="{{ url_for('object_new', slug=game.slug) }}" class="gameNavLink {{ 'active' if request.path.startswith('/game/' ~ game.slug ~ '/objects') else '' }}" title="Comme une table de base de données : un nom, et des champs typés">🗂️ Objet</a>
|
||||
<a href="{{ url_for('game_dashboard', slug=game.slug) }}" class="gameNavLink {{ 'active' if request.path == '/game/' ~ game.slug else '' }}" title="Écrans, objets, éléments de jeu, variables">📊 Tableau de bord</a>
|
||||
<a href="{{ url_for('game_play', slug=game.slug) }}" target="_blank" class="gameNavLink" title="Aperçu jouable du jeu">▶️ Jouer</a>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Éléments de jeu — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Éléments de jeu</h1>
|
||||
<p class="hint mb-4">Un élément de jeu est un conteneur réutilisable.</p>
|
||||
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Créer</h2>
|
||||
<form method="post" class="card">
|
||||
<div class="fieldRow">
|
||||
<div class="formField" style="flex:0 0 80px;">
|
||||
<label for="icon">Icône</label>
|
||||
<input type="text" id="icon" name="icon" value="🧩" maxlength="4">
|
||||
</div>
|
||||
<div class="formField" style="flex:1;">
|
||||
<label for="name">Nom</label>
|
||||
<input type="text" id="name" name="name" placeholder="ex. Personnage, Outil, Carte mail..." required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formField">
|
||||
<label for="bound_definition_id">Objet lié (optionnel)</label>
|
||||
<select id="bound_definition_id" name="bound_definition_id">
|
||||
<option value="">(aucun — élément décoratif, sans donnée)</option>
|
||||
{% for d in definitions %}
|
||||
<option value="{{ d.id }}">{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">+ Créer</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="colRight">
|
||||
<h2>Catalogue</h2>
|
||||
{% if types %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
<thead><tr><th>Nom</th><th>Usage</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for t in types %}
|
||||
<tr>
|
||||
<td>{{ t.icon }} {{ t.name }}</td>
|
||||
<td class="has-text-grey">
|
||||
{{ usage.get(t.id, 0) }} instance(s)
|
||||
{% if t.bound_definition_id %}
|
||||
{% for d in definitions %}{% if d.id == t.bound_definition_id %} · « {{ d.name }} »{% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="fieldsTableActions">
|
||||
<a class="button is-small" href="{{ url_for('screen_edit', slug=game.slug, screen_id=t.template_screen_id) }}" title="Modifier le contenu de cet élément de jeu">✏️</a>
|
||||
<form method="post" action="{{ url_for('element_type_delete', slug=game.slug, element_type_id=t.id) }}"
|
||||
onsubmit="return confirm('Supprimer l\'élément de jeu « {{ t.name }} » du catalogue (et tout son contenu) ?');">
|
||||
<button type="submit" class="button is-small is-danger" {{ 'disabled title="Utilisé sur un écran — retire-le des écrans d\'abord"' if usage.get(t.id, 0) > 0 else '' }}>🗑️</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Aucun élément de jeu défini pour l'instant.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -2,8 +2,6 @@
|
||||
{% block title %}{{ game.name }} — Forge Engine{% endblock %}
|
||||
{% block content_class %}content-wide{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">{{ game.name }}</h1>
|
||||
<p class="hint mb-3">Base de données : projects/{{ game.slug }}/game.db</p>
|
||||
|
||||
<!-- Une seule fenêtre, un onglet par catégorie (même principe que les
|
||||
onglets "Écran / Logique / Timeline" de l'éditeur d'écran, voir
|
||||
@@ -20,6 +18,11 @@
|
||||
|
||||
<!-- ---------- Écrans ---------- -->
|
||||
<div class="builderTabPanel active" data-tab-panel="screens">
|
||||
{% if request.args.get('blocked_screen') %}
|
||||
<div class="warningBanner">
|
||||
⚠️ Suppression impossible : au moins un autre écran a un bouton qui cible précisément celui-ci. Retire d'abord cette action.
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="dashPanelHeader">
|
||||
<h2>Écrans du jeu</h2>
|
||||
<button type="button" class="button is-small primary" onclick="toggleDashCreate('screens')">+ Créer un écran</button>
|
||||
@@ -63,9 +66,8 @@
|
||||
<div class="builderTabPanel" data-tab-panel="objects">
|
||||
<div class="dashPanelHeader">
|
||||
<h2>Objets</h2>
|
||||
<a class="button is-small primary" href="{{ url_for('object_new', slug=game.slug) }}">+ Nouvel objet</a>
|
||||
<button type="button" class="button is-small primary" onclick="openNewObjectPanel()">+ Nouvel objet</button>
|
||||
</div>
|
||||
<p class="hint mb-2">Un objet a des champs typés (nombre, texte, relation...) — sa création se fait sur sa propre page.</p>
|
||||
{% if definitions %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
@@ -203,6 +205,104 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- ---------- Panneau déplaçable : nouvel objet ---------- -->
|
||||
<!-- Réutilise .floatPanel/.floatPanelHeader/.floatPanelBody (éditeur
|
||||
d'écran, voir style.css) pour la même sensation de fenêtre flottante
|
||||
qu'ailleurs dans l'outil, avec sa propre variante centrée
|
||||
(.floatPanel--center) et son propre glisser-déposer minimal (pas de
|
||||
position persistée en localStorage ici, contrairement aux panneaux de
|
||||
l'éditeur d'écran — inutile pour un panneau ouvert ponctuellement).
|
||||
Contenu repris de l'ancienne page "Définir un nouvel objet"
|
||||
(object_form.html, retirée) : même formulaire, même gabarit de ligne
|
||||
de champ, même script (object_form.js). -->
|
||||
<div class="floatPanel floatPanel--center hidden" id="newObjectPanel">
|
||||
<div class="floatPanelHeader" id="newObjectPanelHeader">
|
||||
<span class="floatPanelTitle">⋮⋮ Nouvel objet</span>
|
||||
<button type="button" class="button is-small" onclick="closeNewObjectPanel()">✕</button>
|
||||
</div>
|
||||
<div class="floatPanelBody">
|
||||
<form method="post" action="{{ url_for('object_new', slug=game.slug) }}" id="objectForm" class="formPassthrough">
|
||||
<div class="formField">
|
||||
<label for="object_name">Nom de l'objet (ex. Personnage, Niveau, Question...)</label>
|
||||
<input type="text" id="object_name" name="object_name" required autocomplete="off">
|
||||
</div>
|
||||
<h2 style="margin-top:16px;">Champs</h2>
|
||||
<button type="button" class="button is-outlined is-fullwidth mb-2" id="btnAddField">+ Ajouter un champ</button>
|
||||
<div id="fieldsList"></div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">Créer l'objet</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template id="fieldRowTemplate">
|
||||
<div class="fieldRowCard box">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Nom du champ</label>
|
||||
<div class="control"><input class="input" type="text" name="field_name[]" placeholder="ex. nom, description, pv..." required></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Type</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_type[]" class="fieldTypeSelect">
|
||||
{% for key, val in field_types.items() %}
|
||||
<option value="{{ key }}">{{ val.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relationTarget field" style="display:none;">
|
||||
<label class="label">Objet lié</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_relation[]">
|
||||
{% for d in definitions %}
|
||||
<option value="{{ d.id }}">{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% if not definitions %}
|
||||
<p class="help">Aucun autre objet défini.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="boundsTarget columns" style="display:none;">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Valeur mini</label>
|
||||
<div class="control"><input class="input" type="number" step="any" name="field_min[]" placeholder="ex. 0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Valeur maxi</label>
|
||||
<div class="control"><input class="input" type="number" step="any" name="field_max[]" placeholder="ex. 100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Obligatoire ?</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_required[]">
|
||||
<option value="0">Non</option>
|
||||
<option value="1">Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="button is-small is-danger btnRemoveField">🗑️ Retirer ce champ</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="{{ url_for('static', filename='object_form.js') }}"></script>
|
||||
<script>
|
||||
function switchDashTab(tab) {
|
||||
document.querySelectorAll('#dashTabs .builderTabBtn').forEach(function (btn) {
|
||||
@@ -220,5 +320,49 @@ function toggleDashCreate(tab) {
|
||||
if (firstInput) firstInput.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Onglet initial : ?tab=... (utilisé par les liens "crée-en un" ailleurs
|
||||
// dans l'outil, ex. l'éditeur d'écran, pour arriver directement sur le bon
|
||||
// onglet plutôt que de laisser deviner où cliquer).
|
||||
(function () {
|
||||
var requestedTab = {{ (request.args.get('tab') or '')|tojson }};
|
||||
if (requestedTab) switchDashTab(requestedTab);
|
||||
})();
|
||||
|
||||
// ---------- Panneau déplaçable "Nouvel objet" ----------
|
||||
(function () {
|
||||
var panel = document.getElementById('newObjectPanel');
|
||||
var header = document.getElementById('newObjectPanelHeader');
|
||||
var dragging = false, offsetX = 0, offsetY = 0;
|
||||
|
||||
window.openNewObjectPanel = function () {
|
||||
panel.classList.remove('hidden');
|
||||
};
|
||||
window.closeNewObjectPanel = function () {
|
||||
panel.classList.add('hidden');
|
||||
};
|
||||
|
||||
header.addEventListener('mousedown', function (e) {
|
||||
if (e.target.closest('button')) return;
|
||||
dragging = true;
|
||||
var rect = panel.getBoundingClientRect();
|
||||
panel.style.left = rect.left + 'px';
|
||||
panel.style.top = rect.top + 'px';
|
||||
panel.style.right = 'auto';
|
||||
panel.style.transform = 'none';
|
||||
offsetX = e.clientX - rect.left;
|
||||
offsetY = e.clientY - rect.top;
|
||||
document.body.style.userSelect = 'none';
|
||||
});
|
||||
document.addEventListener('mousemove', function (e) {
|
||||
if (!dragging) return;
|
||||
panel.style.left = (e.clientX - offsetX) + 'px';
|
||||
panel.style.top = (e.clientY - offsetY) + 'px';
|
||||
});
|
||||
document.addEventListener('mouseup', function () {
|
||||
dragging = false;
|
||||
document.body.style.userSelect = '';
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Variables — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Variables globales</h1>
|
||||
<p class="hint mb-4">Des propriétés/valeurs communes à tout le jeu (pas attachées à un objet de données précis) — utile par exemple pour une porte ouverte ou non, un niveau débloqué... Une variable peut être lue dans une "Condition de visibilité" (propriétés d'un élément) et modifiée par une action "Modifier une variable" (Logique de la scène).</p>
|
||||
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Créer</h2>
|
||||
<form method="post" action="{{ url_for('create_global_var', slug=game.slug) }}" class="card">
|
||||
<div class="formField">
|
||||
<label for="new-var-name">Nom</label>
|
||||
<input type="text" id="new-var-name" name="name" placeholder="ex. porte_ouverte" required autocomplete="off">
|
||||
</div>
|
||||
<div class="formField">
|
||||
<label for="new-var-type">Type</label>
|
||||
<select id="new-var-type" name="type">
|
||||
{% for key, val in variable_types.items() %}
|
||||
<option value="{{ key }}">{{ val.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="formField">
|
||||
<label for="new-var-value">Valeur de départ</label>
|
||||
<input type="text" id="new-var-value" name="default_value" placeholder="ex. 0" autocomplete="off">
|
||||
</div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">+ Créer la variable</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="colRight">
|
||||
<h2>Variables définies</h2>
|
||||
{% if variables %}
|
||||
{% for v in variables %}
|
||||
<form method="post" action="{{ url_for('global_var_edit', slug=game.slug, var_id=v.id) }}" id="varEditForm{{ v.id }}"></form>
|
||||
{% endfor %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
<thead><tr><th>Nom</th><th>Type</th><th>Valeur</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for v in variables %}
|
||||
<tr>
|
||||
<td>{{ v.name }}</td>
|
||||
<td>
|
||||
<select form="varEditForm{{ v.id }}" name="type" aria-label="Type de « {{ v.name }} »">
|
||||
{% for key, val in variable_types.items() %}
|
||||
<option value="{{ key }}" {{ 'selected' if v.type == key else '' }}>{{ val.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" form="varEditForm{{ v.id }}" name="value" value="{{ v.value or '' }}" aria-label="Valeur de « {{ v.name }} »"></td>
|
||||
<td class="fieldsTableActions">
|
||||
<button type="submit" form="varEditForm{{ v.id }}" class="button is-small">Enregistrer</button>
|
||||
<form method="post" action="{{ url_for('global_var_delete', slug=game.slug, var_id=v.id) }}"
|
||||
onsubmit="return confirm('Supprimer la variable « {{ v.name }} » ? Toute condition de visibilité ou action qui la référence cessera de fonctionner.');">
|
||||
<button type="submit" class="button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Aucune variable pour l'instant — crée la première à gauche.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,100 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Nouvel objet — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Définir un nouvel objet</h1>
|
||||
|
||||
<form method="post" id="objectForm" class="formPassthrough">
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Objet</h2>
|
||||
<div class="card">
|
||||
<div class="formField">
|
||||
<label for="object_name">Nom de l'objet (ex. Personnage, Niveau, Question...)</label>
|
||||
<input type="text" id="object_name" name="object_name" required>
|
||||
</div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">Créer l'objet</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="colRight">
|
||||
<h2>Champs</h2>
|
||||
<button type="button" class="button is-outlined is-fullwidth mb-2" id="btnAddField">+ Ajouter un champ</button>
|
||||
<div class="fieldsTableWrap" style="padding:10px;">
|
||||
<div id="fieldsList"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<template id="fieldRowTemplate">
|
||||
<div class="fieldRowCard box">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Nom du champ</label>
|
||||
<div class="control"><input class="input" type="text" name="field_name[]" placeholder="ex. nom, description, pv..." required></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Type</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_type[]" class="fieldTypeSelect">
|
||||
{% for key, val in field_types.items() %}
|
||||
<option value="{{ key }}">{{ val.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relationTarget field" style="display:none;">
|
||||
<label class="label">Objet lié</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_relation[]">
|
||||
{% for d in existing_definitions %}
|
||||
<option value="{{ d.id }}">{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% if not existing_definitions %}
|
||||
<p class="help">Aucun autre objet défini.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="boundsTarget columns" style="display:none;">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Valeur mini</label>
|
||||
<div class="control"><input class="input" type="number" step="any" name="field_min[]" placeholder="ex. 0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label">Valeur maxi</label>
|
||||
<div class="control"><input class="input" type="number" step="any" name="field_max[]" placeholder="ex. 100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Obligatoire ?</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="field_required[]">
|
||||
<option value="0">Non</option>
|
||||
<option value="1">Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="button is-small is-danger btnRemoveField">🗑️ Retirer ce champ</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="{{ url_for('static', filename='object_form.js') }}"></script>
|
||||
{% endblock %}
|
||||
@@ -141,7 +141,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Pas encore d'élément de jeu personnalisé — <a href="{{ url_for('element_types', slug=game.slug) }}">crées-en un</a>.</p>
|
||||
<p class="hint">Pas encore d'élément de jeu personnalisé — <a href="{{ url_for('game_dashboard', slug=game.slug, tab='element_types') }}">crées-en un</a>.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</details>
|
||||
@@ -220,7 +220,7 @@
|
||||
|
||||
<div id="nodeFormCondition" style="display:none;">
|
||||
{% if not definitions %}
|
||||
<p class="hint">Aucun objet défini dans ce jeu pour l'instant — <a href="{{ url_for('object_new', slug=game.slug) }}">crées-en un</a>.</p>
|
||||
<p class="hint">Aucun objet défini dans ce jeu pour l'instant — <a href="{{ url_for('game_dashboard', slug=game.slug, tab='objects') }}">crées-en un</a>.</p>
|
||||
{% else %}
|
||||
<label>Objet<select id="nf-cond-definition" onchange="onFlowDefinitionChange('cond')">
|
||||
{% for d in definitions %}
|
||||
@@ -313,7 +313,7 @@
|
||||
|
||||
<div id="nf-action-data-fields" style="display:none;">
|
||||
{% if not definitions %}
|
||||
<p class="hint">Aucun objet défini dans ce jeu pour l'instant — <a href="{{ url_for('object_new', slug=game.slug) }}">crées-en un</a>.</p>
|
||||
<p class="hint">Aucun objet défini dans ce jeu pour l'instant — <a href="{{ url_for('game_dashboard', slug=game.slug, tab='objects') }}">crées-en un</a>.</p>
|
||||
{% else %}
|
||||
<select id="nf-action-data-definition" onchange="onFlowDefinitionChange('action')">
|
||||
{% for d in definitions %}
|
||||
@@ -712,7 +712,7 @@
|
||||
</select>
|
||||
</div>
|
||||
{% if not global_variables %}
|
||||
<p class="help">Aucune variable globale pour l'instant — <a href="{{ url_for('game_variables', slug=game.slug) }}" target="_blank">crées-en une ↗</a></p>
|
||||
<p class="help">Aucune variable globale pour l'instant — <a href="{{ url_for('game_dashboard', slug=game.slug, tab='variables') }}" target="_blank">crées-en une ↗</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -808,7 +808,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% if c.key == 'visibilite_cond_variable' %}
|
||||
<p class="help">Pas la variable qu'il te faut ? <a href="{{ url_for('game_variables', slug=game.slug) }}" target="_blank">Gérer les variables du jeu ↗</a></p>
|
||||
<p class="help">Pas la variable qu'il te faut ? <a href="{{ url_for('game_dashboard', slug=game.slug, tab='variables') }}" target="_blank">Gérer les variables du jeu ↗</a></p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Écrans — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Écrans du jeu</h1>
|
||||
{% if request.args.get('blocked_screen') %}
|
||||
<div class="warningBanner">
|
||||
⚠️ Suppression impossible : au moins un autre écran a un bouton qui cible précisément celui-ci. Retire d'abord cette action.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Créer</h2>
|
||||
<form method="post" action="{{ url_for('screens_new', slug=game.slug) }}" class="card">
|
||||
<div class="formField">
|
||||
<label for="name">Nom du nouvel écran</label>
|
||||
<input type="text" id="name" name="name" placeholder="ex. Accueil, Formulaire d'inscription, Scène 1..." required>
|
||||
</div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">+ Créer l'écran</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="colRight">
|
||||
<h2>Enchaînement des écrans</h2>
|
||||
{% if screen_list %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
<thead><tr><th>#</th><th>Nom</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for s in screen_list %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('screen_edit', slug=game.slug, screen_id=s.id) }}">{{ s.name }}</a>
|
||||
{% if loop.first %} <span class="tag is-info is-light">★ Départ</span>{% endif %}
|
||||
</td>
|
||||
<td class="fieldsTableActions">
|
||||
<form method="post" action="{{ url_for('screen_move', slug=game.slug, screen_id=s.id) }}"><input type="hidden" name="direction" value="up"><button type="submit" class="button is-small" {{ 'disabled' if loop.first else '' }}>↑</button></form>
|
||||
<form method="post" action="{{ url_for('screen_move', slug=game.slug, screen_id=s.id) }}"><input type="hidden" name="direction" value="down"><button type="submit" class="button is-small" {{ 'disabled' if loop.last else '' }}>↓</button></form>
|
||||
<a class="button is-small" href="{{ url_for('screen_edit', slug=game.slug, screen_id=s.id) }}">✏️</a>
|
||||
<form method="post" action="{{ url_for('screen_delete', slug=game.slug, screen_id=s.id) }}"
|
||||
onsubmit="return confirm('Supprimer l\'écran « {{ s.name }} » et tous ses éléments ?');">
|
||||
<button type="submit" class="button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Aucun écran pour l'instant — crée le premier à gauche.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user