fix: sélection multi-blocs fonctionnelle (Ctrl+C/X, drag souris, clic droit) + identité visuelle (v7.69.0)
FlowDeck CI / lint (push) Successful in 1m34s
FlowDeck CI / test (push) Failing after 17m31s
FlowDeck CI / docker (push) Skipped

Trois bugs d'éditeur, chacun avec sa cause racine prouvée par trace
d'événements — le mécanisme Clipboard livré en v7.68 était inutilisable.

1) Ctrl+C / Ctrl+X multi-blocs ne faisaient RIEN.
   Cause : le navigateur ne sait pas sérialiser une sélection qui traverse
   deux `contenteditable` (chaque bloc en a un). `getSelection().toString()`
   renvoie `""` et Chromium n'émet AUCUN événement `copy` — les handlers
   `ct.addEventListener('copy')` n'étaient donc jamais atteints.
   → le raccourci est intercepté au keydown (capture sur document, garde
   `closest('#_blocksCt')` pour ne pas voler Ctrl+C ailleurs) et le markdown
   est écrit dans le presse-papier par nos soins. Sélection mono-bloc =
   comportement natif inchangé.

2) Glisser la souris d'un bloc à l'autre ne sélectionnait qu'un bloc.
   Cause : `mouseup` (on reconstruit la plage) → `click` → `focusin` → le
   navigateur efface la sélection. La plage était reconstruite puis détruite
   dans la foulée.
   → la plage reconstruite est mise en attente (`_mdSelRange`) et restaurée
   au tour de boucle suivant si le focus l'a effectivement effacée. Chaque
   nouveau geste (mousedown) remet l'attente à zéro, donc un clic pour
   placer le curseur reste normal.

3) Le clic droit effaçait le surlignage.
   Cause : `.bm-search` prenait le focus 10 ms après l'ouverture du menu.
   → le menu ne vole plus le focus quand un texte est sélectionné. Les
   actions Clipboard utilisaient déjà la sélection figée à l'ouverture
   (`d._clipSt`) ; le `preventDefault` du clic droit est remonté sur
   `mousedown` (sur `contextmenu` il arrive trop tard).

Identité visuelle (bannière + logo du projet ajoutés à la racine) :
- assets optimisés servis : `static/img/banner.webp` 22,5 Ko (l'original
  fait 1,6 Mo) + JPEG de secours, `logo.webp` 5,3 Ko + `logo-512.jpg` ;
  originaux conservés dans `assets/` pour régénération.
- icônes PWA régénérées à partir du vrai logo (72 → 512 px, marge
  maskable sur 192/512) + apple-touch-icon.
- landing : logo dans la barre de navigation, bannière en <picture>
  (WebP + JPEG) avec dimensions déclarées (pas de décalage de mise en page).
- `og:image`, `twitter:card` et `meta description` ajoutés sur la landing
  ET dans base.html — la landing a son propre <head>.

Tests : `tests/test_v769_selection_persistence.py` (19 statiques) +
`e2e/v769_selection_persistence.spec.js` (5, vrais gestes : drag souris,
Ctrl+C/Ctrl+X au clavier, clic droit). `e2e/v768_columns_clipboard.spec.js`
corrigé : les gestes simulés (`execCommand`, plage fabriquée en evaluate)
sont remplacés par de vrais gestes, et le token statique obsolète
`si>=ei)return null;` aligné sur la garde `isCollapsed` réelle.

pytest 1413 passed / 0 failed · ruff OK · OpenAPI 526 chemins / 7.69.0
This commit is contained in:
2026-10-08 17:27:14 -04:00
parent 7cf922106f
commit 3d3b46b58b
28 changed files with 610 additions and 38 deletions
+1 -1
View File
@@ -186,7 +186,7 @@ async def lifespan(_app: FastAPI):
app = FastAPI(
title="FlowDeck",
version="7.68.0",
version="7.69.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan,
+11
View File
@@ -8,6 +8,17 @@
<link rel="manifest" href="/static/manifest.json">
<meta name="theme-color" content="#191919">
<link rel="apple-touch-icon" href="/static/icons/apple-touch-icon.png">
<!-- v7.69 : identité visuelle (logo + bannière du projet) -->
<meta name="description" content="FlowDeck — espace de travail style Notion auto-hébergé, intégré à Gitea/GitHub.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="FlowDeck">
<meta property="og:title" content="FlowDeck — votre espace Notion auto-hébergé">
<meta property="og:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub, sur votre propre serveur.">
<meta property="og:image" content="/static/img/logo-512.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="FlowDeck — votre espace Notion auto-hébergé">
<meta name="twitter:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub.">
<meta name="twitter:image" content="/static/img/logo-512.jpg">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="stylesheet" href="/static/css/app.css?v={{ asset_version }}">
+36 -1
View File
@@ -11,6 +11,17 @@
<link rel="apple-touch-icon" href="/static/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<!-- v7.69 : identité visuelle — la landing est la page la plus partagée -->
<meta name="description" content="FlowDeck — espace de travail style Notion auto-hébergé, intégré à Gitea/GitHub. Éditeur de blocs, Kanban, bases de données.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="FlowDeck">
<meta property="og:title" content="FlowDeck — votre espace Notion auto-hébergé">
<meta property="og:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub, sur votre propre serveur.">
<meta property="og:image" content="/static/img/logo-512.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="FlowDeck — votre espace Notion auto-hébergé">
<meta name="twitter:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub.">
<meta name="twitter:image" content="/static/img/logo-512.jpg">
<style>
:root {
--bg: #191919;
@@ -112,6 +123,22 @@
padding:12px 28px;
}
/* v7.69 : identité visuelle */
.brand-mark{border-radius:7px;flex:none;}
.hero-visual{
max-width:1060px;
margin:0 auto 72px;
padding:0 32px;
}
.hero-visual img{
width:100%;
height:auto;
display:block;
border-radius:14px;
border:1px solid var(--border);
box-shadow:0 30px 70px -30px rgba(0,0,0,.5);
}
/* Features grid */
.features{
display:grid;
@@ -148,7 +175,7 @@
<nav class="landing-nav">
<a href="/" class="landing-logo">
<span>{{ fd_icon("book",20) }}</span> FlowDeck
<img class="brand-mark" src="/static/img/logo.webp" alt="" width="26" height="26"> FlowDeck
</a>
<div class="landing-nav-actions">
<a href="/auth/login?provider=local" class="btn btn-secondary">Log in</a>
@@ -169,6 +196,14 @@
</div>
</section>
<!-- v7.69 : bannière du projet (asset optimisé : WebP 22 KB, JPEG en secours) -->
<div class="hero-visual">
<picture>
<source srcset="/static/img/banner.webp" type="image/webp">
<img src="/static/img/banner.jpg" alt="FlowDeck — éditeur de blocs, Kanban et bases de données" width="2400" height="793" loading="lazy" decoding="async">
</picture>
</div>
<div class="features">
<div class="feature-card">
<div class="feature-icon">{{ fd_icon("edit",24) }}</div>