diff --git a/frontend/editor-poc.html b/frontend/editor-poc.html
index cc07b7b..84e07a6 100644
--- a/frontend/editor-poc.html
+++ b/frontend/editor-poc.html
@@ -56,7 +56,7 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
.textarea::placeholder { color: var(--text3); }
/* Quick insert + */
-.qi-btn { position: absolute; left: 14px; top: 24px; width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--border); background: var(--bg2); color: var(--text3); cursor: pointer; font-size: 16px; font-weight: 700; display: flex; align-items: center; justify-content: center; z-index: 10; transition: all 100ms; }
+.qi-btn { position: fixed; top: 56px; left: 48px; width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--border); background: var(--bg2); color: var(--text3); cursor: pointer; font-size: 16px; font-weight: 700; display: flex; align-items: center; justify-content: center; z-index: 50; transition: all 100ms; }
.qi-btn:hover { color: var(--text); border-color: var(--accent); background: var(--accent-bg); }
/* Preview pane */
@@ -331,7 +331,9 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
Type / for commands | Alt+I Insert
Ctrl+J AI panel
Ctrl+S save
+ Ctrl+K link
✨ AI processing...
+ ✨ AI ready
@@ -436,6 +438,25 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
replaceLine(l.text.replace(/^\/\s*/, ''));
}
+ // ---- Tab indentation ----
+ function indentLine() {
+ var l = getLine();
+ if (/^(\s*)([-*]|\d+\.)\s/.test(l.text)) { replaceLine(' ' + l.text); }
+ else { insertAtCursor(' '); }
+ }
+ function dedentLine() {
+ var l = getLine();
+ if (/^ /.test(l.text)) { replaceLine(l.text.replace(/^ /, '')); }
+ }
+ function promptLink() {
+ var sel = val().substring(ta.selectionStart, ta.selectionEnd);
+ var url = prompt('URL:', 'https://');
+ if (url) {
+ if (sel) { wrapSelection('[', '](' + url + ')'); }
+ else { insertAtCursor('[text](' + url + ')', 1); }
+ }
+ }
+
// ---- Dirty / Save ----
function markDirty() {
if (!isDirty) { isDirty = true; updateSaveDot(); }
@@ -465,13 +486,13 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
isDirty = false; originalContent = content;
saveDot.className = 'save-dot ok'; saveLabel.textContent = 'Saved';
}).catch(function(e) {
- saveDot.className = 'save-dot err'; saveLabel.textContent = 'Error';
- showToast('Save failed: ' + e.message, 'err');
+ saveDot.className = 'save-dot err'; saveLabel.textContent = 'Erreur';
+ showToast('Echec sauvegarde: ' + e.message, 'err');
});
}
function forceSave() {
- if (!fileVault || !filePath) { showToast('No file loaded. Use ?vault=X&path=Y', 'err'); return; }
+ if (!fileVault || !filePath) { showToast('Aucun fichier charge.', 'err'); return; }
clearTimeout(saveTimer);
saveDot.className = 'save-dot saving'; saveLabel.textContent = 'Saving...';
var content = val();
@@ -484,8 +505,8 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
saveDot.className = 'save-dot ok'; saveLabel.textContent = 'Saved';
showToast('Saved', 'ok');
}).catch(function(e) {
- saveDot.className = 'save-dot err'; saveLabel.textContent = 'Error';
- showToast('Save failed: ' + e.message, 'err');
+ saveDot.className = 'save-dot err'; saveLabel.textContent = 'Erreur';
+ showToast('Echec sauvegarde: ' + e.message, 'err');
});
}
@@ -523,8 +544,8 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
schedulePreview();
})
.catch(function(e) {
- ta.value = '# Error\n\nCould not load: ' + (fileVault || '?') + '/' + (filePath || '?') + '\n\n' + e.message;
- statFile.textContent = 'Load error';
+ ta.value = '# Erreur\n\nImpossible de charger: ' + (fileVault || '?') + '/' + (filePath || '?') + '\n\n' + e.message;
+ statFile.textContent = 'Erreur chargement';
originalContent = ta.value;
updateStats();
});
@@ -538,8 +559,8 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
aiConfigured = s.configured === true;
updateAIButton();
if (aiConfigured) aiCall(endpoint, text, extra, callback);
- else { showToast('AI not configured', 'err'); hideAIProcessing(); }
- }).catch(function() { showToast('AI status check failed', 'err'); hideAIProcessing(); });
+ else { showToast('AI non configuree', 'err'); hideAIProcessing(); }
+ }).catch(function() { showToast('Verification AI echouee', 'err'); hideAIProcessing(); });
return;
}
showAIProcessing();
@@ -570,8 +591,13 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
}
function updateAIButton() {
- if (aiConfigured) { btnAI.className = 'btn btn-ai'; btnAI.title = 'AI Panel (Ctrl+J)'; }
- else { btnAI.className = 'btn btn-ai off'; btnAI.title = 'AI not configured'; }
+ if (aiConfigured) {
+ btnAI.className = 'btn btn-ai'; btnAI.title = 'AI Panel (Ctrl+J)';
+ document.getElementById('stat-ai-ready').style.display = 'inline';
+ } else {
+ btnAI.className = 'btn btn-ai off'; btnAI.title = 'AI not configured';
+ document.getElementById('stat-ai-ready').style.display = 'none';
+ }
}
function showAIProcessing() { statAI.classList.add('on'); }
@@ -646,7 +672,7 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
processPreviewBlocks();
_previewLoading = false;
}).catch(function(e) {
- previewContent.innerHTML = '
Render error: ' + e.message + '
';
+ previewContent.innerHTML = '
Erreur de rendu
';
_previewLoading = false;
});
}
@@ -1048,6 +1074,12 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
if (e.ctrlKey && e.key === 's') { e.preventDefault(); forceSave(); }
if (e.ctrlKey && e.key === 'b') { e.preventDefault(); wrapSelection('**'); }
if (e.ctrlKey && e.key === 'i') { e.preventDefault(); wrapSelection('*'); }
+ if (e.ctrlKey && e.key === 'k') { e.preventDefault(); promptLink(); }
+ // Tab: indent list items
+ if (e.key === 'Tab') {
+ e.preventDefault();
+ if (e.shiftKey) { dedentLine(); } else { indentLine(); }
+ }
// Quick Insert: Alt+I
if (e.altKey && e.key === 'i') { e.preventDefault(); showQI(); }
});
@@ -1177,6 +1209,8 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
loadFile();
checkAIStatus();
updateStats();
+ // Auto-focus after short delay (wait for iframe to fully render)
+ setTimeout(function() { ta.focus(); }, 200);
// ---- Process preview blocks (Mermaid + highlight.js) ----
function processPreviewBlocks() {