, Correçoes UX

This commit is contained in:
2026-08-28 16:14:38 -03:00
parent 19a0c7a302
commit 0e57e48214
7 changed files with 126 additions and 16 deletions

View File

@@ -5,10 +5,16 @@
<div class="grid grid-cols-1 sm:grid-cols-[minmax(0,1fr)_minmax(0,280px)] gap-3">
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">Buscar nesta folha</label>
<div class="flex gap-2">
<%# `min-w-0` no input é o que impede rolagem lateral no celular: um <input>
tem largura intrínseca (~20 caracteres) e `flex-1` NÃO encolhe abaixo
dela, porque o `min-width` padrão de um item flex é `auto`. Com o botão
ao lado, o par estourava para 487px numa tela de 393px e levava a página
junto. O `flex-wrap` é a segunda rede: em tela muito estreita o botão
desce em vez de espremer o campo. %>
<div class="flex flex-wrap gap-2">
<input type="search" placeholder="NF, nome ou bairro/rua…"
data-romaneio-target="busca" data-action="input->romaneio#filtrar"
class="flex-1 bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
class="flex-1 min-w-0 bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
placeholder-gray-600 focus:outline-none focus:border-orange-500 min-h-[48px]">
<%# Rótulo que descreve o que o controle faz (diretriz 2): limpa a BUSCA,
não o romaneio. %>

View File

@@ -4,10 +4,29 @@
paradas cada um tem, que é justamente a conferência que ele faz antes de
mandar imprimir.
Adapta ao dispositivo (diretriz 3): no celular vira faixa horizontal, porque
72 itens empilhados empurrariam a tabela para fora da primeira tela; no
desktop é coluna com rolagem própria, do lado da tabela. %>
<div class="bg-[#111] border border-white/5 rounded-2xl p-4 space-y-3">
── NO CELULAR É UM BLOCO RECOLHIDO (diretriz 3) ───────────────────────────
Aberto, este painel tem os 72 carros mais o campo de motorista e três botões:
media 1.160px de altura e empurrava a EDIÇÃO — busca, campo PLANO e a tabela
de paradas — para 1.330px e 1.533px de rolagem, ou seja, duas telas abaixo do
que o operador foi fazer ali. Medido em 28/08/2026 no iPhone.
Recolhido, o <summary> mostra o que importa de relance (carro atual e quantas
paradas) e a edição sobe para a primeira tela. Um toque abre a lista inteira.
NO DESKTOP NADA MUDA: o <summary> some (`lg:hidden`) e o conteúdo é forçado a
aparecer com `lg:block`, que vence o "esconder" nativo do <details> fechado —
continua a coluna sempre aberta ao lado da tabela. %>
<details class="bg-[#111] border border-white/5 rounded-2xl overflow-hidden">
<summary class="lg:hidden cursor-pointer list-none min-h-[56px] px-4 py-3 flex items-center gap-3
text-white hover:bg-white/5">
<span class="font-semibold truncate"><%= @veiculo %></span>
<span class="text-xs px-2 py-0.5 rounded-lg bg-white/5 text-gray-400 shrink-0">
<%= @romaneio.contagem_por_veiculo[@veiculo].to_i %> paradas
</span>
<span class="ml-auto text-xs text-orange-400 shrink-0">trocar veículo</span>
</summary>
<div class="lg:block p-4 space-y-3">
<div class="flex items-center justify-between">
<h2 class="text-white font-semibold text-sm">Veículos</h2>
<span class="text-xs text-gray-500"><%= @veiculos.size %> no plano</span>
@@ -108,4 +127,5 @@
</span>
<% end %>
</div>
</div>
</div>
</details>

View File

@@ -1,7 +1,9 @@
<%# app/views/consolidacoes/arquivadas.html.erb %>
<% content_for :title, 'Consolidações arquivadas' %>
<div class="flex items-center justify-between mb-6">
<%# flex-wrap pelo mesmo motivo do cabeçalho de consolidacoes/index: título longo
mais botão não cabem na largura de um celular e esticariam a página. %>
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
<h1 class="text-2xl font-bold text-white flex items-center gap-2"><%= icone :arquivadas, espaco: false %> Consolidações arquivadas</h1>
<%= link_to rotulo(:voltar, 'Voltar às ativas', cor: nil), consolidacoes_path,
class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px] flex items-center' %>

View File

