fix: corrections UI — indicateur voute, couleurs, statut IA, spinner éditeur
1. Suppression du badge vault-context-pill doublon en mobile 2. Couleurs dynamiques indicateur header: - Bleu pour 'All' (.vault-ctx-all) - Mauve/violet pour les vaults (.vault-ctx-vault) - Jaune/ambre pour les répertoires (.vault-ctx-dir) 3. Statut IA: vérifie la présence du toolbar AI dans le DOM au lieu d'appeler /api/ai/status (qui ne fonctionnait pas) 4. Indicateur de traitement AI dans l'éditeur (spinner + badge 'AI...' dans le header de l'editor modal) au lieu du flash blanc sur le badge sync
This commit is contained in:
@@ -368,6 +368,10 @@ export async function createAIToolbar(container, getEditorView) {
|
||||
return;
|
||||
}
|
||||
showToast('⏳ AI: traitement en cours...', 'info');
|
||||
|
||||
// Show processing indicator in the editor header
|
||||
_showProcessingIndicator(true);
|
||||
|
||||
// Dispatch AI processing start event
|
||||
document.dispatchEvent(new CustomEvent('ai-processing-start', { detail: { endpoint, mode } }));
|
||||
try {
|
||||
@@ -384,10 +388,30 @@ export async function createAIToolbar(container, getEditorView) {
|
||||
showToast('AI: ' + msg, 'error');
|
||||
}
|
||||
} finally {
|
||||
_showProcessingIndicator(false);
|
||||
// Dispatch AI processing end event
|
||||
document.dispatchEvent(new CustomEvent('ai-processing-end'));
|
||||
}
|
||||
}
|
||||
|
||||
// ── In-editor processing indicator ──
|
||||
function _showProcessingIndicator(show) {
|
||||
let el = document.getElementById('ai-processing-indicator');
|
||||
if (show) {
|
||||
if (!el) {
|
||||
el = document.createElement('span');
|
||||
el.id = 'ai-processing-indicator';
|
||||
el.className = 'ai-processing-indicator';
|
||||
el.innerHTML = '<span class="ai-spinner"></span> AI...';
|
||||
el.title = 'Traitement AI en cours';
|
||||
const header = document.querySelector('#editor-modal .editor-header');
|
||||
if (header) header.appendChild(el);
|
||||
}
|
||||
el.style.display = 'inline-flex';
|
||||
} else if (el) {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
}
|
||||
// ── Keyboard shortcut Ctrl+J for inline completion ──
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.ctrlKey && e.key === 'j') {
|
||||
|
||||
@@ -72,6 +72,16 @@ function syncVaultSelectors() {
|
||||
if (contextText) {
|
||||
contextText.textContent = state.selectedContextVault === "all" ? "All" : state.selectedContextVault;
|
||||
}
|
||||
// Apply color class to the indicator
|
||||
const indicator = document.getElementById("vault-context-indicator");
|
||||
if (indicator) {
|
||||
indicator.classList.remove("vault-ctx-all", "vault-ctx-vault", "vault-ctx-dir");
|
||||
if (state.selectedContextVault === "all") {
|
||||
indicator.classList.add("vault-ctx-all");
|
||||
} else {
|
||||
indicator.classList.add("vault-ctx-vault");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-11
@@ -339,15 +339,15 @@ function _renderSyncPanel(panel) {
|
||||
let _aiProcessing = false;
|
||||
let _aiConfigured = null; // null = unknown, true/false
|
||||
|
||||
/** Check if AI is configured by calling the status endpoint. */
|
||||
async function _checkAIStatus() {
|
||||
try {
|
||||
const resp = await api('/api/ai/status');
|
||||
console.log('[AI Status] API response:', resp);
|
||||
_aiConfigured = !!(resp && resp.configured);
|
||||
} catch (e) {
|
||||
console.error('[AI Status] API call failed:', e);
|
||||
_aiConfigured = false;
|
||||
/** Check if AI is configured by looking for the AI toolbar in the DOM.
|
||||
* The toolbar is only rendered when the AI API responds successfully. */
|
||||
function _checkAIStatus() {
|
||||
const container = document.getElementById('ai-toolbar-container');
|
||||
if (container && container.children.length > 0) {
|
||||
_aiConfigured = true;
|
||||
} else if (_aiConfigured === null) {
|
||||
// Keep unknown state until we have evidence
|
||||
_aiConfigured = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +404,10 @@ function _updateAIStatusInPanel() {
|
||||
}
|
||||
}
|
||||
|
||||
/** Flash the sync badge white during AI processing. */
|
||||
/** Flash the sync badge white during AI processing.
|
||||
* NOTE: now handled via CSS class on #sync-badge.
|
||||
* The visual flash in the editor itself is handled by ai.js
|
||||
* which adds a processing indicator inline. */
|
||||
function _setBadgeAIProcessing(active) {
|
||||
const badge = document.getElementById('sync-badge');
|
||||
if (!badge) return;
|
||||
@@ -435,7 +438,8 @@ function _initAIStatus() {
|
||||
if (badge) {
|
||||
const origClick = badge.onclick;
|
||||
badge.addEventListener('click', () => {
|
||||
_checkAIStatus().then(() => _updateAIStatusInPanel());
|
||||
_checkAIStatus();
|
||||
_updateAIStatusInPanel();
|
||||
}, { once: false });
|
||||
}
|
||||
}
|
||||
|
||||
+68
-19
@@ -171,24 +171,48 @@ a:hover {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
cursor: default;
|
||||
transition: all 200ms ease;
|
||||
/* Default: neutral (overridden by classes below) */
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.vault-context-indicator:hover {
|
||||
background: color-mix(in srgb, var(--accent) 18%, transparent);
|
||||
border-color: var(--accent);
|
||||
filter: brightness(1.15);
|
||||
}
|
||||
.vault-context-indicator i {
|
||||
color: var(--accent);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* All vaults — blue */
|
||||
.vault-ctx-all {
|
||||
background: color-mix(in srgb, #3b82f6 14%, transparent) !important;
|
||||
border-color: color-mix(in srgb, #3b82f6 30%, var(--border)) !important;
|
||||
color: #60a5fa !important;
|
||||
}
|
||||
.vault-ctx-all i { color: #60a5fa !important; }
|
||||
|
||||
/* Specific vault — mauve/violet */
|
||||
.vault-ctx-vault {
|
||||
background: color-mix(in srgb, #a855f7 14%, transparent) !important;
|
||||
border-color: color-mix(in srgb, #a855f7 30%, var(--border)) !important;
|
||||
color: #c084fc !important;
|
||||
}
|
||||
.vault-ctx-vault i { color: #c084fc !important; }
|
||||
|
||||
/* Directory — amber/yellow */
|
||||
.vault-ctx-dir {
|
||||
background: color-mix(in srgb, #f59e0b 14%, transparent) !important;
|
||||
border-color: color-mix(in srgb, #f59e0b 30%, var(--border)) !important;
|
||||
color: #fbbf24 !important;
|
||||
}
|
||||
.vault-ctx-dir i { color: #fbbf24 !important; }
|
||||
|
||||
.hamburger-btn {
|
||||
display: none;
|
||||
background: none;
|
||||
@@ -2150,6 +2174,41 @@ select {
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* AI processing indicator — shown inside editor header during AI calls */
|
||||
.ai-processing-indicator {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
background: rgba(59, 130, 246, 0.3);
|
||||
border: 1px solid rgba(96, 165, 250, 0.4);
|
||||
animation: ai-indicator-pulse 1s ease-in-out infinite;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.ai-spinner {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 2px solid rgba(255,255,255,0.3);
|
||||
border-top-color: #ffffff;
|
||||
border-radius: 50%;
|
||||
animation: ai-spinner-spin 0.6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes ai-spinner-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes ai-indicator-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.6; }
|
||||
}
|
||||
|
||||
.editor-title {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 0.9rem;
|
||||
@@ -6825,22 +6884,12 @@ body.popup-mode .content-area {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Vault context indicator */
|
||||
/* Vault context indicator — hidden (now in header) */
|
||||
.vault-context-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 14px;
|
||||
background: var(--bg-primary);
|
||||
border-bottom: 1px solid var(--border);
|
||||
display: none !important;
|
||||
}
|
||||
.vault-context-pill {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
white-space: nowrap;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mt-btn {
|
||||
|
||||
Reference in New Issue
Block a user