Dev #1
+12
-49
@@ -33,23 +33,11 @@ button{ background:var(--panel2); border:1px solid var(--border); color:var(--te
|
||||
button.primary{ background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600; }
|
||||
button.smallBtn{ padding:5px 10px; font-size:11.5px; }
|
||||
button.danger{ color:var(--danger); border-color:rgba(226,104,95,.4); }
|
||||
.addBtn{ display:inline-block; margin:10px 0; padding:9px 14px; border-radius:6px; border:1px dashed var(--border); color:var(--accent); text-decoration:none; font-size:13px; }
|
||||
.actionsRow{ margin-top:16px; }
|
||||
|
||||
.list{ display:flex; flex-direction:column; gap:4px; }
|
||||
.listRow{ display:block; padding:7px 10px; border:1px solid var(--border); border-radius:6px; background:var(--panel); text-decoration:none; color:var(--text); }
|
||||
.listRow:hover{ background:var(--panel2); }
|
||||
.listRowFlex{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
|
||||
.listRowFlex .rowLink{ flex:1; text-decoration:none; color:var(--text); }
|
||||
.listRowFlex form{ margin:0; }
|
||||
.rowTitle{ font-size:13px; }
|
||||
.rowSub{ font-size:10.5px; color:var(--text-dim); margin-top:1px; }
|
||||
.rowActions{ display:flex; gap:6px; align-items:center; }
|
||||
|
||||
/* Nav compacte à une seule ligne (icône + libellé) — pour une liste
|
||||
d'actions fixe (ex. tableau de bord d'un jeu) où le sous-titre de
|
||||
.listRow prendrait trop de place utile pour rien : sobre et dense plutôt
|
||||
que "carte" explicative. */
|
||||
d'actions fixe (ex. colonne "Créer" du tableau de bord d'un jeu) : sobre
|
||||
et dense plutôt qu'une carte à deux lignes. */
|
||||
.navList{ display:flex; flex-direction:column; gap:3px; }
|
||||
.navRow{ display:flex; align-items:center; gap:8px; padding:7px 10px; border:1px solid var(--border); border-radius:6px; background:var(--panel); text-decoration:none; color:var(--text); font-size:12.5px; }
|
||||
.navRow:hover{ background:var(--panel2); border-color:var(--accent); }
|
||||
@@ -112,7 +100,16 @@ body.objectEditBody > .topbar, body.objectEditBody > .breadcrumbBar{ flex:0 0 au
|
||||
body.objectEditBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; display:flex; flex-direction:column; }
|
||||
|
||||
.content-objectEdit{ width:100%; display:flex; flex-direction:column; min-height:0; }
|
||||
.content-objectEdit > h1, .content-objectEdit > .hint, .content-objectEdit > form{ flex:0 0 auto; }
|
||||
.content-objectEdit > h1, .content-objectEdit > .hint, .content-objectEdit > form, .content-objectEdit > .warningBanner{ flex:0 0 auto; }
|
||||
|
||||
/* Un <form> qui doit envelopper les DEUX colonnes à la fois (un seul
|
||||
formulaire soumis ensemble, ex. object_form.html : nom de l'objet à
|
||||
gauche, liste de champs à droite) ne doit pas devenir lui-même une boîte
|
||||
dans la mise en page flex — sinon .twoCol à l'intérieur perd la hauteur
|
||||
disponible qu'il doit occuper. "display:contents" le rend transparent :
|
||||
.twoCol se comporte comme s'il était directement enfant de
|
||||
.content-objectEdit. */
|
||||
.formPassthrough{ display:contents; }
|
||||
.content-objectEdit .twoCol{ flex:1 1 auto; min-height:0; align-items:stretch; }
|
||||
.content-objectEdit .colLeft{ overflow-y:auto; height:100%; }
|
||||
.content-objectEdit .colRight{ display:flex; flex-direction:column; min-height:0; height:100%; }
|
||||
@@ -128,40 +125,6 @@ body.objectEditBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden
|
||||
.fieldsTable td input, .fieldsTable td select{ min-width:120px; width:auto; }
|
||||
.fieldsTableActions{ display:flex; gap:6px; }
|
||||
|
||||
/* ---------- Gabarit générique "page classique" (toutes les pages sauf
|
||||
l'éditeur d'écran/d'élément et l'aperçu jouable) : même principe que
|
||||
body.objectEditBody ci-dessus, mais à UNE colonne — un en-tête fixe
|
||||
(titre, formulaire de création...) suivi d'UNE zone qui défile pour son
|
||||
propre compte (.scrollArea), jamais la page elle-même. Permet d'afficher
|
||||
beaucoup de lignes (jeux, écrans, objets, variables, données...) sans
|
||||
perdre le formulaire de création ou le fil d'Ariane hors de l'écran. */
|
||||
body.pageBody{ display:flex; flex-direction:column; height:100vh; margin:0; overflow:hidden; }
|
||||
body.pageBody > .topbar, body.pageBody > .breadcrumbBar{ flex:0 0 auto; }
|
||||
body.pageBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; display:flex; flex-direction:column; }
|
||||
|
||||
.content-page{ width:100%; display:flex; flex-direction:column; min-height:0; flex:1 1 auto; }
|
||||
.content-page > *{ flex:0 0 auto; }
|
||||
.content-page > .scrollArea{ flex:1 1 auto; min-height:0; overflow-y:auto; }
|
||||
|
||||
/* Cas d'un formulaire long à champs dynamiques (ex. object_form.html) : le
|
||||
FORMULAIRE lui-même doit grandir pour occuper l'espace restant, et
|
||||
seule sa liste de champs (.scrollArea, à l'intérieur) défile — le champ
|
||||
"nom" et les boutons "+ Ajouter"/"Créer" restent toujours visibles. */
|
||||
.content-page > form.formScroll{ flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
|
||||
.formScroll > *{ flex:0 0 auto; }
|
||||
.formScroll > .scrollArea{ flex:1 1 auto; min-height:0; overflow-y:auto; }
|
||||
|
||||
@media (max-width: 820px){
|
||||
/* Même logique de repli que .content-objectEdit : sous cette largeur,
|
||||
mieux vaut une page qui défile normalement qu'une zone interne trop
|
||||
comprimée. */
|
||||
body.pageBody{ height:auto; overflow:visible; }
|
||||
body.pageBody > main.content{ overflow:visible; }
|
||||
.content-page > .scrollArea{ overflow:visible; }
|
||||
.content-page > form.formScroll{ flex:none; }
|
||||
.formScroll > .scrollArea{ overflow:visible; }
|
||||
}
|
||||
|
||||
/* ---------- Éditeur d'écrans (façon Elementor/Bricks) ---------- */
|
||||
/* La page de l'éditeur d'écran ne doit jamais défiler elle-même : elle
|
||||
occupe exactement la hauteur de la fenêtre (topbar + zone de travail), et
|
||||
|
||||
+59
-48
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ 'Modifier' if row else 'Ajouter' }} — {{ definition.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li><a href="{{ url_for('object_view', slug=game.slug, definition_id=definition.id) }}">{{ definition.name }}</a></li>
|
||||
@@ -9,56 +9,67 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">{{ 'Modifier l\'entrée #' ~ row.id if row else 'Ajouter une entrée' }} — {{ definition.name }}</h1>
|
||||
<p class="hint mb-4">Formulaire généré automatiquement à partir de la définition de cet objet — aucun champ n'est codé en dur ici.</p>
|
||||
|
||||
<form method="post" class="formScroll">
|
||||
<div class="scrollArea">
|
||||
{% for f in definition.fields %}
|
||||
{% set col = f.name|colname %}
|
||||
{% set current = row[col] if row else none %}
|
||||
<div class="field">
|
||||
<label class="label" for="field_{{ f.id }}">{{ f.name }}{% if f.required %} *{% endif %}</label>
|
||||
<div class="control">
|
||||
|
||||
{% if f.type == 'texte' %}
|
||||
<input class="input" type="text" id="field_{{ f.id }}" name="{{ col }}" value="{{ current or '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'texte_long' %}
|
||||
<textarea class="textarea" id="field_{{ f.id }}" name="{{ col }}" rows="4" {{ 'required' if f.required else '' }}>{{ current or '' }}</textarea>
|
||||
|
||||
{% elif f.type == 'nombre_entier' %}
|
||||
<input class="input" type="number" step="1" id="field_{{ f.id }}" name="{{ col }}" value="{{ current if current is not none else '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'nombre_decimal' %}
|
||||
<input class="input" type="number" step="any" id="field_{{ f.id }}" name="{{ col }}" value="{{ current if current is not none else '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'booleen' %}
|
||||
<label class="checkbox"><input type="checkbox" id="field_{{ f.id }}" name="{{ col }}" {{ 'checked' if current else '' }}> Oui</label>
|
||||
|
||||
{% elif f.type == 'date' %}
|
||||
<input class="input" type="date" id="field_{{ f.id }}" name="{{ col }}" value="{{ current or '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'relation' %}
|
||||
{% set current_rel = row[col ~ '_id'] if row else none %}
|
||||
<div class="select is-fullwidth">
|
||||
<select id="field_{{ f.id }}" name="{{ col }}_id" {{ 'required' if f.required else '' }}>
|
||||
<option value="">—</option>
|
||||
{% for opt in relation_options.get(f.id, []) %}
|
||||
<option value="{{ opt.id }}" {{ 'selected' if current_rel == opt.id else '' }}>{{ opt.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% if not relation_options.get(f.id) %}
|
||||
<p class="help">Aucune entrée n'existe encore pour l'objet lié — crée-en une d'abord si tu veux pouvoir la sélectionner ici.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<form method="post" class="formPassthrough">
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Objet</h2>
|
||||
<div class="card">
|
||||
<p class="hint">Formulaire généré automatiquement à partir de la définition de « {{ definition.name }} » — aucun champ n'est codé en dur ici.</p>
|
||||
<div class="actionsRow">
|
||||
<button type="submit" class="primary">{{ 'Enregistrer les modifications' if row else 'Enregistrer en base' }}</button>
|
||||
</div>
|
||||
<p class="hint" style="margin-top:10px;"><a href="{{ url_for('object_view', slug=game.slug, definition_id=definition.id) }}">← Retour à « {{ definition.name }} »</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="actionsRow">
|
||||
<button type="submit" class="primary">{{ 'Enregistrer les modifications' if row else 'Enregistrer en base' }}</button>
|
||||
<div class="colRight">
|
||||
<h2>Champs</h2>
|
||||
<div class="fieldsTableWrap" style="padding:10px;">
|
||||
{% for f in definition.fields %}
|
||||
{% set col = f.name|colname %}
|
||||
{% set current = row[col] if row else none %}
|
||||
<div class="field">
|
||||
<label class="label" for="field_{{ f.id }}">{{ f.name }}{% if f.required %} *{% endif %}</label>
|
||||
<div class="control">
|
||||
|
||||
{% if f.type == 'texte' %}
|
||||
<input class="input" type="text" id="field_{{ f.id }}" name="{{ col }}" value="{{ current or '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'texte_long' %}
|
||||
<textarea class="textarea" id="field_{{ f.id }}" name="{{ col }}" rows="4" {{ 'required' if f.required else '' }}>{{ current or '' }}</textarea>
|
||||
|
||||
{% elif f.type == 'nombre_entier' %}
|
||||
<input class="input" type="number" step="1" id="field_{{ f.id }}" name="{{ col }}" value="{{ current if current is not none else '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'nombre_decimal' %}
|
||||
<input class="input" type="number" step="any" id="field_{{ f.id }}" name="{{ col }}" value="{{ current if current is not none else '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'booleen' %}
|
||||
<label class="checkbox"><input type="checkbox" id="field_{{ f.id }}" name="{{ col }}" {{ 'checked' if current else '' }}> Oui</label>
|
||||
|
||||
{% elif f.type == 'date' %}
|
||||
<input class="input" type="date" id="field_{{ f.id }}" name="{{ col }}" value="{{ current or '' }}" {{ 'required' if f.required else '' }}>
|
||||
|
||||
{% elif f.type == 'relation' %}
|
||||
{% set current_rel = row[col ~ '_id'] if row else none %}
|
||||
<div class="select is-fullwidth">
|
||||
<select id="field_{{ f.id }}" name="{{ col }}_id" {{ 'required' if f.required else '' }}>
|
||||
<option value="">—</option>
|
||||
{% for opt in relation_options.get(f.id, []) %}
|
||||
<option value="{{ opt.id }}" {{ 'selected' if current_rel == opt.id else '' }}>{{ opt.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% if not relation_options.get(f.id) %}
|
||||
<p class="help">Aucune entrée n'existe encore pour l'objet lié — crée-en une d'abord si tu veux pouvoir la sélectionner ici.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
+78
-68
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ definition.name }} — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li class="is-active"><a>{{ definition.name }}</a></li>
|
||||
@@ -28,74 +28,84 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<a class="addBtn" href="{{ url_for('data_new', slug=game.slug, definition_id=definition.id) }}">+ Ajouter une entrée</a>
|
||||
|
||||
<h2>Données enregistrées</h2>
|
||||
<div class="scrollArea">
|
||||
{% if rows %}
|
||||
{% macro row_field_display(f, r) %}
|
||||
{%- if f.type == 'relation' -%}
|
||||
{{ relation_labels.get(f.id, {}).get(r[(f.name|colname) ~ '_id'], '—') }}
|
||||
{%- elif f.type == 'booleen' -%}
|
||||
{{ 'Oui' if r[f.name|colname] else 'Non' }}
|
||||
{%- else -%}
|
||||
{{ r[f.name|colname] }}
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable dataTable fieldsTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
{% for f in definition.fields %}<th>{{ f.name }}</th>{% endfor %}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in rows %}
|
||||
<tr>
|
||||
<td>{{ r.id }}</td>
|
||||
{% for f in definition.fields %}
|
||||
<td>{{ row_field_display(f, r) }}</td>
|
||||
{% endfor %}
|
||||
<td>
|
||||
<div class="buttons is-inline-flex are-small">
|
||||
<button type="button" class="button is-small" title="Voir cette entrée en détail" onclick="openRowDetail({{ r.id }})">👁️</button>
|
||||
<a class="button is-small" href="{{ url_for('data_edit', slug=game.slug, definition_id=definition.id, row_id=r.id) }}">✏️</a>
|
||||
<form method="post" action="{{ url_for('data_delete', slug=game.slug, definition_id=definition.id, row_id=r.id) }}"
|
||||
onsubmit="return confirm('Supprimer définitivement l\'entrée #{{ r.id }} ?');">
|
||||
<button type="submit" class="button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% for r in rows %}
|
||||
<div class="modal" id="rowDetail{{ r.id }}">
|
||||
<div class="modal-background" onclick="closeRowDetail({{ r.id }})"></div>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">Entrée #{{ r.id }}</p>
|
||||
<button class="delete" aria-label="Fermer" onclick="closeRowDetail({{ r.id }})"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
{% for f in definition.fields %}
|
||||
<div class="rowDetailField">
|
||||
<div class="rowDetailLabel">{{ f.name }}</div>
|
||||
<div class="rowDetailValue">{{ row_field_display(f, r) }}</div>
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Ajouter</h2>
|
||||
<div class="card">
|
||||
<p class="hint">Une entrée, c'est une ligne de la table SQL « {{ definition.table_name }} ».</p>
|
||||
<div class="actionsRow">
|
||||
<a class="button is-primary is-outlined is-fullwidth" href="{{ url_for('data_new', slug=game.slug, definition_id=definition.id) }}">+ Ajouter une entrée</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="colRight">
|
||||
<h2>Données enregistrées</h2>
|
||||
{% if rows %}
|
||||
{% macro row_field_display(f, r) %}
|
||||
{%- if f.type == 'relation' -%}
|
||||
{{ relation_labels.get(f.id, {}).get(r[(f.name|colname) ~ '_id'], '—') }}
|
||||
{%- elif f.type == 'booleen' -%}
|
||||
{{ 'Oui' if r[f.name|colname] else 'Non' }}
|
||||
{%- else -%}
|
||||
{{ r[f.name|colname] }}
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable dataTable fieldsTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
{% for f in definition.fields %}<th>{{ f.name }}</th>{% endfor %}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in rows %}
|
||||
<tr>
|
||||
<td>{{ r.id }}</td>
|
||||
{% for f in definition.fields %}
|
||||
<td>{{ row_field_display(f, r) }}</td>
|
||||
{% endfor %}
|
||||
<td>
|
||||
<div class="buttons is-inline-flex are-small">
|
||||
<button type="button" class="button is-small" title="Voir cette entrée en détail" onclick="openRowDetail({{ r.id }})">👁️</button>
|
||||
<a class="button is-small" href="{{ url_for('data_edit', slug=game.slug, definition_id=definition.id, row_id=r.id) }}">✏️</a>
|
||||
<form method="post" action="{{ url_for('data_delete', slug=game.slug, definition_id=definition.id, row_id=r.id) }}"
|
||||
onsubmit="return confirm('Supprimer définitivement l\'entrée #{{ r.id }} ?');">
|
||||
<button type="submit" class="button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% for r in rows %}
|
||||
<div class="modal" id="rowDetail{{ r.id }}">
|
||||
<div class="modal-background" onclick="closeRowDetail({{ r.id }})"></div>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">Entrée #{{ r.id }}</p>
|
||||
<button class="delete" aria-label="Fermer" onclick="closeRowDetail({{ r.id }})"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
{% for f in definition.fields %}
|
||||
<div class="rowDetailField">
|
||||
<div class="rowDetailLabel">{{ f.name }}</div>
|
||||
<div class="rowDetailValue">{{ row_field_display(f, r) }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="hint">Aucune donnée enregistrée pour l'instant.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="hint">Aucune donnée enregistrée pour l'instant.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Éléments de jeu — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li class="is-active"><a>Éléments de jeu</a></li>
|
||||
@@ -10,59 +10,64 @@
|
||||
<h1 class="title">Éléments de jeu</h1>
|
||||
<p class="hint mb-4">Un élément de jeu est un conteneur réutilisable.</p>
|
||||
|
||||
<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 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="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>
|
||||
|
||||
<h2>Catalogue</h2>
|
||||
<div class="scrollArea">
|
||||
{% 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 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 %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Variables — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li class="is-active"><a>Variables</a></li>
|
||||
@@ -10,63 +10,66 @@
|
||||
<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>
|
||||
|
||||
<form method="post" action="{{ url_for('create_global_var', slug=game.slug) }}" class="card">
|
||||
<div class="fieldRow">
|
||||
<div class="formField" style="flex:1;">
|
||||
<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="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="actionsRow"><button type="submit" class="primary">+ Créer la variable</button></div>
|
||||
</form>
|
||||
|
||||
<h2>Variables définies</h2>
|
||||
<div class="scrollArea">
|
||||
{% 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 ci-dessus.</p>
|
||||
{% endif %}
|
||||
<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 %}
|
||||
|
||||
+39
-36
@@ -1,46 +1,49 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Forge Engine — Mes jeux{% endblock %}
|
||||
{% block breadcrumb_wrap %}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Mes jeux</h1>
|
||||
|
||||
<form method="post" action="{{ url_for('games_new') }}" class="card">
|
||||
<div class="fieldRow">
|
||||
<div class="formField" style="flex:1;">
|
||||
<label for="name">Nom du nouveau jeu</label>
|
||||
<input type="text" id="name" name="name" placeholder="ex. CyberQuest RGPD" required>
|
||||
</div>
|
||||
<button type="submit" class="primary" style="align-self:flex-end;">+ Créer le jeu</button>
|
||||
<div class="twoCol">
|
||||
<div class="colLeft">
|
||||
<h2>Créer un jeu</h2>
|
||||
<form method="post" action="{{ url_for('games_new') }}" class="card">
|
||||
<div class="formField">
|
||||
<label for="name">Nom du nouveau jeu</label>
|
||||
<input type="text" id="name" name="name" placeholder="ex. CyberQuest RGPD" required>
|
||||
</div>
|
||||
<div class="actionsRow"><button type="submit" class="primary">+ Créer le jeu</button></div>
|
||||
<p class="hint" style="margin-top:6px;">Crée un dossier avec index.html / index.css / index.js reliés entre eux, et une base de données dédiée à ce jeu.</p>
|
||||
</form>
|
||||
</div>
|
||||
<p class="hint" style="margin-top:6px;">Crée un dossier avec index.html / index.css / index.js reliés entre eux, et une base de données dédiée à ce jeu.</p>
|
||||
</form>
|
||||
|
||||
<h2>Jeux existants</h2>
|
||||
<div class="scrollArea">
|
||||
{% if games %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
<thead><tr><th>Nom</th><th>Dossier</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for g in games %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('game_dashboard', slug=g.slug) }}">{{ g.name }}</a></td>
|
||||
<td class="has-text-grey">projects/{{ g.slug }}/</td>
|
||||
<td class="fieldsTableActions">
|
||||
<form method="post" action="{{ url_for('game_delete', slug=g.slug) }}"
|
||||
onsubmit="return confirm('Supprimer définitivement le jeu « {{ g.name }} » et tout son contenu (dossier + base de données) ?');">
|
||||
<button type="submit" class="button is-small is-danger" title="Supprimer ce jeu">🗑️</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Aucun jeu pour l'instant — crée le premier ci-dessus.</p>
|
||||
{% endif %}
|
||||
<div class="colRight">
|
||||
<h2>Jeux existants</h2>
|
||||
{% if games %}
|
||||
<div class="fieldsTableWrap">
|
||||
<table class="table is-fullwidth is-hoverable fieldsTable">
|
||||
<thead><tr><th>Nom</th><th>Dossier</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{% for g in games %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('game_dashboard', slug=g.slug) }}">{{ g.name }}</a></td>
|
||||
<td class="has-text-grey">projects/{{ g.slug }}/</td>
|
||||
<td class="fieldsTableActions">
|
||||
<form method="post" action="{{ url_for('game_delete', slug=g.slug) }}"
|
||||
onsubmit="return confirm('Supprimer définitivement le jeu « {{ g.name }} » et tout son contenu (dossier + base de données) ?');">
|
||||
<button type="submit" class="button is-small is-danger" title="Supprimer ce jeu">🗑️</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint">Aucun jeu pour l'instant — crée le premier à gauche.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
+20
-12
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Nouvel objet — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li class="is-active"><a>Nouvel objet</a></li>
|
||||
@@ -9,19 +9,27 @@
|
||||
{% block content %}
|
||||
<h1 class="title">Définir un nouvel objet</h1>
|
||||
|
||||
<form method="post" class="formScroll" id="objectForm">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<h3>Champs</h3>
|
||||
<div class="scrollArea">
|
||||
<div id="fieldsList"></div>
|
||||
<div class="colRight">
|
||||
<h2>Champs</h2>
|
||||
<div class="fieldsTableWrap" style="padding:10px;">
|
||||
<div id="fieldsList"></div>
|
||||
</div>
|
||||
<button type="button" class="button is-outlined is-fullwidth mt-2" id="btnAddField">+ Ajouter un champ</button>
|
||||
</div>
|
||||
<button type="button" class="button is-outlined is-fullwidth" id="btnAddField">+ Ajouter un champ</button>
|
||||
|
||||
<div class="actionsRow"><button type="submit" class="primary">Créer l'objet</button></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<template id="fieldRowTemplate">
|
||||
|
||||
+46
-44
@@ -1,60 +1,62 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Écrans — {{ game.name }}{% endblock %}
|
||||
{% block content_class %}content-page{% endblock %}
|
||||
{% block body_class %}pageBody{% endblock %}
|
||||
{% block content_class %}content-wide content-objectEdit{% endblock %}
|
||||
{% block body_class %}objectEditBody{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li class="is-active"><a>Écrans</a></li>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1 class="title">Écrans du jeu</h1>
|
||||
|
||||
<form method="post" action="{{ url_for('screens_new', slug=game.slug) }}" class="card">
|
||||
<div class="fieldRow">
|
||||
<div class="formField" style="flex:1;">
|
||||
<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>
|
||||
<button type="submit" class="primary" style="align-self:flex-end;">+ Créer l'écran</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% 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 %}
|
||||
|
||||
<h2>Enchaînement des écrans</h2>
|
||||
<div class="scrollArea">
|
||||
{% 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 ci-dessus.</p>
|
||||
{% 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