@@ -3,9 +3,14 @@
<div data-controller="nota-avulsa"
data-nota-avulsa-buscar-url-value="<%= buscar_nf_consolidacoes_path %>">
<div class="flex items-center justify-between mb-6">
<%# `flex-wrap` nos DOIS níveis: no celular o título mais os três botões
("Arquivadas", "Nota avulsa", "+ Nova Consolidação") somam mais de 450px e
não cabem nos 393px da tela. Sem a quebra, eles esticavam a PÁGINA INTEIRA
para 732px e tudo — incluindo a lista de consolidações — passava a exigir
rolagem lateral. Medido em 28/08/2026 no iPhone. %>
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
<h1 class="text-2xl font-bold text-white flex items-center gap-2"><%= icone :consolidacoes, espaco: false %> Consolidações</h1>
<div class="flex gap-2">
<div class="flex flex-wrap gap-2">
<%= link_to rotulo(:arquivadas, 'Arquivadas', cor: nil), arquivadas_consolidacoes_path,
class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px] flex items-center transition-colors' %>
<% if policy(Consolidacao).create? %>

View File

@@ -584,7 +584,11 @@
info.textContent = de + '' + ate + ' de ' + linhas.length + ' ' + rotulo;
abas.querySelectorAll('button').forEach(function (b) {
const ativa = Number(b.dataset.pagina) === p;
b.className = 'px-3 py-1.5 rounded-lg text-xs font-semibold transition-colors ' +
// min-w/min-h 44px: são os alvos de toque mais apertados do sistema
// (medidos 63 abaixo de 44px no celular em 28/08/2026) e ficam lado a
// lado, então errar o número da página é fácil com o dedo em movimento.
b.className = 'min-w-[44px] min-h-[44px] px-3 py-1.5 rounded-lg text-xs font-semibold ' +
'inline-flex items-center justify-center transition-colors ' +
(ativa ? 'bg-[#f97316] text-white'
: 'bg-[#0a0a0a] text-gray-400 border border-white/5 hover:text-white');
});

View File

@@ -6,19 +6,31 @@
class="fixed inset-0 bg-black/70 z-30 hidden md:hidden"
onclick="toggleSidebar()"></div>
<%# Sidebar %>
<%# Sidebar
`flex flex-col` NÃO é decoração: é o que faz o menu ROLAR. O <nav> do meio
pede `flex-1 overflow-y-auto`, e `flex-1` só tem efeito dentro de um flex
container — sem isto o <nav> crescia com o conteúdo, nunca ganhava altura
limitada, o `overflow-y-auto` nunca ativava e a lista simplesmente
transbordava o painel sem barra de rolagem.
Caso real (28/08/2026, iPhone 393×852): 1.194px de menu dentro de 852px de
tela, com o último item terminando 324px ABAIXO da borda. Contatos, Grupos,
Envios, Eventos, Variáveis, WhatsApp e o **Sair** ficavam inalcançáveis no
celular — e no notebook de tela baixa também. %>
<aside id="sidebar"
class="fixed top-0 left-0 h-full w-64 bg-[#111111] border-r border-[#2a2a2a] z-40
flex flex-col
transform -translate-x-full md:translate-x-0 transition-transform duration-300">
<%# Logo / Marca %>
<div class="px-4 py-5 border-b border-[#2a2a2a]">
<%# Logo / Marca — `shrink-0`: num flex-col, um bloco de altura fixa ainda é
espremido quando o irmão rolável é grande demais. %>
<div class="px-4 py-5 border-b border-[#2a2a2a] shrink-0">
<%= image_tag '/logo-reem.png', alt: 'Reem Transporte',
class: 'h-14 w-auto mx-auto object-contain' %>
</div>
<%# Usuário logado %>
<div class="px-6 py-4 border-b border-[#2a2a2a]">
<div class="px-6 py-4 border-b border-[#2a2a2a] shrink-0">
<p class="text-xs text-gray-500 mb-1">Logado como</p>
<p class="text-white font-semibold text-sm truncate"><%= current_user.nome_display %></p>
<span class="inline-block mt-1 px-2 py-0.5 text-xs rounded-full
@@ -114,7 +126,9 @@
</nav>
<%# Footer da sidebar — sair %>
<div class="px-6 py-4 border-t border-[#2a2a2a]">
<%# Rodapé com o "Sair": shrink-0 para ele ficar ancorado embaixo, sempre
visível, em vez de rolar junto com a lista. %>
<div class="px-6 py-4 border-t border-[#2a2a2a] shrink-0">
<%= link_to destroy_user_session_path, data: { turbo_method: :delete, turbo_confirm: 'Deseja sair?' },
class: "flex items-center gap-2 text-gray-400 hover:text-red-400 text-sm transition-colors" do %>
<%= icone :sair, cor: nil, tamanho: 'w-5 h-5' %> Sair

