Editeur:
- sync() lisait el.textContent qui supprime les <br> : ajout de gt()
(innerText) utilise par sync(), tableaux (toggle/columns) et _resultText.
- Scission sur Entree + limites haut/bas de bloc via splitCaret() (marqueur
temporaire au curseur), plus de perte de fin de bloc multi-lignes.
Agent:
- fetch_provider_models() valide la liste nvidia : filtre des modeles
non-chat (nom) puis probe reelle /chat/completions (6 paralleles, 6s),
seuls les modeles 2xx restent. 429 conserve (route, donc utilisable).
- Repli sur la liste filtree si toutes les validations echouent.
- tests/test_llm_config.py : 5 cas (catalogue mock, 404 chat, autres
providers non valides, chute de securite, offline). 276 tests passent.
Shift+Entree insere des <br>; sync() lit textContent (des \n). mdEsc() (render
des blocs) n'encaissait pas les \n et le HTML les repliait en espace -> les
lignes disparaissaient au re-rendu apres la scission Entree.
mdEsc() convertit desormais les \n restants en <br> (apres les remplacements
markdown inline): ligne conservee pour tous les types de bloc.
v5.1.7
- Titre : data-placeholder="New Page" + bascule .empty a l'input (mecanisme des
blocs). Le placeholder s'affiche en gris pale quand le titre est vide, y compris
apres effacement. save() stocke un titre vide (plus de "New page" force), la
sidebar garde son fallback, duplicatePage retombe sur "New Page".
- Blocs : les placeholders ("Press 'space' for AI...", "Heading 1", "List"...)
passent sous :focus-within -> ne s'affichent que quand le bloc est focalise.
Idem pour "Type code..." du bloc code.
v5.1.6
La classe .empty (qui pilote les placeholders "Press 'space' for AI or '/' for
commands", "Heading 1", "List", etc.) n'etait basculee qu'au render(). Pendant
la frappe, l'evenement input mettait a jour dirty/autoSave mais jamais .empty :
le texte d'aide restait visible sur un bloc plein.
Le listener input des blocs bascule desormais .empty en direct : texte saisi ->
placeholder disparait; bloc vide -> placeholder reapparait.
v5.1.5
- 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
- AI (space) -> 400 DeepSeek: fdAgent.generate now uses the clean no-tools
/api/agent/generate endpoint instead of the tool-enabled conversation engine
(which sends tools/tool_choice schemas DeepSeek rejects). Fixes the composer,
Ask AI, AI meeting note and summarize flows.
- Slash menu arrows: selection highlight was invisible on open (nothing marked),
so up/down appeared dead. Call _rs() on open + after filtering, and give the
selected item an accent background + left bar. Verified with jsdom harness:
Down/Up move selection, Enter applies.
- Block outline when selected: suppress focus rings (outline/box-shadow) on all
editable blocks ([data-bid], .block-content, page title).
- Drag handle (6-dot): add .block-wrapper:hover/:focus-within .block-handle so
it shows on hover for normal blocks (only column-wrappers showed it before).
- Empty-block hint: brighter (--text-secondary, opacity .75) so the
"Press space for AI or / for commands" text is clearly visible on empty paras.
- VERSION + app.main -> 5.1.3; CHANGELOG updated.
- 271 tests pass; page renders 200; /api/agent/generate route registered;
JS validated (node --check + jsdom).
- Service serveur app/services/export.py: conversion blocs vers Markdown / HTML / PDF
- 4 endpoints: /api/export/markdown|html|pdf|site/{page_id}
- Export Markdown complet (tous les blocs + images + sous-pages recursives)
- Export PDF via xhtml2pdf (pur Python, aucune lib systeme)
- Export HTML standalone self-contained (styles inline)
- Export Site: zip multi-pages (index.html + une page par sous-page)
- UI: menu 'More > Export' dans l'editeur (Markdown, HTML, PDF, Site .zip)
- Tests: 190 passing (6 nouveaux)
The save() function's blocks.map() only copied 7 properties, missing:
embed_type, collection_id, dbs, file_name, file_size, file_mime.
Embed blocks lost their collection reference on save → page reload
showed empty page instead of database table.
Scripts in innerHTML don't execute per HTML spec. Instead, the render
function now scans for .block-embed-collection elements and calls
FlowDeckDB.renderInto() on each one via setTimeout after DOM update.
Clicking Database button now creates the table directly in the page
without asking for a name (uses 'Database' as default). Same pattern
as Notion: one click, inline embed, no popup.
The </script> tag inside a JS template literal was prematurely closing
the outer <script> block, causing 'Unexpected end of input' syntax error
and cascading Alpine.js 'not defined' errors.
- Page title placeholder: new pages created with empty title, CSS :empty::before shows 'New page' in gray
- Database is now inline embed within page (not full-page replacement)
- Embed block 'collection' renders database table via FlowDeckDB.renderInto()
- Open button in column 1 of each row opens page in side peek panel
- Side peek: iframe loading /pages/{id}?embed=1, close/fullscreen/resize
- DB scripts refactored as reusable DBInstance + global FlowDeckDB API
- Migration: add collection_id column to pages table
- POST /api/pages/{id}/convert-to-database: transforms page into database
- GET /api/collections/{id}/table-data: returns props + pages for table view
- POST /api/collections/{id}/pages: creates new row in collection
- New page_editor_collection.html template for database view
- _database_table.html: Notion-style table with columns, rows, New Page, Add Property
- Alpine.js component for cell editing, new page creation, property mgmt
- CSS: complete database table styling (view bar, table, cells, modals, dropdowns)
- Frontend: createDatabase() now converts page to full-page DB (was inline embed)
Now 3 shared modules (zero code duplication):
- _page_editor_content.html — editor HTML (title block, slash menu, toolbar etc)
- _page_editor_scripts.html — 100% original editorState() JS (CMDS, render,
save, slash, database, share/publish, favorites, formatting, etc)
- Used by page_editor.html (full page) and page_editor_embed.html (peek iframe)
Embed page_editor_embed.html now has the exact same editor as full page.
One change to _page_editor_scripts.html updates both views.