fix: side peek des bases repasse en vanilla JS + largeur 1100px standard (v7.49.0)
- Panneau peek: les bindings Alpine (x-data absent du conteneur) rendaient loovverture et le redimensionnement inoperants -> cblage direct sur le document. - Helper unique window.fdWirePeekResize (app.js): pointer capture, 300px-90vw, clic=fermer, largeur persiste fd_peek_width partagee entre les 4 peeks. - database-table-container margin:0 (tableau colle a gauche, marge Library). - .lib-container remonte dans app.css (trash etait pleine largeur), .db-index 1100px. - ObsiGate verifie sans code: creation .xlsx OK (openpyxl, #186).
This commit is contained in:
@@ -2104,9 +2104,9 @@ applyAIBlocks(text){
|
||||
async _pickSyncedBlock(idx){
|
||||
const block=this.blocks[idx];if(!block)return;
|
||||
try{
|
||||
const r=await fetch('/api/synced-blocks');const d=await r.json();
|
||||
const r=await fetch('/board/api/synced-blocks');const d=await r.json();
|
||||
const items=d.synced_blocks||[];
|
||||
if(!items.length){this.showToast('No synced blocks yet. Create one first in Settings → Synced Blocks.');return;}
|
||||
if(!items.length){this.showToast('No synced blocks yet — create one from a Board page first.');return;}
|
||||
const names=items.map(function(s){return (s.title||'Untitled')+' (id:'+s.id+')';});
|
||||
const choice=window.prompt('Choose a synced block:\n\n'+names.join('\n'));
|
||||
if(!choice)return;
|
||||
@@ -2114,7 +2114,7 @@ applyAIBlocks(text){
|
||||
if(!match)return;
|
||||
const sid=parseInt(match[1]);
|
||||
if(!sid){this.showToast('Invalid synced block','error');return;}
|
||||
const sr=await fetch('/api/synced-blocks/'+sid);const sd=await sr.json();
|
||||
const sr=await fetch('/board/api/synced-blocks/'+sid);const sd=await sr.json();
|
||||
if(!sd||!sd.content){this.showToast('Synced block not found','error');return;}
|
||||
block.synced_id=sid;
|
||||
block._synced_content=sd.content||[];
|
||||
@@ -2545,4 +2545,34 @@ applyAIBlocks(text){
|
||||
if (window.Alpine) { Alpine.data('editorState', editorState); fdRefreshXData('editorState'); }
|
||||
else document.addEventListener('alpine:init', function () { Alpine.data('editorState', editorState); });
|
||||
window.editorState = editorState;
|
||||
|
||||
// ── Ctrl/Cmd + S : sauvegarder le document ────────────────────────
|
||||
// L'autosave (1,5 s) suffit pour la frappe au quotidien, mais on ne peut
|
||||
// pas fermer l'onglet « au bout d'un moment » en etant sur que tout est
|
||||
// parti. Le raccourci est attendu par tout le monde : il appelle le même
|
||||
// `save()` que l'autosave (meme endpoint, meme file hors-ligne) et rend
|
||||
// la main explicitement.
|
||||
// `window.E` survit aux navigations partielles : on exige donc que
|
||||
// l'editeur soit reellement monte (`#_blocksCt`) avant d'agir, sinon
|
||||
// Ctrl+S sauvegarderait un editeur detache depuis une autre page.
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey) return;
|
||||
if (String(e.key).toLowerCase() !== 's') return;
|
||||
var E = window.E;
|
||||
if (!E || !document.getElementById('_blocksCt') || typeof E.save !== 'function') return;
|
||||
e.preventDefault(); // sinon le navigateur ouvre « Enregistrer la page »
|
||||
if (E.canEdit === false) {
|
||||
if (E.showToast) E.showToast('This page is locked (read-only)', 'error');
|
||||
return;
|
||||
}
|
||||
if (E.saving) { if (E.showToast) E.showToast('Saving…'); return; }
|
||||
E.dirty = true;
|
||||
var notify = function () {
|
||||
if (E.showToast) E.showToast('Saved', 'success');
|
||||
else if (window.showToast) window.showToast('Saved', 'success');
|
||||
};
|
||||
try { E.save(notify); } catch (err) {
|
||||
if (E.showToast) E.showToast('Save failed', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user