diff --git a/src/components/eli/EliTabela/EliTabela.vue b/src/components/eli/EliTabela/EliTabela.vue index ac519be..f2b3c5f 100644 --- a/src/components/eli/EliTabela/EliTabela.vue +++ b/src/components/eli/EliTabela/EliTabela.vue @@ -8,6 +8,7 @@ import { computed, defineComponent, h, onBeforeUnmount, onMounted, PropType, ref import type { ComponentPublicInstance } from "vue"; import { ArrowDown, ArrowUp, MoreVertical } from "lucide-vue-next"; import { codigosResposta } from "p-respostas"; +import EliTabelaPaginacao from "./EliTabelaPaginacao.vue"; import type { EliTabelaConsulta } from "./types-eli-tabela"; export default defineComponent({ @@ -93,18 +94,6 @@ export default defineComponent({ } } - function paginaAnterior() { - if (paginaAtual.value > 1) { - paginaAtual.value -= 1; - } - } - - function proximaPagina() { - if (paginaAtual.value < totalPaginas.value) { - paginaAtual.value += 1; - } - } - function irParaPagina(pagina: number) { const alvo = Math.min(Math.max(1, pagina), totalPaginas.value); if (alvo !== paginaAtual.value) { @@ -112,62 +101,6 @@ export default defineComponent({ } } - function rangePaginacao(maximoBotoes = 7) { - const total = totalPaginas.value; - const atual = paginaAtual.value; - const resultado: Array<{ label: string; pagina?: number; ativo?: boolean; disabled?: boolean }> = []; - - if (total <= maximoBotoes) { - for (let pagina = 1; pagina <= total; pagina += 1) { - resultado.push({ - label: String(pagina), - pagina, - ativo: pagina === atual, - }); - } - return resultado; - } - - const adicionarPagina = (pagina: number) => { - resultado.push({ - label: String(pagina), - pagina, - ativo: pagina === atual, - }); - }; - - const adicionarEllipsis = () => { - resultado.push({ label: "…", disabled: true }); - }; - - const visiveis = Math.max(3, maximoBotoes - 2); - let inicio = Math.max(2, atual - Math.floor(visiveis / 2)); - let fim = inicio + visiveis - 1; - - if (fim >= total) { - fim = total - 1; - inicio = fim - visiveis + 1; - } - - adicionarPagina(1); - - if (inicio > 2) { - adicionarEllipsis(); - } - - for (let pagina = inicio; pagina <= fim; pagina += 1) { - adicionarPagina(pagina); - } - - if (fim < total - 1) { - adicionarEllipsis(); - } - - adicionarPagina(total); - - return resultado; - } - function handleClickFora(evento: MouseEvent) { if (menuAberto.value === null) { return; @@ -475,10 +408,6 @@ export default defineComponent({ ); } - const podeVoltar = paginaAtual.value > 1; - const podeAvancar = paginaAtual.value < totalPaginas.value; - const botoesPaginacao = rangePaginacao(); - const conteudoTabela = [ h("table", { class: "eli-tabela__table" }, [ h( @@ -659,72 +588,14 @@ export default defineComponent({ if (totalPaginas.value > 1 && quantidade.value > 0) { conteudoTabela.push( - h( - "nav", - { - class: "eli-tabela__paginacao", - role: "navigation", - "aria-label": "Paginação de resultados", + h(EliTabelaPaginacao, { + pagina: paginaAtual.value, + totalPaginas: totalPaginas.value, + maximoBotoes: props.tabela.maximo_botoes_paginacao, + onAlterar: (pagina: number) => { + irParaPagina(pagina); }, - [ - h( - "button", - { - type: "button", - class: "eli-tabela__pagina-botao", - onClick: paginaAnterior, - disabled: !podeVoltar, - "aria-label": "Página anterior", - }, - "<<" - ), - ...botoesPaginacao.map((item, indice) => - item.disabled || !item.pagina - ? h( - "span", - { - key: `${item.label}-${indice}`, - class: "eli-tabela__pagina-ellipsis", - "aria-hidden": "true", - }, - item.label - ) - : h( - "button", - { - key: `${item.label}-${indice}`, - type: "button", - class: [ - "eli-tabela__pagina-botao", - item.ativo - ? "eli-tabela__pagina-botao--ativo" - : undefined, - ], - disabled: item.ativo, - "aria-current": item.ativo ? "page" : undefined, - "aria-label": `Ir para página ${item.label}`, - onClick: () => { - if (item.pagina) { - irParaPagina(item.pagina); - } - }, - }, - item.label - ) - ), - h( - "button", - { - type: "button", - class: "eli-tabela__pagina-botao", - onClick: proximaPagina, - disabled: !podeAvancar, - "aria-label": "Próxima página", - }, - ">>" - ), - ] - ) + }) ); } @@ -818,66 +689,6 @@ export default defineComponent({ opacity: 0; } -.eli-tabela__paginacao { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 12px; - margin-top: 12px; - flex-wrap: wrap; -} - -.eli-tabela__pagina-botao { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; - padding: 6px 14px; - border-radius: 9999px; - border: 1px solid rgba(15, 23, 42, 0.12); - background: #ffffff; - font-size: 0.875rem; - font-weight: 500; - color: rgba(15, 23, 42, 0.82); - cursor: pointer; - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease; -} - -.eli-tabela__pagina-botao:hover, -.eli-tabela__pagina-botao:focus-visible { - background-color: rgba(37, 99, 235, 0.08); - border-color: rgba(37, 99, 235, 0.4); - color: rgba(37, 99, 235, 0.95); -} - -.eli-tabela__pagina-botao:focus-visible { - outline: 2px solid rgba(37, 99, 235, 0.45); - outline-offset: 2px; -} - -.eli-tabela__pagina-botao:disabled { - cursor: default; - opacity: 0.5; - background: rgba(148, 163, 184, 0.08); - border-color: rgba(148, 163, 184, 0.18); - color: rgba(71, 85, 105, 0.75); -} - -.eli-tabela__pagina-botao--ativo { - background: rgba(37, 99, 235, 0.12); - border-color: rgba(37, 99, 235, 0.4); - color: rgba(37, 99, 235, 0.95); -} - -.eli-tabela__pagina-ellipsis { - display: inline-flex; - align-items: center; - justify-content: center; - width: 32px; - color: rgba(107, 114, 128, 0.85); - font-size: 0.9rem; -} - .eli-tabela__tr:last-child .eli-tabela__td { border-bottom: none; } diff --git a/src/components/eli/EliTabela/EliTabelaPaginacao.vue b/src/components/eli/EliTabela/EliTabelaPaginacao.vue new file mode 100644 index 0000000..50a5a87 --- /dev/null +++ b/src/components/eli/EliTabela/EliTabelaPaginacao.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/src/components/eli/EliTabela/types-eli-tabela.ts b/src/components/eli/EliTabela/types-eli-tabela.ts index 49c51bc..f77df38 100644 --- a/src/components/eli/EliTabela/types-eli-tabela.ts +++ b/src/components/eli/EliTabela/types-eli-tabela.ts @@ -39,6 +39,7 @@ export type EliTabelaConsulta = { offSet?: number; limit?: number; }) => Promise>>; + maximo_botoes_paginacao?: number; /** Mensagem exibida quando a consulta retorna ok porém sem dados. */ mensagemVazio?: string; acoes?: EliTabelaAcao[];