Panneau gauche à onglets : "Pages" (gestion complète) et "Mise en page" (bibliothèque)
Build and deploy / test-python (push) Successful in 10m10s
Build and deploy / test-js (push) Successful in 51s
Build and deploy / lint-python (push) Successful in 4m44s
Build and deploy / lint-js (push) Failing after 1m27s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 4m8s

Remplace le carrousel une-page-à-la-fois par un panneau dédié plein
hauteur : liste verticale scrollable de toutes les pages, réordonnage
par glisser OU boutons haut/bas (accessibilité clavier), renommer
(crayon, édition en ligne), supprimer (protégé contre la suppression
de la dernière page), ajouter. La bibliothèque d'éléments passe dans
un second onglet "Mise en page", contenu inchangé. "Mise en page"
actif par défaut au chargement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-23 09:03:21 +02:00
co-authored by Claude Sonnet 5
parent 14ca9e32a8
commit b4e4e80b7c
4 changed files with 319 additions and 258 deletions
+74 -57
View File
@@ -95,82 +95,99 @@
<div class="docBodyWrap">
<div class="docSidebarClose" id="docCloseLeft">← Retour au document</div>
<div class="docSidebar docSidebarLeft" id="docSidebarLeft">
<div class="docPageSection">
<div class="docSectionLabel">Pages</div>
<div class="docPageStrip">
<button type="button"
class="docPageStripNav"
id="docPageStripPrev"
aria-label="Page précédente"
title="Page précédente">‹</button>
<div class="docPageList" id="docPageList">
{# active_page est toujours pages[0] au chargement initial (voir
routes/document/document_edit.py) — index 0 fixe, jamais recalculé
ici ; un changement de page ensuite est entièrement géré côté
client par forgeDocRenderPageList, qui recalcule le VRAI index. #}
{% set active_index = 0 %}
<div class="docPageListItem is-active" role="button" tabindex="0" data-page-id="{{ active_page.id }}">
{# Panneau gauche à onglets (retour utilisateur du 23/09/2026 :
"il dois avoir deux onglets") : "Mise en page" (bibliothèque
d'éléments, contenu inchangé) actif par défaut — le panneau
"Pages" (gestion complète des pages : liste/réordonner/ajouter/
supprimer/renommer) est un espace dédié plein-écran plutôt que
de se partager la hauteur avec la bibliothèque comme les
itérations précédentes (bande de vignettes, puis carrousel). #}
<div class="docSidebarTabs" role="tablist">
<button type="button"
class="docSidebarTab"
id="docTabPages"
role="tab"
aria-selected="false"
aria-controls="docTabPanelPages"
data-tab="pages">Pages</button>
<button type="button"
class="docSidebarTab is-active"
id="docTabLayout"
role="tab"
aria-selected="true"
aria-controls="docTabPanelLayout"
data-tab="layout">Mise en page</button>
</div>
<div class="docSidebarTabPanel"
id="docTabPanelPages"
role="tabpanel"
aria-labelledby="docTabPages"
hidden>
<div class="docPageManagerList" id="docPageManagerList">
{% for page in pages %}
<div class="docPageRow {{ 'is-active' if page.id == active_page.id else '' }}"
role="button"
tabindex="0"
draggable="true"
data-page-id="{{ page.id }}">
{# //NOSONAR Web:S6819,Web:MouseEventWithoutKeyboardEquivalentCheck - div+role=button
volontaire : la rangée contient de vrais <button> d'action (réordonner/renommer/
supprimer), qu'un <button> englobant ne pourrait pas contenir validement.
L'équivalent clavier (Entrée/Espace) est posé côté JS (forgeDocRenderPageList),
L'équivalent clavier (Entrée/Espace) est posé côté JS (forgeDocRenderPageManagerList),
donc le finding clavier de Sonar est un faux positif : l'analyseur statique ne
voit pas les addEventListener dynamiques. #}
<div class="docPageListActions">
<span class="docPageRowHandle" aria-hidden="true">⠿</span>
<span class="docPageRowNumber">{{ loop.index }}</span>
<span class="docPageRowTitle"><span class="docPageRowTitleText">{{ page.title }}</span></span>
<span class="docPageRowActions">
<button type="button"
class="docPageListMove"
class="docPageRowMove"
data-dir="up"
data-page-id="{{ active_page.id }}"
aria-label="Réordonner vers la gauche"
title="Réordonner vers la gauche"
{{ 'disabled' if active_index == 0 else '' }}>←</button>
data-page-id="{{ page.id }}"
aria-label="Monter"
title="Monter"
{{ 'disabled' if loop.first else '' }}>↑</button>
<button type="button"
class="docPageListMove"
class="docPageRowMove"
data-dir="down"
data-page-id="{{ active_page.id }}"
aria-label="Réordonner vers la droite"
title="Réordonner vers la droite"
{{ 'disabled' if active_index == pages|length - 1 else '' }}>→</button>
data-page-id="{{ page.id }}"
aria-label="Descendre"
title="Descendre"
{{ 'disabled' if loop.last else '' }}>↓</button>
<button type="button"
class="docPageListRename"
data-page-id="{{ active_page.id }}"
class="docPageRowRename"
data-page-id="{{ page.id }}"
aria-label="Renommer cette page"
title="Renommer cette page">✎</button>
<button type="button"
class="docPageListDelete"
data-page-id="{{ active_page.id }}"
class="docPageRowDelete"
data-page-id="{{ page.id }}"
aria-label="Supprimer cette page"
title="Supprimer cette page"
{{ 'disabled' if pages|length <= 1 else '' }}>✕</button>
</div>
<div class="docPageListSquare">{{ active_index + 1 }}</div>
<span class="docPageListTitle"><span class="docPageListTitleText">{{ active_page.title }}</span></span>
<span class="docPageListCounter">{{ active_index + 1 }} / {{ pages|length }}</span>
</span>
</div>
{% endfor %}
</div>
<button type="button" class="docBtnSecondary docPageManagerAdd" id="docPageManagerAdd">+ Ajouter une page</button>
</div>
<div class="docSidebarTabPanel" id="docTabPanelLayout" role="tabpanel" aria-labelledby="docTabLayout">
{% for category_key, category in element_library.items() %}
<div>
<div class="docSectionLabel">{{ category.label }}</div>
<div class="docLibList">
{% for kind in category.kinds %}
<div class="docLibItem docLibItem--row"
draggable="true"
data-add="{{ kind }}">
<span class="docLibIcon docLibIcon--{{ kind }}"></span>
<span>{{ element_kind_labels[kind] }}</span>
</div>
{% endfor %}
</div>
</div>
<button type="button"
class="docPageStripNav"
id="docPageStripNext"
aria-label="Page suivante"
title="Page suivante">›</button>
</div>
<button type="button" class="docBtnSecondary docPageListAdd" id="docPageListAdd">+ Ajouter une page</button>
{% endfor %}
</div>
{% for category_key, category in element_library.items() %}
<div>
<div class="docSectionLabel">{{ category.label }}</div>
<div class="docLibList">
{% for kind in category.kinds %}
<div class="docLibItem docLibItem--row"
draggable="true"
data-add="{{ kind }}">
<span class="docLibIcon docLibIcon--{{ kind }}"></span>
<span>{{ element_kind_labels[kind] }}</span>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="docCanvasArea" id="docCanvasArea">
<div class="docPage" id="docPage">