Refatora MelissaBusca pra usar PrimeVue Dialog em vez de popover
absolute. Resolve definitivamente o bug do panel estourar viewport
quando ha muitos resultados.
Mudancas:
1. Trigger no dock: input -> <button> com aparencia de input. Clica
ou Ctrl+K abre Dialog. Mantem placeholder + Ctrl+K kbd hint.
2. Dialog Spotlight: 640px max-width, posicionado 10vh do topo
(estilo Spotlight macOS / Linear / GitHub). Backdrop blur escuro,
dismissable mask, sem header, sem closable button (Esc cobre).
3. Input REAL dentro do Dialog: autofocus on open via nextTick.
Mantem v-model="query" + @keydown="onKeydown" (Arrow/Enter).
4. Panel de resultados: era position:absolute com max-height:60vh
(estourava em layouts com input perto do bottom). Agora vive
DENTRO do Dialog (flex:1, max-height:70vh no content), scroll
interno garantido por design — conteudo NUNCA passa do bottom
da pagina.
5. Remove: onClickOutside (dismissableMask cobre), Transition
mb-fade (Dialog tem sua animacao).
Comportamento end-user identico (Ctrl+K, navegacao com setas, Enter
seleciona, Esc fecha) mas visual + manutencao muito melhor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Texto branco hardcoded ficava ilegivel no tema claro do PrimeVue
(branco em branco). Tema escuro funcionava ok pq fundo era escuro.
Fix: troca cores hardcoded por CSS tokens do tema:
- mb-panel background: var(--surface-card)
- mb-panel border: var(--surface-border)
- mb-item color: var(--text-color)
- mb-item__sub color: var(--text-color-secondary)
- mb-group__title color: var(--text-color-secondary) com opacity
- mb-item hover: color-mix com p-primary-color 8%
Icones semanticos (patient pink, sessao indigo, doc sky, intake
orange) ficam mais saturados no tema claro e suavizados no escuro
via :root.app-dark selectors.
Input field do search bar mantem fallback `white` — ele fica no
shell escuro do Melissa (lockscreen-style), nao depende do tema
PrimeVue.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 fixes pedidos no teste manual:
1. Shape errado da RPC: search_global retorna { id, label, sublabel,
deeplink } pra TODOS os tipos, mas o codigo lia campos diretos
(nome_completo, paciente_nome, inicio_em, nome_original etc) que
nao existem -> resultados saiam "(sem nome)", sem datas.
Fix: filteredPacientes + rpcAppointments + rpcDocuments + rpcIntakes
agora usam label/sublabel direto. selectEntry extrai patient_id da
deeplink quando precisa.
2. Cores ilegiveis: fundo do panel transparente demais (var(--m-bg-medium)
nao tinha contraste em alguns temas). Fix: fundo solido rgba(20,22,32,
0.92), border 14% white, text 96% white pra label, 65% pra sub
(sobe pra 78% no hover/active). Group title 50% + bold pra hierarquia
clara.
3. Cor das sessoes: grupo "Sessoes" tinha icone cinza generico. Fix:
classes .mb-item__icon--{patient,sessao,doc,intake} com paleta
espelhando a agenda — sessao = indigo-500 (#a5b4fc texto +
rgba(99,102,241,0.20) bg, mesma cor do pickColor() padrao);
patient = pink-400; doc = sky-500; intake = orange-400.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ROADMAP item #1.3 #11. localStorage por user_id pra isolar sessoes
diferentes no mesmo browser. ROADMAP sugeria localStorage OU tabela
user_recent_access — escolhi localStorage por simplicidade (sem
migration adicional + zero round-trip por visita).
composables/useRecentPatients.js:
- useRecentPatients() — composable reativo Tipo A: items + hasItems
+ addVisit + remove + clear + refresh
- registerPatientVisit(patient) — helper stateless pra usar fora
de setup (ex: navigation guards, action handlers)
- Sincroniza entre instancias na mesma aba via CustomEvent + 'storage'
- Max 5 items. Dedup por id, novo no topo.
Wire-up de visita (registra ao carregar prontuario):
- MelissaPaciente.vue: registerPatientVisit no loadAll apos detail.load
- PatientProntuario.vue: registerPatientVisit em loadDetail apos p resolved
Wire-up de visualizacao (mostra quando query vazia):
- GlobalSearch.vue: grupo "Acessados recentemente" antes dos Atalhos.
goTo("recent") navega pra /therapist/patients/:id.
- MelissaBusca.vue: grupo "Acessados recentemente". emit('paciente')
reusando a logica do MelissaLayout que ja navega pra
/melissa/paciente?id=X.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fecha ROADMAP #1.3 #10 (busca global topbar). GlobalSearch.vue
classic+rail ja usava RPC. MelissaBusca era client-side preview com
fallback nas props (pacientes+eventos do dia) — agora consulta a
mesma RPC search_global com debounce 200ms + searchSeq pra descartar
respostas obsoletas.
3 grupos novos exibidos quando RPC retorna:
- rpc-appointments -> sessoes qualquer data (alem de "hoje")
- rpc-documents -> documentos por nome/tipo
- rpc-intakes -> cadastros recebidos
Pacientes mescla: RPC tem prioridade (todos os pacientes); props
mantida como fallback rapido (digitacao curta antes do debounce).
Emits estendidos: novos 'documento' + 'intake' alem dos existentes
'acao' + 'paciente' + 'evento'.
MelissaLayout atualizado:
- @paciente agora navega pra /melissa/paciente?id=X (antes ignorava
payload e so abria secao generica — bug existente)
- @documento abre prontuario do paciente com tab=documentos
- @intake abre /melissa cadastros-recebidos
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>