diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9dd40..a85e7e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog - FlowDeck +## v7.60.0 (2026-10-07) — Éditeur : bouton + à gauche du handle de bloc + +### Added + +- **Bouton `+` à gauche du handle** (les 6 points qui ouvrent le menu ⋮⋮ / + servent au drag) : clique → **nouveau bloc inséré sous le bloc courant**, + via le mécanisme déjà en place (`E.addAfter(idx)` → `addAt(idx+1)`). +- Positionné dans la gouttière (`left:-64px`, gouttière `.blocks-container` + de 64px, `-56px` quand elle passe à 32px), apparaît au survol/focus du bloc + comme le handle, masqué avec lui sur écran étroit (≤768px et le second + breakpoint — aucun débordement horizontal ajouté au conteneur. +- `aria-label` + `title` « Add block below » (accessibilité). +- **Tests** — `tests/test_v760_block_insert_btn.py` : **2 tests** (ordre + dans le wrapper, câblage `E.addAfter`, positions/masquages CSS). + ## v7.59.3 (2026-10-07) — Correction : « Turn into » du menu contextuel ### Fixed diff --git a/VERSION b/VERSION index 30e0d31..22861a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.59.3 +7.60.0 diff --git a/app/main.py b/app/main.py index c1841fe..6407807 100644 --- a/app/main.py +++ b/app/main.py @@ -186,7 +186,7 @@ async def lifespan(_app: FastAPI): app = FastAPI( title="FlowDeck", - version="7.59.3", + version="7.60.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, diff --git a/docs/openapi-v2.json b/docs/openapi-v2.json index fa08625..497cdc6 100644 --- a/docs/openapi-v2.json +++ b/docs/openapi-v2.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "FlowDeck", - "version": "7.59.3" + "version": "7.60.0" }, "paths": { "/auth/register": { diff --git a/static/css/app.css b/static/css/app.css index 465ada7..07801cd 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -2341,6 +2341,36 @@ button.breadcrumb-current { max-width: 260px; } cursor: grabbing; } +/* + « ajouter un bloc dessous » — juste à gauche du handle (gouttière 64px) */ +.block-insert-btn { + position: absolute; + left: -64px; + top: 5px; + width: 22px; + height: 22px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + background: none; + border: none; + border-radius: 3px; + color: var(--text-dim); + font-size: 17px; + line-height: 1; + cursor: pointer; + opacity: 0; + transition: opacity 0.15s ease; +} +.block-wrapper:hover .block-insert-btn, +.block-wrapper:focus-within .block-insert-btn { + opacity: 1; +} +.block-insert-btn:hover { + background: var(--bg-hover); + color: var(--text-primary); +} + /* ── v5.10.0: selection multiple + menu contexte bloc ── */ .block-wrapper.selected { background: rgba(35,131,226,0.06); @@ -2934,6 +2964,7 @@ button.breadcrumb-current { max-width: 260px; } .page-title-input { font-size: 28px; } .blocks-container { padding: 8px 16px 96px; } .block-handle { display: none; } + .block-insert-btn { display: none; } .block-actions { display: none; } .editor-statusbar { left: 0; } } @@ -3409,6 +3440,7 @@ button.breadcrumb-current { max-width: 260px; } .page-cover-area { padding: 32px 32px 8px; } .blocks-container { padding: 8px 32px 80px; } .block-handle { left: -32px; } + .block-insert-btn { left: -56px; } .page-title-block::before { left: -32px; } .page-title-input { font-size: 32px; } @@ -3499,6 +3531,7 @@ button.breadcrumb-current { max-width: 260px; } .page-title-input { font-size: 24px; } .blocks-container { padding: 8px 16px 96px; } .block-handle { display: none; } + .block-insert-btn { display: none; } .block-actions { display: none; } .page-title-block::before { display: none; } .page-title-block .page-icon-emoji { margin-left: 0; } diff --git a/static/js/page_editor_scripts.js b/static/js/page_editor_scripts.js index 8eafe00..878c343 100644 --- a/static/js/page_editor_scripts.js +++ b/static/js/page_editor_scripts.js @@ -609,7 +609,10 @@ const PD=(()=>{try{const el=document.getElementById('page-data');return el?JSON. numAttr=` data-num="${idx-s+1}"`; } const actions=idx>=0?`
`:''; + // + « ajouter un bloc dessous », juste avant le handle (gouttière 64px) + const insertBtn=idx>=0?``:''; return `