v-sistec-features 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "v-sistec-features",
3
3
  "private": false,
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "author": "Márlon Bento Azevedo (https://github.com/marlon-bento)",
6
6
  "repository": {
7
7
  "type": "git",
@@ -2,332 +2,221 @@
2
2
  import { computed } from "vue";
3
3
 
4
4
  // =======================================================
5
- // 1. DEFINIÇÃO DE TIPOS E INTERFACES
5
+ // 1. DEFINIÇÃO DE TIPOS E INTERFACES
6
6
  // =======================================================
7
-
8
- // Define a "forma" do objeto de paginação para garantir a segurança dos tipos.
9
7
  interface PaginationObject {
10
8
  current_page: number;
11
9
  count: number;
12
10
  limit_per_page: number;
13
11
  }
14
-
15
- // Define as props do componente usando a interface.
16
12
  interface PaginationProps {
17
13
  pagination: PaginationObject;
18
14
  filtering?: boolean;
19
15
  }
20
16
 
21
17
  // =======================================================
22
- // 2. PROPS E EMITS
18
+ // 2. PROPS E EMITS
23
19
  // =======================================================
24
-
25
- const props = withDefaults(defineProps<PaginationProps>(), {
20
+ const props = withDefaults(defineProps<PaginationProps>(), {
26
21
  filtering: false,
27
22
  });
28
-
29
- // Define os eventos que o componente pode emitir com sua assinatura de tipo.
30
23
  const emit = defineEmits<{
31
24
  (e: 'tradePage'): void
32
25
  }>();
33
26
 
34
27
  // =======================================================
35
- // 3. LÓGICA REATIVA (COMPUTED)
28
+ // 3. LÓGICA REATIVA (Computeds e Funções)
36
29
  // =======================================================
37
-
38
30
  const total_pages = computed<number>(() => {
39
31
  if (!props.pagination.limit_per_page) return 0;
40
32
  return Math.ceil(props.pagination.count / props.pagination.limit_per_page);
41
33
  });
42
34
 
43
-
44
35
  const next = computed(() => {
45
- return props.pagination.current_page + 1 <
46
- Math.ceil(props.pagination.count / props.pagination.limit_per_page)
47
- ? props.pagination.current_page + 1
48
- : null;
36
+ return props.pagination.current_page + 1 < total_pages.value
37
+ ? props.pagination.current_page + 1
38
+ : null;
49
39
  });
50
40
 
51
-
52
- // Função para passar para a próxima página
41
+ // Funções de navegação
53
42
  const nextPage = (): void => {
54
- props.pagination.current_page++;
55
- emit("tradePage");
43
+ props.pagination.current_page++;
44
+ emit("tradePage");
56
45
  };
57
46
  const setPage = (newPage: number): void => {
58
- props.pagination.current_page = newPage;
59
- emit("tradePage");
47
+ props.pagination.current_page = newPage - 1;
48
+ emit("tradePage");
60
49
  };
61
50
  const lastPage = (): void => {
62
- props.pagination.current_page = total_pages.value - 1;
63
- emit("tradePage");
51
+ props.pagination.current_page = total_pages.value - 1;
52
+ emit("tradePage");
64
53
  };
65
54
  const firstPage = (): void => {
66
- props.pagination.current_page = 0;
67
- emit("tradePage");
55
+ props.pagination.current_page = 0;
56
+ emit("tradePage");
68
57
  };
69
- // Função para voltar para a página anterior
70
58
  const prevPage = (): void => {
71
- if (props.pagination.current_page > 0) {
72
- props.pagination.current_page--;
73
- emit("tradePage");
74
- }
59
+ if (props.pagination.current_page > 0) {
60
+ props.pagination.current_page--;
61
+ emit("tradePage");
62
+ }
75
63
  };
76
64
 
65
+ // =======================================================
66
+ // 4. LÓGICA DE GERAÇÃO DE PÁGINAS
67
+ // =======================================================
68
+
77
69
  /**
78
- * @description função que serve para saber quais páginas mostrar
79
- *
80
- *
81
- * @param page esse valor é o valor n do v-for
82
- * @param current_page página atual que o usuário está usando
83
- * @param total_pages total de páginas que existem
84
- *
85
- *
70
+ * @description Computa um array com os números das páginas e as reticências a serem exibidas.
71
+ * Ex: [1, 2, '...', 10, 11, 12, '...', 33, 34]
86
72
  */
87
- function rate_next_pages(page: number, current_page: number, total_pages: number): boolean {
88
- /* se a página atual for a página que o v-for chegou, ela deve ser mostrada */
89
- if (page === current_page) {
90
- return true;
91
- } else if (current_page === page - 1 && page != 3) {
92
- /* se a página que o v-for chegou não for a página 3
93
- mostra as páginas posteriores a atual
94
- */
95
- return true;
96
- } else if (current_page === page + 1) {
97
- /*
98
- mostra as páginas anteriores a atual
99
- */
100
- return true;
101
- } else if (page > total_pages - 2) {
102
- /* mostra as duas ultimas páginas */
103
- return true;
104
- } else {
105
- return false;
106
- }
107
- }
108
- function rate_first_last_pages(page: number, current_page: number, total_pages: number): boolean {
109
- /*
110
- Verifica se a página atual está longe das primeiras páginas e das últimas páginas,
111
- e se estamos na terceira última página do total.
112
- Exemplo: mostra "..." antes das últimas páginas (ex: ... 8 9).
113
- */
114
- if (
115
- page == total_pages - 2 &&
116
- current_page > 2 &&
117
- current_page != total_pages
118
- ) {
119
- return true;
120
- } else {
121
- return false;
122
- }
123
- }
124
- function rate_last_pages(page: number, current_page: number, total_pages: number): boolean {
125
- /*
126
- Controla a exibição das últimas duas páginas,
127
- garantindo que "..." apareça apenas quando a página atual não for uma das duas últimas.
128
- */
129
- if (current_page != total_pages - 1 && current_page != total_pages - 2) {
130
- if (page > total_pages - 2) {
131
- return true;
132
- } else {
133
- return false;
134
- }
135
- } else {
136
- return false;
73
+ const paginasParaExibir = computed(() => {
74
+ // Se houver 7 páginas ou menos, mostre todas.
75
+ if (total_pages.value <= 7) {
76
+ return Array.from({ length: total_pages.value }, (_, i) => i + 1);
77
+ }
78
+
79
+ const paginaAtual = props.pagination.current_page + 1;
80
+ const total = total_pages.value;
81
+
82
+ // O conjunto de páginas visíveis sempre inclui as 2 primeiras, 2 últimas,
83
+ // a atual e suas duas vizinhas. O Set cuida de remover duplicatas.
84
+ const paginasEssenciais = new Set([
85
+ 1, 2, // Sempre mostra as 2 primeiras
86
+ paginaAtual - 1, paginaAtual, paginaAtual + 1, // Mostra a atual e vizinhas
87
+ total - 1, total // Sempre mostra as 2 últimas
88
+ ]);
89
+
90
+ const resultado: (number | string)[] = [];
91
+ let ultimoNumeroAdicionado = 0;
92
+
93
+ // Ordena os números e itera sobre eles para inserir as reticências
94
+ Array.from(paginasEssenciais).sort((a, b) => a - b).forEach(num => {
95
+ // Ignora números inválidos (como página 0 ou menores, ou maiores que o total)
96
+ if (num < 1 || num > total) return;
97
+
98
+ // Se houver um buraco entre o último número adicionado e o atual, insere "..."
99
+ if (num > ultimoNumeroAdicionado + 1) {
100
+ resultado.push('...');
137
101
  }
138
- }
139
- </script>
140
-
141
- <template>
142
- <div class="d-flex align-items-center justify-content-between w-100" v-if="props.pagination.count > 0">
143
- <span>
144
- Mostrando de
145
- {{
146
- props.pagination.count !== 0
147
- ? props.pagination.limit_per_page * props.pagination.current_page + 1
148
- : 0
149
- }}
150
- até
151
- {{
152
- props.pagination.limit_per_page * (props.pagination.current_page + 1) < props.pagination.count ?
153
- props.pagination.limit_per_page * (props.pagination.current_page + 1) : props.pagination.count }} de {{
154
- props.pagination.count }} registros </span>
155
- <div class="d-flex align-items-center p-2 gap-2" v-if="total_pages > 0">
156
- <div class="d-flex">
157
- <button class="btn btn-estilo" @click.prevent="firstPage"
158
- :disabled="props.pagination.current_page === 0">
159
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
160
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
161
- stroke-linejoin="round"
162
- class="icon icon-tabler icons-tabler-outline icon-tabler-chevrons-left">
163
- <path stroke="none" d="M0 0h24v24H0z" fill="none" />
164
- <path d="M11 7l-5 5l5 5" />
165
- <path d="M17 7l-5 5l5 5" />
166
- </svg>
167
102
 
168
- </button>
169
- <button class="btn btn-estilo" @click.prevent="prevPage"
170
- :disabled="props.pagination.current_page === 0">
171
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
172
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
173
- stroke-linejoin="round"
174
- class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-left">
175
- <path stroke="none" d="M0 0h24v24H0z" fill="none" />
176
- <path d="M15 6l-6 6l6 6" />
177
- </svg>
178
- </button>
179
- </div>
103
+ resultado.push(num);
104
+ ultimoNumeroAdicionado = num;
105
+ });
180
106
 
181
- <div class="d-flex gap-2">
182
- <template v-if="total_pages < 7">
183
- <template v-for="n in total_pages" :key="n">
184
- <!-- Exibe normalmente todos os botões de páginas se o total de páginas que existem for menor que 7 -->
185
- <button :class="props.pagination.current_page + 1 == n ? 'page-select' : ''"
186
- class="page-estilo" @click.prevent="setPage(n - 1)"
187
- :disabled="props.pagination.current_page + 1 == n">
188
- {{ n }}
189
- </button>
190
- </template>
191
- </template>
192
- <template v-else>
193
- <template v-for="n in total_pages" :key="n">
194
- <!-- primeiramente avalia as primeiras 2 páginas -->
195
- <template v-if="n < 3">
196
- <button :class="props.pagination.current_page + 1 == n ? 'page-select' : ''
197
- " class="page-estilo" @click.prevent="setPage(n - 1)"
198
- :disabled="props.pagination.current_page + 1 == n">
199
- {{ n }}
200
- </button>
201
- <!-- tratamento de quando mostrar os ... que sempre fica depois da página 2 -->
202
- <p v-if="
203
- n === 2 &&
204
- props.pagination.current_page + 1 !== 2 &&
205
- props.pagination.current_page + 1 !== 3 &&
206
- props.pagination.current_page + 1 !== 4
207
- " class="m-0 p-0">
208
- ...
209
- </p>
210
- </template>
211
- <!-- Se a página atual for a 2, da a opção de ir pra próxima, que no caso é a 3 -->
212
- <template v-else-if="n === 3 && props.pagination.current_page + 1 === 2">
213
- <button :class="props.pagination.current_page + 1 == n ? 'page-select' : ''
214
- " class="page-estilo" @click.prevent="setPage(n - 1)"
215
- :disabled="props.pagination.current_page + 1 == n">
216
- {{ n }}
217
- </button>
218
- <!-- mostra que tem mais páginas -->
219
- <p class="m-0 p-0">...</p>
220
- </template>
221
- <!-- Agora o tratamento para quais páginas além das 2 primeiras devem aparecer -->
222
- <template v-else>
223
- <!-- -->
224
- <button v-if="
225
- rate_next_pages(
226
- n,
227
- props.pagination.current_page + 1,
228
- total_pages,
229
- )
230
- " :class="props.pagination.current_page + 1 == n ? 'page-select' : ''
231
- " class="page-estilo" @click.prevent="setPage(n - 1)"
232
- :disabled="props.pagination.current_page + 1 == n">
233
- {{ n }}
234
- </button>
235
- <template v-else>
236
- <p v-if="
237
- rate_first_last_pages(
238
- n,
239
- props.pagination.current_page + 1,
240
- total_pages,
241
- )
242
- " class="m-0 p-0">
243
- ...
244
- </p>
245
- <button v-if="
246
- rate_last_pages(
247
- n,
248
- props.pagination.current_page + 1,
249
- total_pages,
250
- )
251
- " :class="props.pagination.current_page + 1 == n ? 'page-select' : ''
252
- " class="page-estilo" @click.prevent="setPage(n - 1)"
253
- :disabled="props.pagination.current_page + 1 == n">
254
- {{ n }}
255
- </button>
256
- </template>
257
- </template>
258
- </template>
259
107
 
108
+ return resultado;
109
+ });
110
+ const svg_duas_setas =`
111
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
112
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
113
+ class="icon icon-tabler icons-tabler-outline icon-tabler-chevrons-left">
114
+ <path stroke="none" d="M0 0h24v24H0z" fill="none" />
115
+ <path d="M11 7l-5 5l5 5" />
116
+ <path d="M17 7l-5 5l5 5" />
117
+ </svg>
118
+ `
119
+ const svg_uma_seta = `
120
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
121
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
122
+ class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-left">
123
+ <path stroke="none" d="M0 0h24v24H0z" fill="none" />
124
+ <path d="M15 6l-6 6l6 6" />
125
+ </svg>
126
+ `
260
127
 
261
- </template>
262
- </div>
263
-
264
-
265
- <div class="d-flex">
266
- <button @click.prevent="nextPage" class="btn btn-estilo" :disabled="!next">
267
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
268
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
269
- stroke-linejoin="round"
270
- class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-right">
271
- <path stroke="none" d="M0 0h24v24H0z" fill="none" />
272
- <path d="M9 6l6 6l-6 6" />
273
- </svg>
274
- </button>
275
- <button @click.prevent="lastPage" class="btn btn-estilo" :disabled="!next">
276
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
277
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
278
- stroke-linejoin="round"
279
- class="icon icon-tabler icons-tabler-outline icon-tabler-chevrons-right">
280
- <path stroke="none" d="M0 0h24v24H0z" fill="none" />
281
- <path d="M7 7l5 5l-5 5" />
282
- <path d="M13 7l5 5l-5 5" />
283
- </svg>
284
-
285
- </button>
286
- </div>
287
-
128
+ </script>
288
129
 
289
- </div>
290
- </div>
130
+ <template>
131
+ <div class="d-flex align-items-center justify-content-between w-100" v-if="props.pagination.count > 0">
132
+ <span>
133
+ Mostrando de
134
+ {{
135
+ props.pagination.count !== 0
136
+ ? props.pagination.limit_per_page * props.pagination.current_page + 1
137
+ : 0
138
+ }}
139
+ até
140
+ {{
141
+ props.pagination.limit_per_page * (props.pagination.current_page + 1) < props.pagination.count ?
142
+ props.pagination.limit_per_page * (props.pagination.current_page + 1) : props.pagination.count }} de {{
143
+ props.pagination.count }} registros </span>
144
+ <div class="d-flex align-items-center p-2 gap-2" v-if="total_pages > 0">
145
+ <div class="d-flex">
146
+ <button class="btn btn-estilo" @click.prevent="firstPage" :disabled="props.pagination.current_page === 0" v-html="svg_duas_setas">
147
+ </button>
148
+ <button class="btn btn-estilo" @click.prevent="prevPage" :disabled="props.pagination.current_page === 0" v-html="svg_uma_seta">
149
+ </button>
150
+ </div>
151
+
152
+ <div class="d-flex gap-2">
153
+ <template v-for="(pagina, index) in paginasParaExibir" :key="index">
154
+ <button v-if="typeof pagina === 'number'"
155
+ :class="props.pagination.current_page + 1 == pagina ? 'page-select' : ''" class="page-estilo"
156
+ @click.prevent="setPage(pagina)" :disabled="props.pagination.current_page + 1 == pagina">
157
+ {{ pagina }}
158
+ </button>
159
+ <span v-else class="m-0 p-0">...</span>
160
+ </template>
161
+ </div>
162
+ <div class="d-flex">
163
+ <button @click.prevent="nextPage" class="btn btn-estilo rotate-180" :disabled="!next" v-html="svg_uma_seta">
164
+ </button>
165
+ <button @click.prevent="lastPage" class="btn btn-estilo rotate-180" :disabled="!next" v-html="svg_duas_setas">
166
+ </button>
167
+ </div>
168
+
169
+ </div>
170
+ </div>
291
171
  </template>
292
172
  <style lang="scss" scoped>
173
+ .rotate-180 {
174
+ :deep(svg) {
175
+ transform: rotate(180deg);
176
+ }
177
+
178
+ }
293
179
  .page-select {
294
- background-color: var(--tblr-primary) !important;
295
- color: white !important;
296
- border: none !important;
180
+ background-color: var(--tblr-primary) !important;
181
+ color: white !important;
182
+ border: none !important;
297
183
  }
298
184
 
299
185
  .page-estilo {
300
- border: none;
301
- --cor-escurecida: color-mix(in srgb, var(--tblr-primary), #000 25%);
302
- //border: 2px solid var(--cor-escurecida);
303
- background: transparent;
304
- padding: 1px 10px;
305
- border-radius: 7px;
306
- margin: 0 !important;
307
- transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
308
-
309
- &:hover {
310
- background: var(--cor-escurecida);
311
- color: white;
312
- }
186
+ border: none;
187
+ --cor-escurecida: color-mix(in srgb, var(--tblr-primary), #000 25%);
188
+ //border: 2px solid var(--cor-escurecida);
189
+ background: transparent;
190
+ padding: 1px 10px;
191
+ border-radius: 7px;
192
+ margin: 0 !important;
193
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
194
+
195
+ &:hover {
196
+ background: var(--cor-escurecida);
197
+ color: white;
198
+ }
313
199
  }
314
200
 
315
-
316
- .btn-estilo {
317
- background: 0 0;
318
- margin: 0 !important;
319
- padding: 0 !important;
320
- border: none;
321
- transition: color 200ms ease-in-out;
322
-
323
- &:hover {
324
- color: rgb(86, 148, 242);
325
- border: var(--tblr-pagination-border-width) solid var(--tblr-pagination-border-color);
326
- }
201
+ .btn{
202
+ padding: 0 !important;
203
+ margin: 0 !important;
204
+ background: transparent !important;
205
+ border: none !important;
206
+ box-shadow: none !important;
207
+ }
208
+ :deep(.btn-estilo) {
209
+ svg {
210
+ padding: 0px !important;
211
+ margin: 0px !important;
212
+ }
213
+ &:hover svg {
214
+ stroke: var(--tblr-primary);
215
+ }
327
216
  }
328
217
 
329
218
  .icon-tabler {
330
- margin: 0 !important;
331
- padding: 0 !important;
219
+ margin: 0 !important;
220
+ padding: 0 !important;
332
221
  }
333
222
  </style>
@@ -17,6 +17,7 @@ interface VColumnProps {
17
17
  deactivate_img_preview?: boolean;
18
18
  limite_text?: number | string | null;
19
19
  transform_function?: ((value: any) => any) | null;
20
+ click?: Function | null;
20
21
  }
21
22
  const props = withDefaults(defineProps<VColumnProps>(), {
22
23
  field: null,
@@ -41,6 +42,7 @@ const props = withDefaults(defineProps<VColumnProps>(), {
41
42
 
42
43
  /* recebe função para alterar o que é mostrado */
43
44
  transform_function: null ,
45
+ click: null,
44
46
  });
45
47
 
46
48
  const slots = useSlots();
@@ -83,6 +85,7 @@ onMounted(() => {
83
85
  class_column: props.class_column,
84
86
  class_row: props.class_row,
85
87
  class_item: props.class_item,
88
+ click: props.click,
86
89
  transform_function: props.transform_function,
87
90
 
88
91
  bodySlot: slots.body,