diff --git a/src/layout/melissa/MelissaBusca.vue b/src/layout/melissa/MelissaBusca.vue index 2a49552..8c1d981 100644 --- a/src/layout/melissa/MelissaBusca.vue +++ b/src/layout/melissa/MelissaBusca.vue @@ -14,7 +14,7 @@ * Quando promover pra produção: trocar a busca por chamada à RPC * `search_global` + manter a mesma estrutura de panel/items. */ -import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'; +import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'; import { supabase } from '@/lib/supabase/client'; import { useRecentPatients } from '@/composables/useRecentPatients'; @@ -161,22 +161,15 @@ function closePanel() { showPanel.value = false; query.value = ''; activeIndex.value = -1; - inputEl.value?.blur(); } -function onFocus() { +function openDialog() { showPanel.value = true; -} - -function onClickOutside(e) { - if (rootEl.value && !rootEl.value.contains(e.target)) { - showPanel.value = false; - activeIndex.value = -1; - } + // Foca input do Dialog após ele montar + nextTick(() => inputEl.value?.focus()); } function onKeydown(e) { - if (!showPanel.value) return; if (e.key === 'ArrowDown') { e.preventDefault(); activeIndex.value = Math.min(activeIndex.value + 1, flatList.value.length - 1); @@ -186,19 +179,15 @@ function onKeydown(e) { } else if (e.key === 'Enter' && activeIndex.value >= 0) { e.preventDefault(); selectEntry(flatList.value[activeIndex.value]); - } else if (e.key === 'Escape') { - // Stop bubbling pra ESC do parent não fechar overlay aleatório - e.stopPropagation(); - closePanel(); } + // Escape é tratado pelo Dialog (dismissableMask + closable) } function onGlobalKeydown(e) { - // Ctrl+K / ⌘+K → foca input + // Ctrl+K / ⌘+K → abre dialog if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); - showPanel.value = true; - inputEl.value?.focus(); + openDialog(); } } @@ -246,11 +235,9 @@ watch(query, (v) => { }); onMounted(() => { - document.addEventListener('mousedown', onClickOutside); window.addEventListener('keydown', onGlobalKeydown); }); onBeforeUnmount(() => { - document.removeEventListener('mousedown', onClickOutside); window.removeEventListener('keydown', onGlobalKeydown); if (debounceT) clearTimeout(debounceT); }); @@ -258,22 +245,45 @@ onBeforeUnmount(() => { @@ -438,16 +448,17 @@ onBeforeUnmount(() => { position: relative; width: 100%; max-width: 560px; - /* Só horizontal — top/bottom ficam livres pro parent (mt-X do Tailwind) */ margin-left: auto; margin-right: auto; font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; } +/* ─── Trigger no dock (visual de input, mas é botão que abre Dialog) ─── */ .mb-field { position: relative; display: flex; align-items: center; + width: 100%; background: var(--m-bg-soft); backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(140%); @@ -455,11 +466,12 @@ onBeforeUnmount(() => { border-radius: 12px; padding: 0 14px; height: 44px; + cursor: pointer; + text-align: left; transition: background-color 160ms ease, border-color 160ms ease; } -.mb-field:focus-within { +.mb-field:hover { background: var(--m-bg-soft-hover); - border-color: var(--m-border-strong); } .mb-field__icon { color: var(--m-text-muted); @@ -467,18 +479,15 @@ onBeforeUnmount(() => { margin-right: 10px; flex-shrink: 0; } -.mb-field__input { +.mb-field__placeholder { flex: 1; - background: transparent; - border: none; - outline: none; - color: var(--m-text, white); /* fallback white pro shell escuro do Melissa */ + color: var(--m-text-muted); font-size: 0.9rem; font-family: inherit; min-width: 0; -} -.mb-field__input::placeholder { - color: var(--m-text-muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .mb-field__kbd { color: var(--m-text-muted); @@ -493,26 +502,82 @@ onBeforeUnmount(() => { letter-spacing: 0.05em; } -.mb-panel { - position: absolute; - top: calc(100% + 6px); - left: 0; - right: 0; - z-index: 30; - max-height: 60vh; - overflow-y: auto; - /* Background do tema atual (claro ou escuro) — herda do PrimeVue - theme tokens. Antes era hardcoded escuro/transparente e ficava - texto-branco-em-fundo-branco no tema claro. */ +/* ─── Dialog Spotlight (PrimeVue Dialog customizado) ─── */ +:global(.mb-dialog__mask) { + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + background: rgba(0, 0, 0, 0.55) !important; +} +:global(.mb-dialog) { + border-radius: 14px !important; + overflow: hidden; + /* Posiciona mais alto que o centro (estilo Spotlight) */ + margin-top: 10vh !important; + align-self: flex-start; +} +:global(.mb-dialog .mb-dialog__content) { + padding: 0 !important; + background: var(--surface-card) !important; + border-radius: 14px !important; + overflow: hidden; + max-height: 70vh; + display: flex; + flex-direction: column; +} + +.mb-dialog__field { + display: flex; + align-items: center; + gap: 12px; + padding: 14px 18px; + border-bottom: 1px solid var(--surface-border); background: var(--surface-card); - backdrop-filter: blur(20px) saturate(140%); - -webkit-backdrop-filter: blur(20px) saturate(140%); + flex-shrink: 0; +} +.mb-dialog__field-icon { + color: var(--text-color-secondary); + font-size: 1.05rem; + flex-shrink: 0; +} +.mb-dialog__input { + flex: 1; + background: transparent; + border: none; + outline: none; + color: var(--text-color); + font-size: 1.05rem; + font-family: inherit; + min-width: 0; +} +.mb-dialog__input::placeholder { + color: var(--text-color-secondary); + opacity: 0.7; +} +.mb-dialog__esc { + color: var(--text-color-secondary); + font-size: 0.65rem; + font-weight: 500; + padding: 2px 8px; + border-radius: 4px; + background: var(--surface-ground); border: 1px solid var(--surface-border); - border-radius: 12px; + flex-shrink: 0; + letter-spacing: 0.05em; + opacity: 0.8; +} + +/* Panel agora vive DENTRO do Dialog (não mais absolute). Scroll interno + resolve o bug de overflow — o conteúdo nunca passa do bottom porque + o Dialog tem max-height e o panel é flex:1. */ +.mb-panel { + flex: 1 1 auto; + overflow-y: auto; + overflow-x: hidden; padding: 6px; - box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25); + background: var(--surface-card); scrollbar-width: thin; scrollbar-color: var(--surface-border) transparent; + min-height: 0; /* permite shrink no flex */ } .mb-panel::-webkit-scrollbar { width: 6px; } .mb-panel::-webkit-scrollbar-thumb { @@ -624,13 +689,4 @@ onBeforeUnmount(() => { flex-shrink: 0; } -.mb-fade-enter-active, -.mb-fade-leave-active { - transition: opacity 140ms ease, transform 160ms ease; -} -.mb-fade-enter-from, -.mb-fade-leave-to { - opacity: 0; - transform: translateY(-6px); -}