Alterações de fotos da simpleroute
This commit is contained in:
@@ -71,14 +71,12 @@
|
||||
|
||||
<div class="grid lg:grid-cols-3 gap-0">
|
||||
|
||||
<%# Coluna esquerda — fotos %>
|
||||
<%# Coluna esquerda — galeria com TODAS as fotos do lançamento %>
|
||||
<div class="p-5 border-b lg:border-b-0 lg:border-r border-white/5 space-y-3">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider">Foto da fachada</p>
|
||||
<div id="c-foto-wrap"></div>
|
||||
<div id="c-extras-wrap" class="hidden">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mt-4 mb-2">Fotos do SimpliRoute</p>
|
||||
<div id="c-extras" class="grid grid-cols-3 gap-2"></div>
|
||||
</div>
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Fotos do lançamento <span id="c-fotos-contador" class="normal-case font-normal text-gray-600"></span>
|
||||
</p>
|
||||
<div id="c-fotos" class="space-y-3"></div>
|
||||
</div>
|
||||
|
||||
<%# Coluna direita — campos click-to-edit %>
|
||||
@@ -105,6 +103,38 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%# Visualizador de foto — amplia e navega entre todas as imagens do lançamento %>
|
||||
<div id="modal-foto" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<div id="modal-foto-overlay" class="absolute inset-0 bg-black/85"></div>
|
||||
<div class="relative w-full max-w-3xl flex flex-col gap-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<p id="modal-foto-titulo" class="text-white font-semibold text-sm"></p>
|
||||
<div class="flex items-center gap-2">
|
||||
<a id="modal-foto-abrir" href="#" target="_blank" rel="noopener"
|
||||
class="px-3 py-2 rounded-lg bg-white/5 hover:bg-white/10 text-gray-300 text-xs inline-flex items-center">
|
||||
<%= icone :visualizar, cor: nil, tamanho: 'w-4 h-4' %> Tamanho real
|
||||
</a>
|
||||
<button id="modal-foto-fechar" type="button"
|
||||
class="w-9 h-9 rounded-lg bg-white/5 hover:bg-white/10 text-gray-300 flex items-center justify-center"
|
||||
aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-5 h-5', espaco: false %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative bg-[#151515] border border-white/10 rounded-2xl overflow-hidden">
|
||||
<img id="modal-foto-img" src="" alt="" class="w-full max-h-[70vh] object-contain bg-black">
|
||||
<button id="modal-foto-ant" type="button"
|
||||
class="absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/70 hover:bg-black
|
||||
text-white flex items-center justify-center" aria-label="Foto anterior">
|
||||
<%= icone :voltar, cor: nil, tamanho: 'w-5 h-5', espaco: false %>
|
||||
</button>
|
||||
<button id="modal-foto-prox" type="button"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/70 hover:bg-black
|
||||
text-white flex items-center justify-center" aria-label="Próxima foto">
|
||||
<%= icone :avancar, cor: nil, tamanho: 'w-5 h-5', espaco: false %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -202,34 +232,89 @@
|
||||
b.innerHTML = ico(cfg.icone) + ' ' + esc(cfg.label);
|
||||
}
|
||||
|
||||
// Etiqueta de cada tipo de imagem — o ADM precisa saber o que está olhando
|
||||
// para julgar se a foto está errada.
|
||||
// `cls` = etiqueta translúcida (foto em destaque, fundo escuro previsível).
|
||||
// `txt` = só a cor do texto, usada na miniatura sobre fundo preto sólido —
|
||||
// sobre foto clara a versão translúcida ficava ilegível.
|
||||
const ROTULO_FOTO = {
|
||||
fachada: { texto: 'Fachada', cls: 'bg-orange-500/20 text-orange-300 border-orange-500/40', txt: 'text-orange-300' },
|
||||
entrega: { texto: 'Comprovante', cls: 'bg-blue-500/20 text-blue-300 border-blue-500/40', txt: 'text-blue-300' },
|
||||
assinatura: { texto: 'Assinatura', cls: 'bg-purple-500/20 text-purple-300 border-purple-500/40', txt: 'text-purple-300' }
|
||||
};
|
||||
|
||||
function renderFotos() {
|
||||
const wrap = document.getElementById('c-foto-wrap');
|
||||
if (visita.foto_fachada) {
|
||||
wrap.innerHTML =
|
||||
'<a href="' + esc(visita.foto_fachada) + '" target="_blank" rel="noopener" title="Abrir em tamanho real">' +
|
||||
'<img src="' + esc(visita.foto_fachada) + '" alt="Fachada" loading="lazy" ' +
|
||||
'class="w-full h-52 object-cover rounded-xl border border-white/10 hover:opacity-90 transition-opacity">' +
|
||||
'</a>';
|
||||
} else {
|
||||
const fotos = visita.fotos || [];
|
||||
const wrap = document.getElementById('c-fotos');
|
||||
const cont = document.getElementById('c-fotos-contador');
|
||||
|
||||
cont.textContent = fotos.length ? '— ' + fotos.length + (fotos.length > 1 ? ' imagens' : ' imagem') : '';
|
||||
|
||||
if (!fotos.length) {
|
||||
wrap.innerHTML =
|
||||
'<div class="w-full h-52 rounded-xl border border-dashed border-white/10 flex items-center justify-center ' +
|
||||
'text-gray-600 text-sm">' + ico('camera-fill') + ' Sem foto da fachada para esta entrega</div>';
|
||||
'text-gray-600 text-sm">' + ico('camera-fill') + ' Nenhuma foto registrada neste lançamento</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
const extras = [...(visita.pictures || [])];
|
||||
if (visita.signature) extras.push(visita.signature);
|
||||
const extrasWrap = document.getElementById('c-extras-wrap');
|
||||
const grid = document.getElementById('c-extras');
|
||||
if (extras.length) {
|
||||
grid.innerHTML = extras.map(u =>
|
||||
'<a href="' + esc(u) + '" target="_blank" rel="noopener">' +
|
||||
'<img src="' + esc(u) + '" loading="lazy" class="w-full h-16 object-cover rounded-lg border border-white/10 hover:opacity-90">' +
|
||||
'</a>').join('');
|
||||
extrasWrap.classList.remove('hidden');
|
||||
} else {
|
||||
extrasWrap.classList.add('hidden');
|
||||
grid.innerHTML = '';
|
||||
}
|
||||
// A 1ª em destaque; as demais numa grade de 3. Clicar abre o visualizador.
|
||||
// Na miniatura a etiqueta é compacta e truncada (senão estoura a célula);
|
||||
// o rótulo completo + origem aparecem no visualizador.
|
||||
const figura = (f, i, destaque) => {
|
||||
const r = ROTULO_FOTO[f.tipo] ||
|
||||
{ texto: f.tipo, cls: 'bg-white/10 text-gray-300 border-white/20', txt: 'text-gray-300' };
|
||||
const etiqueta = destaque
|
||||
? '<figcaption class="absolute top-1.5 left-1.5 px-1.5 py-0.5 rounded text-[10px] font-bold uppercase ' +
|
||||
'tracking-wide border ' + r.cls + '">' + esc(r.texto) + '</figcaption>' +
|
||||
'<span class="absolute bottom-1.5 right-1.5 px-1.5 py-0.5 rounded bg-black/70 text-gray-300 text-[10px]">' +
|
||||
esc(f.origem) + '</span>'
|
||||
: '<figcaption class="absolute top-1 left-1 right-1 px-1 py-0.5 rounded text-[9px] font-bold uppercase ' +
|
||||
'tracking-tight truncate bg-black/80 ' + r.txt + '">' + esc(r.texto) + '</figcaption>';
|
||||
|
||||
return '<figure class="relative group cursor-zoom-in" data-foto-idx="' + i + '" ' +
|
||||
'title="' + esc(r.texto + ' · ' + f.origem) + ' — clique para ampliar">' +
|
||||
'<img src="' + esc(f.url) + '" alt="' + esc(r.texto) + '" loading="lazy" ' +
|
||||
'class="w-full ' + (destaque ? 'h-52' : 'h-24') + ' object-cover rounded-xl border border-white/10 ' +
|
||||
'group-hover:opacity-90 transition-opacity">' +
|
||||
etiqueta +
|
||||
'</figure>';
|
||||
};
|
||||
|
||||
const resto = fotos.slice(1).map((f, i) => figura(f, i + 1, false)).join('');
|
||||
|
||||
wrap.innerHTML = figura(fotos[0], 0, true) +
|
||||
(resto ? '<div class="grid grid-cols-3 gap-2">' + resto + '</div>' : '');
|
||||
|
||||
wrap.querySelectorAll('[data-foto-idx]').forEach(el =>
|
||||
el.addEventListener('click', () => abrirVisualizador(+el.dataset.fotoIdx)));
|
||||
}
|
||||
|
||||
// ── Visualizador (lightbox) — amplia e navega entre as fotos ──────────
|
||||
let fotoAtual = 0;
|
||||
|
||||
function abrirVisualizador(i) {
|
||||
fotoAtual = i;
|
||||
document.getElementById('modal-foto').classList.remove('hidden');
|
||||
pintarVisualizador();
|
||||
}
|
||||
function fecharVisualizador() {
|
||||
document.getElementById('modal-foto').classList.add('hidden');
|
||||
}
|
||||
function navegarFoto(passo) {
|
||||
const fotos = visita.fotos || [];
|
||||
if (!fotos.length) return;
|
||||
fotoAtual = (fotoAtual + passo + fotos.length) % fotos.length;
|
||||
pintarVisualizador();
|
||||
}
|
||||
function pintarVisualizador() {
|
||||
const fotos = visita.fotos || [];
|
||||
const f = fotos[fotoAtual];
|
||||
if (!f) return;
|
||||
const r = ROTULO_FOTO[f.tipo] || { texto: f.tipo };
|
||||
document.getElementById('modal-foto-img').src = f.url;
|
||||
document.getElementById('modal-foto-titulo').textContent =
|
||||
r.texto + ' · ' + f.origem + ' (' + (fotoAtual + 1) + '/' + fotos.length + ')';
|
||||
document.getElementById('modal-foto-abrir').href = f.url;
|
||||
}
|
||||
|
||||
// ── Campos click-to-edit ────────────────────────────────────
|
||||
@@ -365,7 +450,20 @@
|
||||
function fecharModal() { modal.classList.add('hidden'); }
|
||||
document.getElementById('modal-hist-fechar').onclick = fecharModal;
|
||||
document.getElementById('modal-hist-overlay').onclick = fecharModal;
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') fecharModal(); });
|
||||
|
||||
// ── Visualizador de foto ────────────────────────────────────
|
||||
document.getElementById('modal-foto-fechar').onclick = fecharVisualizador;
|
||||
document.getElementById('modal-foto-overlay').onclick = fecharVisualizador;
|
||||
document.getElementById('modal-foto-ant').onclick = () => navegarFoto(-1);
|
||||
document.getElementById('modal-foto-prox').onclick = () => navegarFoto(1);
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key === 'Escape') { fecharModal(); fecharVisualizador(); }
|
||||
// Setas só navegam com o visualizador aberto, senão atrapalham os campos.
|
||||
if (document.getElementById('modal-foto').classList.contains('hidden')) return;
|
||||
if (e.key === 'ArrowLeft') navegarFoto(-1);
|
||||
if (e.key === 'ArrowRight') navegarFoto(1);
|
||||
});
|
||||
|
||||
document.getElementById('btn-historico').addEventListener('click', async () => {
|
||||
if (!visita) return;
|
||||
|
||||
Reference in New Issue
Block a user