Commit graph

501 commits

Author SHA1 Message Date
Francisco Solla
4baa617c01
Merge pull request #610 from fsolla/C110-agenda-mobile-feedback-visual-do-arrasto-reveal-do-peri
C110 — feedback visual do arrasto na agenda mobile (reveal do período adjacente + commit/snap-back)
2026-08-10 15:02:53 -03:00
Francisco Solla
3b81431d39 refactor(C110): simplify — helpers de dominância/clamp, seed e2e generalizado, CSS sem regras mortas 2026-08-10 14:42:54 -03:00
Francisco Solla
b23a323f83 feat(C110): feedback visual do arrasto na agenda mobile — reveal do período adjacente + commit/snap-back 2026-08-10 13:51:55 -03:00
Francisco Solla
cc7dff88c4 feat(C100): lista unificada de pessoas em /campanha/pessoas
Merge por Contact (uma linha por pessoa física) de lideranças,
dobradinhas e staff, com capacidades como colunas; omnibox com
capacidade/município/apoio + filtros salvos (2º call site do B18 via
factory createSavedFilterStore); apagar pessoa com manifest de
confirmação e cascata transacional; mobile edge-to-edge (omnibox sem
bordas, cards com divisórias, salvar filtro no header). Sem migration.

Closes #495
2026-08-10 13:45:46 -03:00
Francisco Solla
89e7292529
Merge pull request #580 from fsolla/OPS22-ci-main-e2e-da-agenda-mobile-vermelho-desde-o-merge-do
OPS22 — fix: settle do chat desktop não vaza drawer para a visita mobile da mesma aba (CI main / deploy desbloqueado)
2026-08-10 13:35:07 -03:00
Francisco Solla
0fefbd0490
Merge pull request #604 from fsolla/OPS29-busca-global-sem-sugestoes-mostra-regiao-em-branco-est
fix(OPS29): estado vazio honesto na busca global sem sugestões curadas
2026-08-10 13:31:03 -03:00
Francisco Solla
04ce091b14 style(OPS22): prettier — ordena imports no provider do chat 2026-08-10 13:12:12 -03:00
Francisco Solla
5bc154dd20 fix(OPS22): settle do chat desktop não vaza drawer para a visita mobile da mesma aba — CI main verde (deploy desbloqueado) 2026-08-10 13:12:12 -03:00
Francisco Solla
fb7f85cd59 fix(OPS29): estado vazio honesto na busca global sem sugestões curadas (Closes #585)
- HomeSearchResultsShell renderiza 'Nenhuma sugestão ainda — priorize
  municípios na planilha de projeção' quando o suggest responde success
  sem hits (Início e FAB overlay compartilham o shell; SSR initialSuggest
  e POST cobertos); gateada por !isFetching para não falar sob o skeleton
- B126 e2e determinístico: pin um município priority alta claimado;
  testes OPS29 novos usam advisor sem carteira (scoped, imune a alta
  global de workers paralelos); settle de animação do overlay no B126
- unit: 3 casos novos no shell + overlap skeleton/mensagem
2026-08-10 12:54:16 -03:00
Francisco Solla
b210939226 refactor(B193): simplify fixes pós-revisão — mapper único de updates, API de trigger uniforme, grupos de relação extraídos, hardening do sheet host
- Extrai toMunicipalityUpdateViewModel/loadUpdateAuthorNames compartilhados
  (feed + batch da lista); remove avatarClassName morto.
- MunicipalityRelationTriggerProps compartilhado nos 3 wrappers; triggerClassName
  no ExpectedVotesControl; ChipLabel/RelationGroup/CityDash no card.
- Sheet host: cleanup de unmount no overlay (sem drawer órfão), registerFooter
  valida open, branch nulo do handleOpenChange limpa footer; chrome freeze
  documentado.
- A11y/UX: ícone de alerta no rodapé frio (WCAG 1.4.1), iniciais de avatar
  aria-hidden, chip sem_base sem target morto, label da cidade com Tendência,
  aria-label da barra anuncia os 3 cenários, card layout 'colocação · votos'.
- E2E: settleStream no B184 (flake da cópia transitória do streaming), cards
  ancorados por hasText (q= casa prefixos), cor da borda via classe do token.
2026-08-10 11:23:49 -03:00
Francisco Solla
3d8dbae61f feat(B193): card de município mobile denso com edit-where-you-see e rodapé de atualização expandível
- Card denso (wireframe): posição de voto à direita, barra de cenários com
  marcador do ativo, chips classe/tendência/nível (label à esquerda), 3 grupos
  de avatares com wrap (um por entidade), rodapé Última atualização + chevron
  que expande revelando o último card de atualização + CTA registrar; sem
  atualização → CTA direto; prioridade = borda lateral direita 6px primary.
- Controles ganham prop trigger/triggerClassName (precedente RelationChipCell);
  MunicipalityRelationAvatarStack ganha modo wrap.
- C109 (sheet quebra ao abrir) corrigida: sessões do sheet host keyed por id
  (imune à identidade dos callbacks recriados por render) e footer customizado
  renderizado pelo host dentro da árvore do Drawer (portal perdia o Dialog
  context — reproduzido digitando no sheet).
- Dado: MunicipalityListViewModel.lastUpdate (batch por página, scoped).
- E2E novos (barra/votos, chip nível, borda prioridade, expansão/CTA vazio).
Sem migration/access/Consent.
2026-08-10 11:23:49 -03:00
Francisco Solla
972c6ac8ba
Merge pull request #577 from fsolla/D7-sticky-dos-headers-da-tabela-desktop-quebrado-b41-morto-t
fix(D7): sticky dos headers das tabelas desktop volta a engajar (overflow-x-clip)
2026-08-10 09:52:54 -03:00
Francisco Solla
2fa38a08f5 style(B192): format (prettier) 2026-08-10 09:13:38 -03:00
Francisco Solla
382c4c46ec feat(B192): follow-ups sugeridos após cada resposta do Sollinha (bloco no prompt + chips extraídos) 2026-08-10 09:13:38 -03:00
Francisco Solla
00a4b7f0c7 fix(D7): sticky dos headers das tabelas desktop volta a engajar (overflow-x-clip)
O wrapper do ui/Table (`overflow-x-auto`, depois `overflow-x-hidden` via
container queries) é um scroll container nos dois eixos — o overflow-y computa
para `auto` — e o th `position: sticky; top: 0` declarado pelo B41 resolvia
contra ele, que nunca rola (o scroll vertical real é o CampaignContentScroll da
shell). A feature estava silenciosamente morta desde o B41.

`overflow-x: clip` (permitido ao lado de `overflow-y: visible`, sem promover
visible→auto) NÃO cria scroll container: o th volta a resolver contra o
scrollport da shell e engaja. Troca nas duas listas com sticky declarado
(MunicipalityList, TerritoryList), preservando o fallback `overflow-x-auto`
para browsers sem container queries. As demais listas (lideranças, demandas,
dobradinhas, apoiadores) estouram em 1440px e dependem do scroller — não
tocadas.

Validado nos 3 engines (Chromium/Firefox/WebKit): th 174 → 69 (topo do content
box do scrollport, padding da shell acima — mesmo ponto onde o omnibox mobile
do B184 cola). E2E novo pina o engajamento com asserção bilateral + guarda de
computed style; unit pinado no novo contrato; JSDoc do containerClassName
atualizado. Closes #543.
2026-08-10 09:11:38 -03:00
Francisco Solla
e9d7f0da39
Merge pull request #567 from fsolla/C109-quick-edit-sheet-mobile-da-lista-de-municipios-quebra-a
fix(campanha): quick-edit sheet mobile com footer custom quebrava ao abrir (C109)
2026-08-10 08:49:39 -03:00
Francisco Solla
5ad2f7c722 fix(campanha): quick-edit sheet mobile com footer custom quebrava ao abrir (C109)
O footer custom ('Registrar atualização' B42, 'Registrar movimento' E14) era
portalado da célula para o DrawerFooter do shared-sheet: createPortal preserva
o contexto React da origem (sem Drawer.Root), então o DrawerCloseButton
(base-ui DialogClose) crashava em useDialogRootContext() e o sheet nunca
renderizava.

O footer agora viaja no chrome do CampaignListSheetHost (mesmo mecanismo de
title/description) e é renderizado inline no DrawerFooter — contexto correto
por construção. O elemento continua criado na célula (estado do form e
associação form attribute preservados). footerPortalRef/attachFooterPortal/
hasCustomFooter removidos; fallback sem provider e popover intactos.

Cobertura: unit do shared path (abre/fecha/reabre + submit via form attribute)
e e2e mobile no describe B42 (abre, registra, fecha — incluindo o sheet do
nível E14).
2026-08-10 08:11:05 -03:00
Francisco Solla
7bdd7f91b1
Merge pull request #559 from fsolla/B187-sollinha-links-com-aparencia-de-link-nas-respostas
B187 — Sollinha: links com aparência de link nas respostas
2026-08-10 07:34:36 -03:00
Francisco Solla
1016668265 feat(B187): links com aparência de link nas respostas do Sollinha
Estilo de links no markdown do chat (primária + sublinhado + hover/foco),
externos abrem em aba nova; compõe com o next/link interno do B188.
Sem migration; e2e + unit cobrem a superfície.
2026-08-10 07:20:44 -03:00
Francisco Solla
1937688fc5
Merge pull request #555 from fsolla/C106-atualizacoes-mobile-feed-sem-moldura-omnibox-sticky-sem
C106 — Atualizações mobile: feed sem moldura (omnibox sticky sem label, criar no header, cards edge-to-edge)
2026-08-10 04:31:17 -03:00
Francisco Solla
74ccce432d
Merge pull request #554 from fsolla/B191-sollinha-acoes-rapidas-de-abertura-no-chat-chips-de-per
feat(B191): chips de pergunta de abertura no chat Sollinha
2026-08-10 04:15:38 -03:00
Francisco Solla
7eaa65ce03 feat(C106): atualizações mobile sem moldura — omnibox sticky, criar no header, cards edge-to-edge
- CSS de página (padrão C101): .campaign-updates-filter-strip sticky sob a
  top bar com linha separadora, :has() zera o padding-top do scroll container
- Chassis B127 ganha o hook estável data-slot=campaign-omnibox-field (sem
  mudança de comportamento)
- 'Nova atualização' vira icon no header via SetCampaignHeaderAction (slot
  C94/C95), gate de resolução 100% CSS (md:hidden); mesmo modal C89
- Cards edge-to-edge (-mx-4) sem borda, divisor de linha; corrigido o leak do
  @layer base editorial (ul my-6 ml-6 [&>li]:mt-2) que afetava a única lista
  campaign em <ul>
- Empty state com copy única descrevendo a ação
- E2E campaignUpdatesMobile (mobile + regressão desktop); impl plan + changelog
2026-08-10 04:12:23 -03:00
Francisco Solla
04951f6772 feat(B191): chips de pergunta de abertura no chat Sollinha (curados por papel e viewport)
- src/lib/sollinhaOpeningQuestions.ts: catálogo puro de chips de abertura
  (staff: 4 perguntas ancoradas nas tools atuais; leader: conjunto seguro
  sem tool eleitoral — fail-closed B180)
- ChatChipGroup: primitivo presentacional reutilizável (slot compartilhado
  com o B192)
- role do usuário flui do layout server pelo shell até o context do chat
- slot acima do input renderiza só com conversa vazia (messages 0 + ready);
  tocar envia via sendMessage e os chips somem no primeiro envio
- unit tests do catálogo + e2e (staff desktop 4 / mobile 3 / leader seguro)
2026-08-10 03:49:08 -03:00
fsolla
5abc0e0881 fix(C103): reaplica timeVisible/allDay do C104 perdidos no ciclo de rebase 2026-08-10 03:34:33 -03:00
Francisco Solla
acd522f035 feat(C103): agenda mobile — formulário de criação usável (sheet do topo, sem labels, salvar fixo, seletor em bottom sheet) 2026-08-10 03:34:33 -03:00
Francisco Solla
3ca200e7b0
Merge pull request #549 from fsolla/B184-municipios-mobile-lista-sem-moldura-omnibox-sticky-x-de
B184 — Municípios mobile: lista sem moldura (omnibox sticky, X de limpar no input, salvar filtro no header, cards edge-to-edge)
2026-08-10 03:30:25 -03:00
Francisco Solla
d60fe3867a
Merge pull request #552 from fsolla/C107-atualizacoes-mobile-sheet-de-criacao-usavel-altura-auto
C107 — Atualizações mobile: sheet de criação usável (altura auto até o topo, form sem labels com divisórias, placeholders, polaridade em toggle, checks à direita)
2026-08-10 03:29:43 -03:00
Francisco Solla
324e1c3c51 feat(B184): omnibox mobile sem moldura como padrão das listas (sticky no form, X de limpar no input, salvar filtro no header, cards edge-to-edge)
- Chassis CampaignListOmnibox (B127): abaixo de md a label some (input carrega
  aria-label), o campo perde borda/sombra (md: restaura), o form do filtro vira
  barra sticky com linha separadora (sticky no form porque não escapa do
  containing block — a coluna do input dentro do wrapper curto não grudava),
  o texto Limpar vira X circular dentro do input (chips OU busca; slot sempre
  renderizado com invisible; hit target 44px; live region de limpeza), botão
  texto Limpar desktop-only. Padrão para as 11 listas via
  campaignListOmniboxFormClassName.
- Municípios: Salvar filtro vira icon no header mobile (C94/C95 slot,
  presentation='icon', nome de rename = contrato 2.5.3); cards edge-to-edge
  com separador de linha (border-b last:border-b-0, -mx-4, gate md:).
- Atualizações: Nova atualização vai para o header mobile (único trailing
  mobile-visible que grudaria na barra).
- campaignMobileHeaderIconClassName compartilhada (3º consumidor).
- E2E mobile novo (390x844) com pins: foco/aria-expanded após limpar, salvar
  -> renomear no header, cards, desktop invertido.
- D7 registrado no caminho: sticky dos headers da tabela desktop morto.
2026-08-10 03:11:43 -03:00
Francisco Solla
c3f10cce23 feat(C108): sino de notificações — abrir marca tudo como lido, painel limpo, modal central no desktop
openCampaignNotifications (lista + marca em 1 round trip) substitui
listCampaignNotifications + markAllCampaignNotificationsRead; markAllNotificationsRead
extraída (owner-scoped, idempotente, cap 200) com int test; bell vira Dialog
desktop / Drawer mobile (par C94), sem título/rodapé/botões, skeleton de
loading, safe-area, focus-visible, role=alert; readAt sai do contrato do item;
P4-D ledger atualizado (batch sem transação agora no hot path, self-healing).
2026-08-10 02:56:20 -03:00
Francisco Solla
07464b8810
Merge pull request #548 from fsolla/B188-sollinha-contexto-da-conversa-persiste-na-sessao-da-jan
B188 — Sollinha: contexto da conversa persiste na sessão da janela/tab
2026-08-10 02:53:54 -03:00
Francisco Solla
c8e009b47a
Merge pull request #537 from fsolla/C104-agenda-compromisso-todo-o-dia-na-criacao-rapida-so-data
C104 — Compromisso 'Todo o dia' na criação rápida da agenda (só datas, multi-dia)
2026-08-10 01:37:56 -03:00
Francisco Solla
5380154dca fix(B188): simplify — settle não reabre chat fechado no reload desktop; prune com cabeça de pergunta; node fora do Link; mock SSE v7 no B167
- P1: B167 settle forçava open=true no load desktop mesmo com sessão restaurada
  open:false (storage auto-curava para true); restore agora vence quando existe
- prune: cabeça assistant quebra convertToModelMessages; drop até ancorar em user
- MarkdownLink: node do react-markdown não vaza para <Link>/<a>
- isUIMessage: parts com shape inválido falham-closed no restore
- B167 mock: chunk legado {"type":"text"} falha schema v7 (status preso em erro);
  agora usa start/text-start/text-delta/text-end/finish
2026-08-10 01:34:53 -03:00
Francisco Solla
9c1d4839b2
Merge pull request #539 from fsolla/agent/C101-ux-agenda-mobile-affordance-do-hoje-no-titulo-navegacao
C101-ux — Agenda mobile: navegação por teclado + affordance do tap no título
2026-08-10 01:17:05 -03:00
Francisco Solla
ca1dbb80f7 feat(B188): contexto da conversa do Sollinha persiste na sessão da janela/tab
- sessionStorage por aba: mensagens + estado aberto, restaurados no reload;
  escrita só em estado settle (nunca mid-stream); guardrail 50 msgs / 256 KB
- links internos (/campanha…) do markdown navegam via next/link (sem reload)
- e2e novo + ajuste do B167 (visita mobile nova agora loga em viewport mobile)
2026-08-10 01:13:25 -03:00
Francisco Solla
d52d001613 style(C104): format (prettier) 2026-08-10 01:13:12 -03:00
Francisco Solla
ea700e3113 feat(C104): compromisso 'Todo o dia' na criação rápida da agenda (só datas, multi-dia) 2026-08-10 01:13:12 -03:00
Francisco Solla
4e920ee064 feat(C107): sheet de criação de atualização usável no mobile — altura auto até o topo, form sem labels com divisórias full-bleed, placeholders, polaridade em toggle, checks à direita
- MunicipalityUpdateFields ganha layout 'labeled'|'list'; polaridade vira ToggleGroup Ruim|Neutra|Boa nas duas resoluções (mesmo dado, hidden input)
- layout 'list': labels sr-only, textarea sem borda, divisórias divide-y full-bleed, Urgente/Sinalizar adversário como linha tocável com check à direita
- StrictCombobox: prop placeholder (backward-compatible)
- Sheet do feed: max-h-dvh (teto no topo, rola por dentro), título sr-only, form lista com placeholders descritivos; desktop preservado
- Quick-edit B42 herda o visual no sheet mobile via layout
- unit/e2e atualizados para o toggle (radio)
2026-08-10 01:11:24 -03:00
Francisco Solla
f3c41d3382 feat(C101-ux): agenda mobile — navegação por teclado (região focável) + affordance do tap no título
- useAgendaKeyboardNavigation: ArrowLeft/Right → prev/next no mobile
  (FullCalendar v7 não tem setas no grid — verificado no bundle); skips
  para modificadores/dialog/menu/inputs; restore de foco na região
- Região de teclado mobile-only: tabIndex/role/aria-label gateados por
  isMobile (desktop mantém a toolbar e sua árvore a11y intacta)
- onTitleClick ganha icon?: LucideIcon (glyph da página, aria-hidden);
  agenda passa RotateCcw como affordance do 'voltar para hoje'
- E2E: teste de teclado (dia e mês), glyph no título, hardening do swipe
  CDP (pacing 25ms — burst era classificado como flick pelo Chromium e
  disparava back-nav ~35% das runs)
- Unit: 14 testes do hook/pura + 4 do renderer do glyph; impl plan
  docs/plans/c101-ux-pos-critique-impl.md (aprovado pelo humano)

Closes #512
2026-08-10 00:53:19 -03:00
Francisco Solla
cd41b44de4 feat(C105): tags no sheet da agenda + rótulo no evento + prefill no "Mais detalhes"
O filtro por tag na omnibox já existia (C94); o C105 completa a superfície da
agenda: campo de tags no overlay de criação inline (chips, sugestões das tags
já usadas), rótulo leve #tag no evento do calendário (oculto no mês/mobile) e
tags via prefill do "Mais detalhes" (params repetidos, parse fail-closed).

- ActivityTagInput extraído do ActivityForm (compartilhado, aria-label novo)
- "Mais detalhes" espelha estado vivo (horários editados + tags)
- popover do sheet com max-h --radix-popper-available-height (shift-before-flip
  do Radix clipava os campos do topo em viewports baixos)
- submit lê tags do estado espelho (fonte única), 4 KB cap p/ responsáveisJson
- limites mantidos 20/80 (C14), sem migration/access/Consent

Impl: docs/plans/agenda-tags-eventos-impl.md (aprovado no gate humano)
2026-08-10 00:21:20 -03:00
Francisco Solla
a7dce2c716
Merge pull request #516 from fsolla/C101-agenda-mobile-calendario-com-cara-de-app-nativo-context
C101 — Agenda mobile: calendário com cara de app nativo (contexto no header, navegação por arrasto, filtro sticky, dia na hora atual)
2026-08-09 22:43:12 -03:00
Francisco Solla
51fb715ec7 feat(C101): agenda mobile com cara de app nativo — contexto no header, swipe, filtro sticky, dia na hora atual
- toolbar do FullCalendar some no mobile; título do header mostra o período
  ("9 Agosto", "3–9 Agosto", "Agosto", "Agenda") e tap volta ao hoje
- navegação por arrasto horizontal (useAgendaSwipeNavigation): limiar 48px,
  claim 12px com preventDefault, touchcancel sintético contra o long-press
  do FC, dateClick do dia suprimido (C91/C15 intactos)
- filtro vira strip edge-to-edge sem rótulo, sticky sob a barra do app
  (containing block via :has no padding do scroll container)
- visão de dia com scroll interno (height fixa), 08:00 na abertura,
  cabeçalho do dia fixo, scroll preservado ao trocar de dia
- desktop inalterado; impl plan + plano pós-critique (C101-ux)
2026-08-09 22:09:47 -03:00
Francisco Solla
457aad5a21
Merge pull request #510 from fsolla/C102-mobile-sem-botao-sheet-de-sidebar-navegacao-pela-barra-
C102 — Mobile: sem botão/sheet de sidebar — navegação pela barra inferior + Mais
2026-08-09 19:56:07 -03:00
Francisco Solla
f0dff330bd feat(C102): sem hamburger/sheet de sidebar no mobile staff — navegação pela barra + Mais
No mobile (<768px) staff perde o botão de abrir sidebar na top bar
(CampaignMobileTopBar role-gated via useCampaignPageChromeRole +
isStaffCampaignRole; leader mantém) e o sheet de navegação deixa de
montar (CampaignSidebar early-return quando isMobile && staff).
Filtros salvos de Municípios (B18) migram para o drawer Mais
(MunicipalityNavSavedFilters variant 'overflow', mesma store,
apagar/desfazer/sucessão de foco; drawer ganha overflow-y-auto).

Correção de bug pré-existente (D4): o Toaster vivia dentro do wrapper
[contain:layout_paint] do painel da AI, que vira containing block para
position:fixed e stacking context próprio — toasts com ação (ex.
Desfazer) ficavam inalcançáveis sob os portais z-50 de drawer/sheet.
Movido para o root layout (campaign).

Testes: unit top bar (staff sem trigger / leader com trigger) + e2e
(staff sem trigger/dialog, leader com sheet, B18 no drawer completo).
2026-08-09 19:13:43 -03:00
Francisco Solla
27daa1339e feat(C99): toda conta campaignUser aponta para uma ficha Contact; lideranças ganham assessores responsáveis 2026-08-09 19:12:35 -03:00
Francisco Solla
dff940681d fix(B182): PWA iOS — heal do zoom preso do visual viewport no standalone
Motor client-side (standalone-iOS only, no-op em aba/desktop):
heal imediato no install + launch/bfcache/resume/pós-teclado/resize,
scrollTo(0,0) + re-measure nudge, retry ≤3×250ms por episódio,
pinça preservada (janela renovada por gesture*/touch ≥2), debug
global para verificação em aparelho, fallback maximum-scale off.

40 testes unit (jsdom) pinam detecção, guards, retry e teardown.
2026-08-09 18:50:00 -03:00
Francisco Solla
fdedfa9ad4 feat(C97): seletor shadcn de dia+horário 24h no popover de criação rápida da agenda
Troca o datetime-local nativo (AM/PM no idioma do browser, horário pouco
confiável) por ActivityDateTimeField: trigger com rótulo civil
dd/mm/aaaa às hh:mm + popover com Calendar (react-day-picker 9.7,
timeZone America/Bahia, locale pt-BR) e selects Hora 00-23 / Minuto
em passos de 15. Contrato de valor e submit inalterados; prefill do
slot mantido. Novo ui/Calendar.tsx (variante radix-nova), helpers
puros em campaignTime.ts. Sem migration. Closes #482 (PR).
2026-08-09 15:13:15 -03:00
Francisco Solla
07b4509e42 feat(campaign): Tendência migra para Ações ao colapsar a coluna (B172)
Em /campanha/municipios (staff), abaixo de 60rem do container a coluna
Tendência some inteira (hidden @min-60:table-cell no th+td, invertendo a
decisão B158 'container query nunca duplica' só para Tendência) e o mesmo
editor monta como ícone compacto na coluna Ações, ao lado do de atualização;
acima de 60rem volta o badge completo e Ações é gated fechado quando nada
está oculto manualmente. Ações torna-se sempre montada para staff e pinada
por ocultação manual no B17. Uma instância visível do editor por linha por
faixa (dual-render CSS-gated, sem JS/resize). Sem migration. Closes #446.
2026-08-09 13:36:04 -03:00
Francisco Solla
dff3a9e8b1 feat(C95): seletor de modo de visualização no header do app (agenda)
- view=week|day|month|list no contrato URL da agenda (canônico, fail-closed)
- seletor compacto 'Semana ▾' no header desktop e mobile (slot C94/C95)
- FullCalendar headerToolbar sem os 4 botões de modo; escolha vence resize
- effect normaliza a vista também quando a URL perde o param (sem vista órfã)
- useNarrowMeasured(breakpoint) em hooks/use-mobile (settle de hidratação)
- e2e reescrito no seletor + persistência + escolha-vence-resize + estabilização
  dos waits de slot (grid lazy do FullCalendar substitui gridcells no load)
2026-08-09 12:34:04 -03:00
Francisco Solla
6c34da4a47
Merge pull request #488 from fsolla/B178-salvador-cidade-agregada-no-campanha-pagina-virtual-lin
fix(B178): review do simplify — ordenação de nulls nativos, mapa sem slug da cidade, a11y e testes de borda
2026-08-09 10:53:46 -03:00
Francisco Solla
d8ee2dbafa fix(B178): review do simplify — nulls nativos em DESC, mapa sem slug da cidade, sr-only morto, sinal mobile, paginação/edges testados 2026-08-09 10:40:18 -03:00