diff --git a/docs/roadmap-resenha.md b/docs/roadmap-resenha.md index ebb34bc8..7f13ac44 100644 --- a/docs/roadmap-resenha.md +++ b/docs/roadmap-resenha.md @@ -30,6 +30,10 @@ código e os commits seguem em inglês, como o resto do repositório. ## Já existia no código (verificado, não construir de novo) +- **Busca com filtros** — servidor (`q`, `from`, `has`, `before`, `after`), + client de API e painel no `SearchPopover` já existiam completos. Só faltava + tradução, sintaxe embutida (`de:fulano`) e descoberta. + - **Animação de digitação** — `TypingIndicator.tsx`, três pontos `animate-bounce` escalonados em 0/150/300ms. - **Sons de call/stream** — `SoundController.tsx`, montado no `AppLayout`: @@ -79,6 +83,7 @@ fixas por `t('chave')`. O que faltar cai para o inglês sozinho. - Chat: composer e mensagens (placeholder, anexos, responder, reações) - Barra lateral: servidores, canais e menus de contexto - Lista de membros (grupos por cargo, carregamento) +- Busca (rótulos, filtros e sintaxe embutida) - Registro de auditoria e Estatísticas (nasceram bilíngues) ### Fila sugerida de tradução @@ -115,7 +120,6 @@ Escolhidas pelo dono, inspiradas no Discord. **Nenhuma iniciada.** | Feature | Tamanho | Observação técnica | |---|---|---| | **Fixar mensagens no canal** | Pequena | Tabela de fixadas por canal + rota de listagem; permissão natural é `MANAGE_MESSAGES` | -| **Busca com filtros** | Média | `SearchPopover` já existe; falta filtrar por autor, canal e presença de anexo — e índice no banco, senão fica lento quando o histórico crescer | | **Resposta rápida de voz (soundboard por atalho)** | Pequena | O soundboard já está pronto; falta só marcar favoritos e ligar a atalhos de teclado, sem abrir painel. Cuidado: o limite de repetição do servidor continua valendo e é o que impede virar metralhadora | | **Cargos com ícone e exibição separada** | Média | Cargos e cores já existem; falta ícone, o campo "exibir separadamente" e o agrupamento na lista de membros | diff --git a/packages/web/src/components/chat/SearchPopover.tsx b/packages/web/src/components/chat/SearchPopover.tsx index d6870b0b..c8bdbb0a 100644 --- a/packages/web/src/components/chat/SearchPopover.tsx +++ b/packages/web/src/components/chat/SearchPopover.tsx @@ -1,4 +1,6 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; +import { useT } from '../../i18n'; +import { parseSearchQuery } from '../../utils/searchQuery'; import { createPortal } from 'react-dom'; import { useFloatingPosition } from '../../hooks/useFloatingPosition'; import { isDmChannel, getChannelOrigin, getApiForOrigin } from '../../stores/spaceStore'; @@ -103,6 +105,7 @@ export function SearchPopover({ open, onClose, anchorRef, channelId, isDm, onJum }); const [query, setQuery] = useState(''); + const t = useT(); const [fromFilter, setFromFilter] = useState(''); const [hasFilter, setHasFilter] = useState(''); const [beforeFilter, setBeforeFilter] = useState(''); @@ -153,8 +156,16 @@ export function SearchPopover({ open, onClose, anchorRef, channelId, isDm, onJum }, [open, onClose]); const doSearch = useCallback(async (searchOffset = 0) => { - const trimmed = query.trim(); - if (!trimmed && !fromFilter && !hasFilter && !beforeFilter && !afterFilter) { + // Filtros digitados na consulta (`de:fulano`) valem sobre os do painel: + // quem acabou de escrever está expressando a intenção mais recente. + const parsed = parseSearchQuery(query); + const trimmed = parsed.text; + const effFrom = parsed.from ?? fromFilter; + const effHas = parsed.has ?? hasFilter; + const effBefore = parsed.before ?? beforeFilter; + const effAfter = parsed.after ?? afterFilter; + + if (!trimmed && !effFrom && !effHas && !effBefore && !effAfter) { setResults([]); setTotalCount(0); return; @@ -166,10 +177,10 @@ export function SearchPopover({ open, onClose, anchorRef, channelId, isDm, onJum const client = getApiForOrigin(origin); const params = { q: trimmed || undefined, - from: fromFilter || undefined, - has: hasFilter || undefined, - before: beforeFilter || undefined, - after: afterFilter || undefined, + from: effFrom || undefined, + has: effHas || undefined, + before: effBefore || undefined, + after: effAfter || undefined, offset: searchOffset, limit: 25, }; @@ -224,7 +235,7 @@ export function SearchPopover({ open, onClose, anchorRef, channelId, isDm, onJum type="text" value={query} onChange={(e) => setQuery(e.target.value)} - placeholder="Search messages..." + placeholder={t('search.placeholder')} className="input-embedded flex-1 text-[14px]" /> {query && ( @@ -257,30 +268,30 @@ export function SearchPopover({ open, onClose, anchorRef, channelId, isDm, onJum {showFilters && (