mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 17:43:04 +00:00
Merge branch 'cursor/eb1e2048'
This commit is contained in:
commit
983d266012
9 changed files with 66 additions and 27 deletions
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,28 @@
|
|||
# Critique — MunicipalityList B41 (2026-07-27)
|
||||
|
||||
Provenance: Assessment A + B via isolated subagents. Browser skipped (no local server). Detector exit 0, 0 findings.
|
||||
|
||||
## AI slop
|
||||
|
||||
No — Territory mirror with domain comment.
|
||||
|
||||
## Strengths
|
||||
|
||||
- Sticky Município keeps orientation while scrolling staff columns
|
||||
- Desktop/mobile split preserved (cards = B42)
|
||||
- Chrome matches Territory (overflow shell, z-index corner)
|
||||
|
||||
## Issues addressed this session
|
||||
|
||||
- **P1 fixed:** removed conflicting `max-w-52` with `min-w-56` on sticky name cell (aligned to Territory `min-w-56` only)
|
||||
- **P3 fixed:** E10 comment no longer claims the table cannot scroll horizontally
|
||||
|
||||
## Deferred (plan rabbit holes / adiado)
|
||||
|
||||
- **P1 edge fade:** plan Adiado — shadow/edge fade indicating more columns; revisit if field reports discoverability miss
|
||||
- **P2 row-hover tint on sticky cell:** Territory parent rows same solid `bg-background`; skip until 3rd sticky call site
|
||||
- **P2 denser sticky content (badge wrap):** accepted for v1; B17 column picker mitigates
|
||||
|
||||
## Harden/optimize
|
||||
|
||||
Out (no form/action/empty; no perf signal)
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
# Scroll horizontal + coluna Município fixa na lista de municípios
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-07-26
|
||||
Status: entregue
|
||||
Atualizado em: 2026-07-27
|
||||
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B41)
|
||||
Impeccable: B — encaixe em `CampaignTable` / `MunicipalityList` (desktop/tablet); sem rota nova
|
||||
Appetite: ~0,5–0,75 dia eng; overflow-x + sticky left na 1ª coluna; reusa padrão de `TerritoryList`
|
||||
Responsável: —
|
||||
|
||||
**Revisão 2026-07-26 (auditoria pré-implementação):** questão aberta fechada — **A** (classes na column def `name` só; sem `stickyColumnId` no `CampaignTable` até o 3º call site). O wrapper desktop já usa `className="hidden overflow-visible md:block"` (sobrescreve o `overflow-hidden` do `CampaignTable`, como Territory) — **manter** ao trocar só `containerClassName` para `overflow-x-auto`.
|
||||
|
||||
**Revisão 2026-07-27 (as-built):** `MunicipalityList` → `containerClassName="overflow-x-auto"`; coluna `name` com `sticky left-0 z-20` (head) / `z-[5]` (cell) + `min-w-56 bg-background` (espelho Territory; `max-w-52` removido no polish — conflitava com `min-w-56`). Mobile cards intactos. Critique: 0 P0; P1 width fix aplicado; edge fade permanece Adiado; sticky top+left layering igual Territory (header pode grudar no scroller interno do `overflow-x-auto` — aceitável). Gate: tsc/lint/format/knip(P3 pré-existente)/cycles/540 unit/413 int/build; Aikido 0 findings (Opengrep exit 2 conhecido).
|
||||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (Clarity under pressure; anti spreadsheet) / `DESIGN.md` · sistema de listas Pass 2 W1 · precedente **B21 ✓** (`TerritoryList`).
|
||||
|
|
@ -50,7 +54,7 @@ O precedente já existe na página de territórios (**B21 ✓**): [`TerritoryLis
|
|||
|
||||
## Questões em aberto
|
||||
|
||||
- **Extrair helper de classes sticky para `CampaignTable`?** **Opções:** A) só classes nas column defs de municípios (e Territory já tem as suas) | B) prop `stickyColumnId` no `CampaignTable`. **Recomendação:** A no v1 (<3 call sites distintos de API); B quando B29/outras listas pedirem o mesmo seam. _(assumido.)_
|
||||
- **Extrair helper de classes sticky para `CampaignTable`?** **Resolvida (2026-07-26):** **A** — só classes nas column defs de municípios (Territory já tem as suas). **B** (`stickyColumnId` no `CampaignTable`) quando o 3º call site pedir o mesmo seam. _(assumido — validado na auditoria de implementação.)_
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
|
|
@ -91,7 +95,8 @@ Depth check: copiar o padrão Territory, não um grid library.
|
|||
## Adiado com gatilho
|
||||
|
||||
- **Sticky first column genérico no `CampaignTable`.** Revisitar no 3º call site (municípios + territórios + uma terceira).
|
||||
- **Sombra/edge fade indicando mais colunas à direita.** Revisitar se critique acusar descoberta fraca do scroll.
|
||||
- **Sombra/edge fade indicando mais colunas à direita.** Revisitar se critique acusar descoberta fraca do scroll (critique B41 2026-07-27 confirmou descoberta fraca — ainda Adiado até pedido de campo).
|
||||
- **Tint de hover na célula sticky.** Territory parent rows usam `bg-background` sólido; revisitar no 3º call site sticky (ou se a mesa reclamar da coluna “morta” sob hover).
|
||||
|
||||
## Referências
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -118,11 +118,11 @@ const VotePositionReadout = ({
|
|||
|
||||
/**
|
||||
* E10 classe. In the table only the pill is visible — spelling the factors out
|
||||
* under it made this the widest cell in a grid that cannot scroll
|
||||
* horizontally, so the "por quê" moves to the column's `cellTooltip` (hover,
|
||||
* focus and tap) and stays as `sr-only` text; the card has the width to show
|
||||
* it outright. Either way the class never reaches anyone as a bare verdict,
|
||||
* which is the one thing it must never be.
|
||||
* under it still bloats the sticky/dense row even with horizontal scroll,
|
||||
* so the "por quê" moves to the column's `cellTooltip` (hover, focus and tap)
|
||||
* and stays as `sr-only` text; the card has the width to show it outright.
|
||||
* Either way the class never reaches anyone as a bare verdict, which is the
|
||||
* one thing it must never be.
|
||||
*/
|
||||
const TerritorialClassReadout = ({
|
||||
municipality,
|
||||
|
|
@ -262,11 +262,12 @@ const municipalityListColumns = ({
|
|||
filterOptions={columnFilterOptions.name}
|
||||
showPriorityFilter={isStaffView}
|
||||
description={municipalityColumnDescriptions.name}
|
||||
className="sticky left-0 z-20 min-w-56 bg-background"
|
||||
>
|
||||
Município
|
||||
</MunicipalitySortableHead>
|
||||
),
|
||||
cellClassName: 'max-w-52 whitespace-normal',
|
||||
cellClassName: 'sticky left-0 z-[5] min-w-56 whitespace-normal bg-background',
|
||||
cell: (municipality) => (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Link
|
||||
|
|
@ -611,12 +612,10 @@ export const MunicipalityList = (props: MunicipalityListProps) => {
|
|||
})}
|
||||
</div>
|
||||
|
||||
{/* No inner scroller: the app shell's <main> scrolls, so the sticky header
|
||||
resolves against it. A sticky <th> can't paint the row border, hence the
|
||||
inset shadow standing in for it. */}
|
||||
{/* A sticky <th> can't paint the row border, hence the inset shadow. */}
|
||||
<CampaignTable
|
||||
className="hidden overflow-visible md:block"
|
||||
containerClassName="overflow-x-visible"
|
||||
containerClassName="overflow-x-auto"
|
||||
headerClassName="[&_th]:sticky [&_th]:top-0 [&_th]:z-10 [&_th]:bg-background [&_th]:shadow-[inset_0_-1px_0_var(--border)] [&_th:first-child]:rounded-tl-xl [&_th:last-child]:rounded-tr-xl [&_tr]:border-b-0"
|
||||
caption={
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ type CampaignTableProps<Row> = {
|
|||
caption?: ReactNode
|
||||
/** Outer wrapper (border/rounding live here). */
|
||||
className?: string
|
||||
/** `ui/Table` scroll container override (e.g. municipality's `overflow-x-visible`). */
|
||||
/** `ui/Table` scroll container class (default already includes `overflow-x-auto`). */
|
||||
containerClassName?: string
|
||||
/** `<thead>` override (e.g. sticky headers). */
|
||||
headerClassName?: string
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ const Table = ({
|
|||
containerClassName,
|
||||
...props
|
||||
}: React.ComponentProps<'table'> & {
|
||||
/** Escape hatch for the scroll container — e.g. `overflow-x-visible` so a
|
||||
* sticky header can resolve against the page scroller instead of this box. */
|
||||
/** Override the scroll container (default already includes `overflow-x-auto`).
|
||||
* Sticky-left columns keep that default; `overflow-x-visible` only when a
|
||||
* sticky header must resolve against the page scroller instead of this box. */
|
||||
containerClassName?: string
|
||||
}) => (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -249,8 +249,13 @@ describe('campaign visual foundation', () => {
|
|||
// B22: every one of the 10 staff columns carries a header explanation —
|
||||
// pinned in the `<thead>` only, since `cellTooltip` (e.g. "Classe") adds
|
||||
// its own triggers in the body.
|
||||
const [theadHtml] = html.split('<tbody')
|
||||
const [theadHtml, tbodyHtml = ''] = html.split('<tbody')
|
||||
expect(theadHtml.match(/data-slot="tooltip-trigger"/g)).toHaveLength(10)
|
||||
|
||||
// B41: horizontal scroll + sticky Município (Territory pattern).
|
||||
expect(html).toMatch(/data-slot="table-container"[^>]*class="[^"]*overflow-x-auto/)
|
||||
expect(theadHtml).toMatch(/sticky left-0 z-20[^"]*min-w-56[^"]*bg-background/)
|
||||
expect(tbodyHtml).toMatch(/sticky left-0 z-\[5\][^"]*min-w-56[^"]*bg-background/)
|
||||
})
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ describe('CampaignTable cellTooltip', () => {
|
|||
const html = renderTable()
|
||||
|
||||
expect(html).toContain('Seabra')
|
||||
// No wrapper at all: the municipality list runs with `overflow-x-visible`
|
||||
// and a sticky header, so an unrequested inline-flex span is a layout risk.
|
||||
// No wrapper at all: the municipality list uses overflow-x-auto + sticky
|
||||
// header/first column, so an unrequested inline-flex span is a layout risk.
|
||||
expect(html).not.toContain('inline-flex')
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue