fix(editor): placeholder visible, fleches menu /, icones callout/image, largeur composer AI
FlowDeck CI / test (push) Failing after 15s
FlowDeck CI / docker (push) Skipped

- Placeholder "Press 'space'..." : la classe .empty est basculee sur l'element
  interne [data-bid], mais la regle CSS ciblait .block-content (l'exterieur),
  donc le ::before ne se rendait jamais. La regle cible desormais
  .block-content [data-bid].empty::before.
- Fleches haut/bas du menu / : ajout d'un ecouteur keydown au niveau document
  (actif quand le menu est ouvert) pour naviguer quel que soit le focus
  (l'input vit dans #_slashMenu, voisin de #_blocksCt). Selection .selected en
  !important pour gagner sur :hover + auto-scroll de l'element selectionne.
- Item "callout" du menu / : icone texte 'lightbulb' remplacee par l'emoji
  (et 'image' par ). Le texte n'est plus mal positionne.
- Composer "Edit with AI" : largeur alignee sur celle du bloc (min 280px).

v5.1.4
This commit is contained in:
2026-09-07 11:56:16 -04:00
parent 43aca1a1f7
commit 63a41ade48
5 changed files with 59 additions and 12 deletions
+32 -1
View File
@@ -1,6 +1,37 @@
# Changelog — FlowDeck
## v5.1.3 (2026-09-07) — Corrections : AI inline (400), bloc vide, menu `/`, poignée, contour
## v5.1.4 (2026-09-07) — Corrections : placeholder invisible, flèches `/`, item vocabulaire, largeur AI
> Résout les derniers retours UI de l'éditeur v5.1.2/5.1.3.
### Placeholder « Press 'space' for AI » — jamais affiché
- **Cause réelle** : la classe `.empty` est basculée sur l'élément interne
`[data-bid]` (sélecteur `[data-placeholder]` au render), mais la règle CSS
ciblait l'élément **externe** `.block-content` — deux éléments différents, donc
le `::before` d'aide ne se rendait **jamais**.
- La règle cible désormais `.block-content [data-bid].empty::before` (l'élément
qui porte réellement `data-placeholder` + `.empty`).
### Flèches ↑/↓ du menu `/`
- La navigation dépendait de l'endroit où se trouvait le focus (`_in` vs bloc vs
ailleurs) : `onKd` n'est lié qu'à `#_blocksCt`, l'input vit dans `#_slashMenu`
(un voisin), d'où un comportement fragile/incohérent.
- Ajout d'un écouteur `keydown` **au niveau document** (actif quand le menu est
ouvert) : ↑/↓/Entrée/Échap fonctionnent quel que soit le focus, plus de double
déclenchement.
- La sélection `.selected` passe en `!important` pour toujours gagner sur
`.slash-item:hover`, et l'élément sélectionné est auto-défilé (`scrollIntoView`).
### Item « vocabulaire / vocabulaire » du menu `/` mal positionné
- Les icônes texte `'lightbulb'` (Callout) et `'image'` (Image) étaient injectées
en clair dans la pastille d'icône, provoquant un texte décalé/débordant.
- Remplacées par les emojis `💡` (Callout) et `🖼️` (Image).
### Composer « Edit with AI » — largeur
- Le composer AI utilisait une largeur fixe `420px` ; il s'aligne désormais sur la
largeur du bloc ciblé (min 280px, max 1200px).
> Résout les régressions du composer AI et de l'éditeur Notion-style v5.1.2.
+1 -1
View File
@@ -1 +1 @@
5.1.3
5.1.4
+1 -1
View File
@@ -60,7 +60,7 @@ async def lifespan(_app: FastAPI):
app = FastAPI(
title="FlowDeck",
version="5.1.3",
version="5.1.4",
docs_url="/docs" if settings.log_level == "DEBUG" else None,
redoc_url=None,
lifespan=lifespan,
+23 -8
View File
@@ -7,10 +7,10 @@
{id:'paragraph',name:'Text',icon:'¶'},{id:'heading_1',name:'Heading 1',icon:'H1'},{id:'heading_2',name:'Heading 2',icon:'H2'},
{id:'heading_3',name:'Heading 3',icon:'H3'},{id:'heading_4',name:'Heading 4',icon:'H4'},{id:'bulleted_list',name:'Bulleted list',icon:'•'},{id:'numbered_list',name:'Numbered list',icon:'1.'},
{id:'to_do',name:'To-do',icon:'☐'},{id:'toggle',name:'Toggle',icon:'▶'},{id:'quote',name:'Quote',icon:'❝'},
{id:'callout',name:'Callout',icon:'lightbulb'},{id:'table_of_contents',name:'Table of contents',icon:'☰'},{id:'math',name:'Math equation',icon:'∑'},
{id:'callout',name:'Callout',icon:'💡'},{id:'table_of_contents',name:'Table of contents',icon:'☰'},{id:'math',name:'Math equation',icon:'∑'},
{id:'columns',name:'Column list',icon:'▮'},{id:'divider',name:'Divider',icon:'—'},{id:'code',name:'Code block',icon:'<>'},
{id:'table',name:'Table',icon:'⊞'},
]},{name:'MEDIA',items:[{id:'image',name:'Image',icon:'image'}]},
]},{name:'MEDIA',items:[{id:'image',name:'Image',icon:'🖼️'}]},
{name:'DATA',items:[{id:'database',name:'Database / Inline database',icon:'📊'}]}];
let _bid=0;function genId(){return 'b'+(++_bid)+'_'+Date.now().toString(36);}
@@ -220,10 +220,23 @@
footer.onclick=()=>SM.close();
const inp=document.createElement('input');inp.type='text';inp.placeholder='Type to search';
inp.style.cssText='width:100%;padding:9px 12px;background:var(--bg-secondary);border:none;border-top:1px solid var(--border);color:var(--text-primary);font-size:14px;outline:none;box-sizing:border-box';
inp.oninput=()=>SM.flt();inp.onkeydown=ev=>SM._kd(ev);
inp.oninput=()=>SM.flt();
e.appendChild(list);e.appendChild(footer);e.appendChild(inp);
SM._e=e;SM._in=inp;SM._li=list;SM._f=footer;
document.addEventListener('mousedown',ev=>{if(!e.contains(ev.target))SM.close();});
if(!SM._doc){
SM._doc=true;
document.addEventListener('keydown',function(ev){
if(!SM._o)return;
if(ev.metaKey||ev.ctrlKey||ev.altKey)return;
if(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Enter'||ev.key==='Escape'){
ev.preventDefault();ev.stopPropagation();SM._docKd(ev);
}
});
}
SM._docKd=function(ev){
if(SM._o&&(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Enter'||ev.key==='Escape'))SM._kd(ev);
};
},
_hover(it){ if(!it) return; const id=it.dataset.sid; if(!id) return;
if(!SM._pv){ const d=document.createElement('div'); d.className='sm-preview'; d.style.cssText='position:fixed;z-index:1000;background:var(--bg-modal);border:1px solid var(--border-light);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.5);padding:12px;width:220px;pointer-events:none;'; document.body.appendChild(d); SM._pv=d; }
@@ -253,7 +266,7 @@
else if(e.key==='ArrowUp'){e.preventDefault();SM._s=Math.max(SM._s-1,0);SM._rs();}
else if(e.key==='Enter'){e.preventDefault();const c=SM._it[SM._s];if(c)SM.sel(c.id);}
else if(e.key==='Escape'){e.preventDefault();SM.close();}},
_rs(){const its=SM._li.querySelectorAll('.slash-item');its.forEach((el,i)=>{el.classList.toggle('selected',i===SM._s);});},
_rs(){const its=SM._li.querySelectorAll('.slash-item');its.forEach((el,i)=>{el.classList.toggle('selected',i===SM._s);});const cur=its[SM._s];if(cur&&cur.scrollIntoView)cur.scrollIntoView({block:'nearest'});},
sel(id){if(window.E)window.E.applySlash(id);SM.close();},
get isOpen(){return SM._o;}};
@@ -266,14 +279,16 @@
const d=document.createElement('div'); d.id='_aiC'; d.style.cssText='position:fixed;z-index:1200;width:420px;max-width:92vw;display:none';
document.body.appendChild(d); this.ROOT=d; return d; },
open(idx){ const self=this; this._idx=idx; this._stage='input'; this.mk();
const r=this._anchorRect(idx); this.ROOT.style.left=Math.max(8,Math.min(r.left,window.innerWidth-440))+ 'px';
const r=this._anchorRect(idx);
const w=Math.max(r.width||0,280); this.ROOT.style.width=Math.min(w,1200)+'px';
this.ROOT.style.left=Math.max(8,Math.min(r.left,window.innerWidth-r.width-16))+ 'px';
this.ROOT.style.top=Math.max(8,(r.bottom+6>window.innerHeight-260)?r.top-180:r.bottom+6)+'px';
this.paint(); this.ROOT.style.display='block'; this._open=true; this._focusIngest();
document.addEventListener('mousedown',function onDoc(ev){ if(!self.ROOT.contains(ev.target)){ self.close(); document.removeEventListener('mousedown',onDoc); } });
},
close(){ if(this.ROOT)this.ROOT.style.display='none'; this._open=false; this._html=''; if(window.E)window.E.dirty=true; this._stage=''; },
_anchorRect(idx){ const E=window.E; if(!E||!E.blocks)return{x:Math.max(24,window.innerWidth/2-210),bottom:window.innerHeight/2};
const b=E.blocks[idx]; const el=E.getEl(b?b.id:null); if(el){const r=el.getBoundingClientRect();return r;} return {left:24,top:120,bottom:180}; },
_anchorRect(idx){ const E=window.E; if(!E||!E.blocks)return{left:Math.max(24,window.innerWidth/2-210),top:window.innerHeight/2,bottom:window.innerHeight/2,width:420};
const b=E.blocks[idx]; const el=E.getEl(b?b.id:null); if(el){const r=el.getBoundingClientRect();return r;} return {left:24,top:120,bottom:180,width:420}; },
_focusIngest(){ const i=this.ROOT.querySelector('.aici-input'); if(i){i.focus();} },
_escTag(tag,s){return '<'+tag+'>'+s+'</'+tag+'>';},
_mdToHtml(md){ // compact block render (headings, lists, bold, paragraphs)
@@ -1088,7 +1103,7 @@ applyAIBlocks(text){
const{el,bid,idx}=ab;const block=this.blocks[idx];if(!block)return;
if(SM.isOpen){
if(e.key==='Escape'){e.preventDefault();SM.close();return;}
if(e.key==='ArrowDown'||e.key==='ArrowUp'||e.key==='Enter'){e.preventDefault();SM._in.dispatchEvent(new KeyboardEvent('keydown',{key:e.key,bubbles:true}));return;}
if(e.key==='ArrowDown'||e.key==='ArrowUp'||e.key==='Enter'){e.preventDefault();return;}
if(e.key==='Backspace'&&!SM._q&&(el.textContent||'').trim()==='/'){e.preventDefault();SM.close();return;}
return;
}
+2 -1
View File
@@ -2334,6 +2334,7 @@ button.breadcrumb-current { max-width: 260px; }
min-height: 28px;
word-break: break-word;
}
.block-content [data-bid].empty::before,
.block-content.empty::before {
content: attr(data-placeholder);
color: var(--text-secondary);
@@ -4585,7 +4586,7 @@ button.breadcrumb-current { max-width: 260px; }
@keyframes ai-pulse { 0%,100%{opacity:.45} 50%{opacity:1} }
.slash-menu { flex-direction: column; }
.slash-menu .sm-footer:hover { background: var(--bg-hover); }
.slash-item.selected { background: rgba(35,131,226,.16); box-shadow: inset 2px 0 0 var(--accent,#2383E2); }
.slash-item.selected { background: rgba(35,131,226,.16) !important; box-shadow: inset 2px 0 0 var(--accent,#2383E2) !important; }
.slash-item.selected .slash-item-name { color: var(--text); }
.slash-item-hint { font-size: 12px; color: var(--text-dim); opacity: .7; }
.sm-preview { font-family: inherit; }