, correção de UX para gerara prévia do romaneio
This commit is contained in:
@@ -1,44 +1,101 @@
|
||||
<%# ── Prévia do PDF ───────────────────────────────────────────────────────
|
||||
<details> NATIVO, e não um modal controlado por Stimulus. Isto é o
|
||||
conserto de um problema que voltou três vezes: a prévia era o ÚNICO jeito
|
||||
de conferir a folha antes de imprimir e morria junto com o JavaScript.
|
||||
Quando os assets do servidor ficaram 404 (precompile que não rodou no
|
||||
deploy), o botão "Ver prévia do PDF" não fazia nada e o operador ficava
|
||||
sem saída — a tela abria normal, sem erro visível. Com <details> o
|
||||
abrir/fechar é do navegador: funciona com o JS quebrado, sem JS, e no
|
||||
celular.
|
||||
<%# Prévia do PDF em POP-UP, com navegação de veículo igual à do carrossel do
|
||||
motorista (setas grandes + contador "3 de 72").
|
||||
|
||||
`loading="lazy"`: o iframe só busca o PDF quando o bloco é aberto. É o que
|
||||
preserva a economia que o modal trazia (gerar PDF a cada carregamento da
|
||||
tela era o problema original) sem precisar de JS para preencher o `src`.
|
||||
── POR QUE É CSS PURO E NÃO JAVASCRIPT ────────────────────────────────────
|
||||
Abrir/fechar sai do `:target`: o botão é um link para `#previa` e o pop-up só
|
||||
aparece quando ele é o alvo da URL. As setas são links de verdade para
|
||||
`?veiculo=X#previa`, então trocar de folha mantém o pop-up aberto.
|
||||
|
||||
<iframe> e não <embed>/<object>: o CSP está em enforcing com
|
||||
`object_src :none`, e sem `frame_src` ele cai em `default_src :self` — o
|
||||
iframe de mesma origem passa, os outros dois não.
|
||||
Isso não é preciosismo: a prévia é a ÚNICA conferência antes de imprimir e
|
||||
já morreu três vezes junto com o JavaScript (assets 404 no servidor, com a
|
||||
tela abrindo normal e o botão sem reação). Do jeito atual ela funciona com o
|
||||
JS quebrado, sem JS, no celular, e continua endereçável — dá para mandar o
|
||||
link já com a prévia aberta.
|
||||
|
||||
O `data-romaneio-target="preview"` continua aqui de propósito: com o JS
|
||||
no ar, `atualizarPreview()` recarrega a folha depois de cada edição. Sem
|
||||
ele, basta fechar e abrir. %>
|
||||
<details class="bg-[#111] border border-white/5 rounded-2xl overflow-hidden"
|
||||
data-romaneio-target="overlay"
|
||||
data-action="toggle->romaneio#aoAbrirPreview">
|
||||
<summary class="cursor-pointer list-none px-4 py-3 min-h-[48px] flex items-center gap-2
|
||||
text-white hover:bg-white/5">
|
||||
<%= icone :visualizar, cor: nil, espaco: false %>
|
||||
Prévia do PDF — <span data-romaneio-target="tituloPreview"><%= @veiculo %></span>
|
||||
<span class="ml-auto text-xs text-gray-500">clique para abrir / fechar</span>
|
||||
</summary>
|
||||
`loading="lazy"` no iframe: fechado, o pop-up é `display:none` e o navegador
|
||||
NÃO busca o PDF. É o que preserva a economia de não gerar um documento a cada
|
||||
carregamento da tela.
|
||||
|
||||
<div class="px-4 pb-4 space-y-2">
|
||||
<div class="flex justify-end">
|
||||
<%= link_to 'Abrir em outra aba',
|
||||
pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||
target: '_blank', rel: 'noopener',
|
||||
class: 'text-sm text-gray-300 hover:text-white px-3 py-2 rounded-lg hover:bg-white/10' %>
|
||||
<iframe> e não <embed>/<object>: o CSP está enforcing com `object_src :none`
|
||||
e sem `frame_src`, então cai em `default_src :self` — o iframe de mesma
|
||||
origem passa, os outros dois não.
|
||||
|
||||
Fechar leva para `#sem-previa`, um id que não existe em lugar nenhum: o
|
||||
`:target` deixa de casar e o pop-up some sem o salto ao topo que um `href="#"`
|
||||
causaria. %>
|
||||
<% nomes = @veiculos.map(&:veiculo) %>
|
||||
<% posicao = nomes.index(@veiculo) %>
|
||||
<% anterior = posicao&.positive? ? nomes[posicao - 1] : nil %>
|
||||
<% proximo = posicao && posicao < nomes.size - 1 ? nomes[posicao + 1] : nil %>
|
||||
|
||||
<div id="previa" data-romaneio-target="overlay"
|
||||
class="hidden target:flex fixed inset-0 z-50 items-center justify-center p-3 sm:p-6
|
||||
bg-black/80 backdrop-blur-sm">
|
||||
|
||||
<%# O fundo escuro fecha ao ser clicado — um link cobrindo a área, atrás da
|
||||
caixa (que é `relative`). Sem isso, só o ✕ fecharia. %>
|
||||
<a href="#sem-previa" tabindex="-1" aria-label="Fechar prévia" class="absolute inset-0"></a>
|
||||
|
||||
<div class="relative w-full max-w-6xl h-[92vh] flex flex-col gap-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<h2 class="text-white font-semibold truncate">
|
||||
Prévia — <span data-romaneio-target="tituloPreview"><%= @veiculo %></span>
|
||||
</h2>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<%= link_to 'Abrir em outra aba',
|
||||
pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||
target: '_blank', rel: 'noopener',
|
||||
class: 'text-sm text-gray-300 hover:text-white px-3 py-2 rounded-lg hover:bg-white/10' %>
|
||||
<a href="#sem-previa" aria-label="Fechar prévia"
|
||||
class="min-w-[48px] min-h-[48px] flex items-center justify-center rounded-xl
|
||||
bg-[#1a1a1a] border border-white/10 text-white hover:bg-[#242424]">✕</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe data-romaneio-target="preview" loading="lazy"
|
||||
src="<%= pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo) %>"
|
||||
class="w-full h-[80vh] rounded-xl border border-white/10 bg-white"
|
||||
class="flex-1 w-full rounded-xl border border-white/10 bg-white"
|
||||
title="Pré-visualização do romaneio"></iframe>
|
||||
|
||||
<%# Controles no mesmo desenho do carrossel do motorista (redondos, 56px,
|
||||
próximo em laranja), mas como LINKS: cada folha é uma URL. Na ponta vira
|
||||
<span> apagado em vez de sumir — botão que some muda o layout no meio da
|
||||
conferência e o operador perde o alvo do clique. %>
|
||||
<div class="flex items-center justify-center gap-3">
|
||||
<% if anterior %>
|
||||
<%= link_to admin_romaneio_path(@romaneio, veiculo: anterior, anchor: 'previa'),
|
||||
'aria-label': "Folha anterior (#{anterior})",
|
||||
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
||||
bg-[#1a1a1a]/90 backdrop-blur border border-white/15 text-white
|
||||
hover:border-orange-500 transition-colors' do %>
|
||||
<%= icone :voltar, cor: nil, tamanho: 'w-6 h-6', espaco: false %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="w-14 h-14 rounded-full flex items-center justify-center
|
||||
bg-[#1a1a1a]/50 border border-white/10 text-gray-600 opacity-40">
|
||||
<%= icone :voltar, cor: nil, tamanho: 'w-6 h-6', espaco: false %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<span class="bg-[#1a1a1a] border border-[#2a2a2a] text-gray-200 text-sm font-semibold
|
||||
rounded-full px-4 py-2 whitespace-nowrap">
|
||||
<%= posicao ? posicao + 1 : 1 %> de <%= nomes.size %> · <%= @veiculo %>
|
||||
</span>
|
||||
|
||||
<% if proximo %>
|
||||
<%= link_to admin_romaneio_path(@romaneio, veiculo: proximo, anchor: 'previa'),
|
||||
'aria-label': "Próxima folha (#{proximo})",
|
||||
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
||||
bg-orange-500/90 backdrop-blur border border-orange-400 text-black
|
||||
hover:bg-orange-500 transition-colors' do %>
|
||||
<%= icone :avancar, cor: nil, tamanho: 'w-6 h-6', espaco: false %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="w-14 h-14 rounded-full flex items-center justify-center
|
||||
bg-orange-500/20 border border-orange-400/30 text-black/40 opacity-40">
|
||||
<%= icone :avancar, cor: nil, tamanho: 'w-6 h-6', espaco: false %>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user