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... +
@@ -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() {