From 622c14150d10a66b2b57d9467dfbc3f81b3e6238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Ign=C3=A1cio=20Fontoura=20Solla?= Date: Wed, 29 Jul 2026 16:07:43 -0300 Subject: [PATCH] chore: format ancorar-busca-acoes-inicio-mobile plan (pre-push). --- .../ancorar-busca-acoes-inicio-mobile.md | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 docs/plans/ancorar-busca-acoes-inicio-mobile.md diff --git a/docs/plans/ancorar-busca-acoes-inicio-mobile.md b/docs/plans/ancorar-busca-acoes-inicio-mobile.md new file mode 100644 index 00000000..668fab8a --- /dev/null +++ b/docs/plans/ancorar-busca-acoes-inicio-mobile.md @@ -0,0 +1,120 @@ +# Ancorar busca + ações do Início no limite inferior (mobile) + +Status: rascunho +Atualizado em: 2026-07-29 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B — **B65**; follow-up do chassis UX-1 / B46) +Impeccable: B — encaixe de layout em `CampaignHomeLayout` / shell do Início sob tema `campaign` +Appetite: ~0,25–0,5 dia eng; CSS/altura do chrome do Início; sem migration +Responsável: — + +## Design (Impeccable) + +Âncoras: `PRODUCT.md` (Clarity under pressure; Feel the action; alvos de toque no campo) / `DESIGN.md` · primitivo **B46** + busca **B47** · tema `data-theme='campaign'`. + +Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. + +Brief compacto: + +- **Persona / contexto:** CG/assessor no celular — polegar na metade inferior; o conjunto busca + strip de ações precisa estar no limite inferior do viewport útil (acima da bottom nav), não flutuando no meio/topo porque a coluna não preenche a altura. +- **Job principal:** alcançar ações e busca sem alongar o polegar; em `md+` manter o layout atual (busca → ações no topo). +- **Estratégia de cor:** Restrained — sem mudança visual além de posição. +- **Edit where you see:** não — chrome de launcher. +- **Anti-goals:** `fixed`/`sticky` que tapa a bottom nav ou o Sheet da sidebar; misturar viewport (`md`) com pointer; reabrir ordem ações↔busca do B46/B47; redesenhar `CampaignPageShell` global. + +## Dados → decisão → apresentação + +Dados: N/A — posicionamento de chrome; sem KPI/série. + +## Contexto + +**B46 ✓** entregou `CampaignHomeLayout` com spacer `flex-1` (`md:hidden`) + `order-*` (mobile: ações → busca; `md+`: busca → ações) e `CampaignPageShell` com `min-h-full`. **B47 ✓** pluga a busca no mesmo layout e esconde spacer/strip no modo focado. + +**Pedido de produto (2026-07-29):** o conjunto barra de busca + lista de ações deve ficar alinhado ao **limite inferior** no mobile; tablet/desktop permanece como está. + +**Por que B46 não teve sucesso:** o spacer `flex-1` só empurra o dock se o flex container tiver **altura definida maior que o conteúdo**. A cadeia atual é: + +1. `data-slot="campaign-content-scroll"` — `min-h-0 flex-1 overflow-y-auto` + `pb-24` (reserva da bottom nav) em [`layout.tsx`](<../../src/app/(campaign)/campanha/(app)/layout.tsx>). +2. `CampaignPageShell` — `min-h-full` (percentual). +3. `CampaignHomeLayout` — `min-h-full` + spacer. + +Em scrollport com altura definida pelo flex do `SidebarInset`, filhos com só `min-h-full` / `%` frequentemente **não** herdam a altura do viewport visível (altura do containing block ainda “depende do conteúdo” para resolução de `%`). Resultado: spacer colapsa → ações + busca ficam no topo do fluxo, não no limite inferior. O as-built de B46 resolveu a **ordem**, não a **âncora**. + +## Objetivos + +- No viewport **< `md`**, com Início **não** focado (query B47 inativa): o **grupo** strip de ações + barra de busca fica colado ao limite inferior do conteúdo útil (acima da bottom nav / `pb-24` do scroll), sem gap morto entre o grupo e esse limite. +- Em **`md+`**: comportamento visual inalterado (busca acima das ações, no topo do conteúdo). +- Modo focado **B47** intacto: spacer/strip ocultos; input sobe; resultados abaixo. +- Leader (só strip, sem busca) também ancora a strip no inferior no mobile. +- Sem migration / collection / Consent / server action / mudança de URL. +- Pin em unit (cadeia de classes / presença do dock) + checklist visual mobile (viewport ~390) no e2e existente ou asserção de layout leve se couber sem flake. + +## Decisões travadas + +- **Corrigir a cadeia de altura no chrome do Início — não inventar overlay `fixed`.** Opções rejeitadas: A) `position: fixed; bottom: …` para o dock (compete com `CampaignBottomNav`, Sheet, teclado virtual, safe-area — B46 já rejeitou); B) `sticky bottom` sem preencher a coluna (ainda deixa o bloco no topo do fluxo quando o conteúdo é curto). **Escolhido:** fazer o shell do Início **preencher o scrollport** (`h-full` / flex fill na cadeia local) e ancorar o grupo com spacer `flex-1` **ou** `mt-auto` no wrapper do dock — o que o craft medir como estável. Escopo = Início (`page.tsx` + `CampaignHomeLayout` / `CampaignHomeStaffChrome`), não o scroll global de todas as rotas. +- **Breakpoint continua viewport `md`, não pointer** (herda B46). **Rejeitado:** `pointer-coarse` → bottom. +- **Ordem relativa B46/B47 intacta** (mobile: ações → busca; `md+`: busca → ações). Este item só ancora o **conjunto**. **Rejeitado:** inverter ordem neste slice sem pedido novo. +- **Âncora acima da bottom nav** — respeitar `pb-24` + `env(safe-area-inset-bottom)` já no nav; não cobrir a barra. **Rejeitado:** reduzir `pb-24` “para colar mais” sem medir o `min-h-12` + label da bottom nav. +- **i18n:** ids/slots em inglês (`home-dock`, `home-thumb-spacer`, …); copy intacta. + +## Questões em aberto + +- **`h-full` na cadeia vs `min-h-[calc(100dvh-…)]` no layout do Início?** **Opções:** A) `h-full`/`min-h-0`/`flex-1` do scrollport → shell → chrome → layout (puro flex) | B) `min-h` com `calc(100dvh − header − bottom-nav)` no layout | C) `dvh` só no spacer. **Recomendação:** **A** — a altura do scroll já é definitiva via `h-svh` + flex no `SidebarInset`; propaga sem hardcodar header/nav. B/C quebram com teclado virtual / mudança de chrome. Se A falhar num browser alvo, cair para B só no Início com constantes nomeadas ao lado do `pb-24`. _(assumido — validar no craft)_ + +## Abordagem proposta + +```mermaid +flowchart TB + Scroll["campaign-content-scroll
altura definitiva flex"] + Shell["CampaignPageShell
h-full no Início"] + Chrome["CampaignHomeStaffChrome / Layout
flex col fill"] + Spacer["spacer flex-1 md:hidden"] + Dock["grupo ações + busca"] + Scroll --> Shell --> Chrome + Chrome --> Spacer --> Dock +``` + +Componentes: + +- **`CampaignHomeLayout`** (`src/components/campaign/dashboard/CampaignHomeLayout.tsx`): garantir fill no mobile (`h-full` / `min-h-0` + flex); manter spacer; opcional wrapper `data-slot="home-dock"` em volta de actions+search com `mt-auto` **só se** o spacer sozinho continuar frágil após a cadeia de altura — depth check: um mecanismo, não dois. +- **`CampaignHomeStaffChrome`** / **`page.tsx`**: propagar `h-full`/`min-h-full` no shell do Início (`CampaignPageShell className`) para o fill chegar no layout; não alterar `gap-8` do shell nas outras rotas. +- **`campaign-content-scroll`:** só tocar se inevitável (ex. `flex flex-col` + filho Início `flex-1`) — e **somente** com guard que não quebre listas longas (ou limitar a classe ao Início via wrapper na page, preferível). +- **Testes:** estender `tests/unit/campaignHomeLayout.unit.spec.ts` (cadeia / dock / focused esconde spacer); smoke visual ou asserção de geometria no e2e do Início se estável. +- **Migration:** Sem migration, sem collection, sem server action. + +## Dependências + +- Dura de código: **B46 ✓** + **B47 ✓** (layout e slots existem). Nenhuma seta dura de item aberto. +- Soft: **B58** (polimento visual da strip — independente da âncora); **B56** (resumo no topo — quando landar, o fill deve empurrar o dock, não o resumo, para baixo: spacer entre resumo e dock). + +## Não escopo + +- Polimento de rótulos/heading/scrollbar da strip → **B58**. +- Resultados / grid da busca → **B48–B54**. +- Wizards → **B59+**. +- Redesign da bottom nav ou do `pb-24` global. +- Inversão da ordem ações↔busca. + +## Rabbit holes + +- **`100dvh` / teclado virtual iOS.** Se alguém “só completar” com calc de viewport: o dock sobe por cima do teclado ou deixa buraco. **Mitigação:** preferir altura do scrollport flex; não amarrar ao `dvh` na v1. +- **Tornar `campaign-content-scroll` `display:flex` em todas as rotas.** Listas longas + `flex-1` em filhos errados quebram scroll. **Mitigação:** fill só no subtree do Início. +- **Reabrir B46 como reopen no roadmap.** **Mitigação:** item novo **B65** com diagnóstico; B46 permanece ✓ (ordem/slots). + +## Adiado com gatilho + +- **Ajuste fino do `pb-24` vs altura real da bottom nav.** Revisitar se, após o dock ancorar, ainda sobrar gap >~8 px ou colisão com a nav em device real (medir `CampaignBottomNav` + safe-area). +- **Dock quando B56 colocar resumo no topo.** Revisitar no craft do B56: spacer entre briefing e dock (não entre header e briefing). + +## Referências + +- `docs/roadmap.md` (B46 ✓, B47 ✓, B65) +- [posicao-botoes-acao-inicio-thumb-zone.md](posicao-botoes-acao-inicio-thumb-zone.md) — as-built que não ancorou +- [busca-global-inicio-input.md](busca-global-inicio-input.md) — modo focado / slots +- `src/components/campaign/dashboard/CampaignHomeLayout.tsx` +- `src/components/campaign/dashboard/CampaignHomeStaffChrome.tsx` +- `src/app/(campaign)/campanha/(app)/page.tsx` +- `src/app/(campaign)/campanha/(app)/layout.tsx` (`campaign-content-scroll`, `pb-24`, `CampaignBottomNav`) +- `src/components/campaign/shell/CampaignPageShell.tsx` +- `tests/unit/campaignHomeLayout.unit.spec.ts` +- `PRODUCT.md` / `DESIGN.md` — Field Desk / Clarity under pressure +- AGENTS.md — naming; Feel the action