Modificação na area do motorista
This commit is contained in:
@@ -1,42 +1,90 @@
|
||||
// app/javascript/controllers/carrossel_controller.js
|
||||
// Stimulus — paginação em "carrossel" para listas longas no celular (painel do
|
||||
// motorista). Os itens já vêm todos no HTML; aqui só mostramos uma PÁGINA por
|
||||
// vez, com setas e o indicador "1 / 3".
|
||||
// Stimulus — paginação em "carrossel" para listas longas: mostra N itens por vez
|
||||
// com setas grandes e o indicador "1–10 de 12".
|
||||
//
|
||||
// Por que no cliente e não com ?pg= no servidor: a lista divide a tela com os
|
||||
// cards de valor e o filtro de período — recarregar a página a cada seta faria o
|
||||
// motorista perder a posição e piscar a tela inteira num 3G.
|
||||
// PADRÃO EM TELA PEQUENA, LISTA INTEIRA EM TELA GRANDE. Em celular e monitor
|
||||
// pequeno, uma lista de 30 cards vira rolagem infinita e o rodapé/ações da tela
|
||||
// somem de vista; num monitor grande a mesma lista cabe e paginar só atrapalha
|
||||
// (Ctrl+F do navegador não acha o que está escondido). O corte é por largura de
|
||||
// janela — `maxLargura` — e é reavaliado no resize/rotação da tela.
|
||||
//
|
||||
// Sem itens suficientes para duas páginas, os controles somem sozinhos (nada de
|
||||
// seta morta ocupando espaço).
|
||||
// Os itens já vêm todos no HTML; aqui só escondemos os de fora da página. Por
|
||||
// isso não serve para listas de centenas de itens (aí é paginação no servidor).
|
||||
//
|
||||
// Uso:
|
||||
// <div data-controller="carrossel"
|
||||
// data-carrossel-tamanho-value="10" <- itens por página
|
||||
// data-carrossel-max-largura-value="1366"> <- acima disso, mostra tudo
|
||||
// <div data-carrossel-target="item">…</div> <- cada item
|
||||
// …
|
||||
// <div data-carrossel-target="controles" class="hidden">
|
||||
// <button data-action="carrossel#anterior" data-carrossel-target="anterior">
|
||||
// <span data-carrossel-target="indicador"></span>
|
||||
// <button data-action="carrossel#proxima" data-carrossel-target="proximo">
|
||||
// </div>
|
||||
// </div>
|
||||
//
|
||||
// Um item com data-carrossel-inicial="true" (ex.: o motorista com a composição
|
||||
// aberta) define em qual página o carrossel abre — senão o clique dele "sumia".
|
||||
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["item", "controles", "indicador", "anterior", "proximo"]
|
||||
static values = { tamanho: { type: Number, default: 10 } }
|
||||
static values = {
|
||||
tamanho: { type: Number, default: 10 },
|
||||
maxLargura: { type: Number, default: 1366 }
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.pagina = 0
|
||||
this.pagina = this.paginaInicial()
|
||||
this._aoRedimensionar = () => this.render()
|
||||
window.addEventListener("resize", this._aoRedimensionar)
|
||||
this.render()
|
||||
}
|
||||
|
||||
proxima() { this.ir(this.pagina + 1) }
|
||||
disconnect() {
|
||||
window.removeEventListener("resize", this._aoRedimensionar)
|
||||
}
|
||||
|
||||
proxima() { this.ir(this.pagina + 1) }
|
||||
anterior() { this.ir(this.pagina - 1) }
|
||||
|
||||
ir(destino) {
|
||||
this.pagina = Math.min(Math.max(destino, 0), this.totalPaginas - 1)
|
||||
this.render()
|
||||
// Volta ao topo da lista: sem isso, na 2ª página o motorista continua vendo
|
||||
// o fim da anterior e parece que nada mudou.
|
||||
// Volta ao topo da lista: sem isso, na 2ª página o leitor continua vendo o
|
||||
// fim da anterior e parece que nada mudou.
|
||||
this.element.scrollIntoView({ behavior: "smooth", block: "start" })
|
||||
}
|
||||
|
||||
// Tela grande: sem paginação (a lista inteira aparece).
|
||||
get paginando() {
|
||||
return window.innerWidth <= this.maxLarguraValue &&
|
||||
this.itemTargets.length > this.tamanhoValue
|
||||
}
|
||||
|
||||
get totalPaginas() {
|
||||
return Math.max(Math.ceil(this.itemTargets.length / this.tamanhoValue), 1)
|
||||
}
|
||||
|
||||
paginaInicial() {
|
||||
const i = this.itemTargets.findIndex((el) => el.dataset.carrosselInicial === "true")
|
||||
return i < 0 ? 0 : Math.floor(i / this.tamanhoValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
const total = this.itemTargets.length
|
||||
|
||||
if (!this.paginando) {
|
||||
this.itemTargets.forEach((item) => item.classList.remove("hidden"))
|
||||
if (this.hasControlesTarget) this.controlesTarget.classList.add("hidden")
|
||||
return
|
||||
}
|
||||
|
||||
// Uma tela menor pode ter reduzido o total de páginas desde a última vez.
|
||||
this.pagina = Math.min(this.pagina, this.totalPaginas - 1)
|
||||
|
||||
const inicio = this.pagina * this.tamanhoValue
|
||||
const fim = inicio + this.tamanhoValue
|
||||
|
||||
@@ -45,12 +93,11 @@ export default class extends Controller {
|
||||
})
|
||||
|
||||
if (!this.hasControlesTarget) return
|
||||
this.controlesTarget.classList.remove("hidden")
|
||||
|
||||
this.controlesTarget.classList.toggle("hidden", this.totalPaginas < 2)
|
||||
if (this.hasIndicadorTarget) {
|
||||
// "1–10 de 12" e não "página 1 de 2": o motorista quer saber quantos
|
||||
// fechamentos existem, não quantas páginas a tela tem.
|
||||
const total = this.itemTargets.length
|
||||
// "1–10 de 12" e não "página 1 de 2": quem lê quer saber quantos itens
|
||||
// existem, não quantas páginas a tela tem.
|
||||
this.indicadorTarget.textContent = `${inicio + 1}–${Math.min(fim, total)} de ${total}`
|
||||
}
|
||||
if (this.hasAnteriorTarget) this.alternar(this.anteriorTarget, this.pagina === 0)
|
||||
@@ -60,7 +107,6 @@ export default class extends Controller {
|
||||
// Botão de ponta: desabilitado de verdade (não só apagado), para o toque não
|
||||
// "funcionar sem fazer nada".
|
||||
alternar(botao, desligado) {
|
||||
if (!botao) return
|
||||
botao.disabled = desligado
|
||||
botao.classList.toggle("opacity-30", desligado)
|
||||
botao.classList.toggle("pointer-events-none", desligado)
|
||||
|
||||
Reference in New Issue
Block a user