View File

@@ -301,6 +301,64 @@ manual e pontual, mas é o primeiro candidato a virar download em segundo plano
o volume crescer ou se dois operadores baixarem ao mesmo tempo. **Não** compare
esse número com o do PDF de um veículo: são unidades diferentes (1 folha × 72).
## Caso 10 — Mobile: quebras visuais (varredura)
Roda em **todas** as telas do roteiro com `agent-browser set device "iPhone 16"`
(393×852), logado. São três medições objetivas; anote o número, não só passou/falhou.
### 10a — Rolagem horizontal
Nenhuma tela pode ter rolagem lateral no celular (diretriz 3: nada que exija zoom).
```bash
agent-browser set device "iPhone 16"
for u in /dashboard /dashboard/operacoes "/consolidacoes?visao=lista" "/consolidacoes?visao=motoristas" /admin/romaneios /admin/romaneios/13; do
agent-browser open "https://teste.reemtransportes.com.br$u" >/dev/null
agent-browser eval "document.documentElement.scrollWidth+'/'+document.documentElement.clientWidth"
done
```
**PASSOU se**: os dois números são iguais (ex.: `393/393`) em todas.
Para achar o culpado quando falhar:
```bash
agent-browser eval "(()=>{const vw=document.documentElement.clientWidth; return [...document.querySelectorAll('*')].filter(e=>{const b=e.getBoundingClientRect(); return b.right>vw+2 && b.width>40 && getComputedStyle(e).position!=='fixed';}).slice(0,5).map(e=>e.tagName+'.'+String(e.className).split(' ').slice(0,2).join('.')+' right='+Math.round(e.getBoundingClientRect().right)).join(' || ');})()"
```
> ⚠️ Causa recorrente: contêiner `flex` **sem `flex-wrap`** com botões que não cabem,
> ou `<input class="flex-1">` **sem `min-w-0`** (input não encolhe abaixo da largura
> intrínseca). Foram as duas causas de 28/08/2026.
### 10b — Menu inteiro alcançável
Todo item do menu tem que ser alcançável rolando — inclusive o **Sair**, o último.
```bash
agent-browser open "https://teste.reemtransportes.com.br/dashboard"
agent-browser snapshot -i | grep -i "menu" # pegar o ref do botão "Abrir menu"
agent-browser click @eN
agent-browser eval "(()=>{const nav=document.querySelector('#sidebar nav'); if(!nav) return 'NAV AUSENTE'; const ult=[...document.querySelectorAll('#sidebar a')].at(-1); return 'nav rola='+(nav.scrollHeight>nav.clientHeight)+' overflowY='+getComputedStyle(nav).overflowY+' | ultimo item: '+ult.textContent.trim()+' | fora da tela por '+Math.max(0, Math.round(ult.getBoundingClientRect().bottom-window.innerHeight))+'px';})()"
```
**PASSOU se**: `overflowY=auto` e "fora da tela por 0px" (o item pode estar abaixo
da dobra, desde que o `<nav>` role até ele).
**FALHOU se**: `overflowY=visible` ou o último item aparece fora por N px — foi o
bug de 28/08/2026, em que 7 itens (incluindo Sair) eram inalcançáveis no celular.
> O que segura isso é o `flex flex-col` no `<aside id="sidebar">`: sem ele o
> `flex-1 overflow-y-auto` do `<nav>` não tem efeito nenhum.
### 10c — Alvos de toque
```bash
agent-browser eval "(()=>{const p=[...document.querySelectorAll('a,button,input,select,summary')].filter(e=>{const b=e.getBoundingClientRect(); return b.height>0 && b.height<44;}); return p.length+' alvos <44px';})()"
```
**Linha de base após as correções de 28/08/2026** (iPhone 16): dashboard tinha
**63** antes do ajuste da paginação; as demais telas ficam entre 3 e 5. Um número
que **cresce** entre execuções é regressão — vale investigar o que foi
adicionado, não apenas registrar.
## Relatório final (obrigatório)
Terminar a execução com uma tabela e a lista de falhas:
@@ -317,6 +375,7 @@ Terminar a execução com uma tabela e a lista de falhas:
| 7 Notificações | … | … |
| 8 PIN motorista | … | … |
| 9 Performance | … | tabela de tempos |
| 10 Mobile (10a/b/c) | … | larguras, menu, alvos |
Depois da tabela, listar **somente as falhas**, cada uma com: URL, o que era
esperado, o que aconteceu (mensagem de erro/console) e o caminho do screenshot.