@makolabs/ripple 0.0.1-dev.55 → 0.0.1-dev.57
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/dist/index.d.ts +11 -0
- package/dist/layout/table/Table.svelte +430 -58
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,8 @@ export type TableProps<T extends DataRow = any> = {
|
|
|
201
201
|
bordered?: boolean;
|
|
202
202
|
striped?: boolean;
|
|
203
203
|
pageSize?: number;
|
|
204
|
+
currentPage?: number;
|
|
205
|
+
totalItems?: number;
|
|
204
206
|
selectable?: boolean;
|
|
205
207
|
selected?: T[];
|
|
206
208
|
class?: ClassValue;
|
|
@@ -212,12 +214,21 @@ export type TableProps<T extends DataRow = any> = {
|
|
|
212
214
|
thclass?: ClassValue;
|
|
213
215
|
tdclass?: ClassValue;
|
|
214
216
|
footerclass?: ClassValue;
|
|
217
|
+
paginationclass?: ClassValue;
|
|
215
218
|
onrowclick?: (row: T, index: number) => void;
|
|
216
219
|
onsort?: (sortState: SortState) => void;
|
|
217
220
|
onselect?: (selected: T[]) => void;
|
|
221
|
+
onpagechange?: (page: number) => void;
|
|
218
222
|
rowclass?: (row: T, index: number) => ClassValue;
|
|
219
223
|
loading?: boolean;
|
|
220
224
|
expandedContent?: Snippet<[T]>;
|
|
225
|
+
pagination?: boolean;
|
|
226
|
+
showPagination?: boolean;
|
|
227
|
+
showPageSize?: boolean;
|
|
228
|
+
pageSizeOptions?: number[];
|
|
229
|
+
onpagesizechange?: (pageSize: number) => void;
|
|
230
|
+
paginationPosition?: 'top' | 'bottom' | 'both';
|
|
231
|
+
paginationTemplate?: 'simple' | 'full';
|
|
221
232
|
};
|
|
222
233
|
export type BreadcrumbItem = {
|
|
223
234
|
label: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
|
-
import { table } from './table
|
|
3
|
+
import { table } from './table';
|
|
4
4
|
import type { TableProps, SortDirection, SortState } from '../../index.js';
|
|
5
5
|
|
|
6
6
|
let {
|
|
@@ -9,11 +9,15 @@
|
|
|
9
9
|
bordered = true,
|
|
10
10
|
striped = false,
|
|
11
11
|
pageSize = 10,
|
|
12
|
+
currentPage: externalCurrentPage,
|
|
13
|
+
totalItems,
|
|
12
14
|
selectable = false,
|
|
13
15
|
selected = $bindable([]),
|
|
14
|
-
onrowclick
|
|
16
|
+
onrowclick,
|
|
15
17
|
onsort = () => {},
|
|
16
18
|
onselect = () => {},
|
|
19
|
+
onpagechange,
|
|
20
|
+
onpagesizechange,
|
|
17
21
|
class: classname = '',
|
|
18
22
|
wrapperclass: wrapperClass = '',
|
|
19
23
|
tableclass: tableClass = '',
|
|
@@ -23,17 +27,40 @@
|
|
|
23
27
|
thclass: thClass = '',
|
|
24
28
|
tdclass: tdClass = '',
|
|
25
29
|
footerclass: footerClass = '',
|
|
30
|
+
paginationclass: paginationClass = '',
|
|
26
31
|
rowclass = () => '',
|
|
27
32
|
loading = false,
|
|
28
|
-
expandedContent
|
|
33
|
+
expandedContent,
|
|
34
|
+
pagination = true,
|
|
35
|
+
showPagination = true,
|
|
36
|
+
showPageSize = false,
|
|
37
|
+
pageSizeOptions = [5, 10, 25, 50, 100],
|
|
38
|
+
paginationPosition = 'bottom',
|
|
39
|
+
paginationTemplate = 'full'
|
|
29
40
|
}: TableProps<any> = $props();
|
|
30
41
|
|
|
31
42
|
let sortColumn = $state('');
|
|
32
43
|
let sortDirection = $state<SortDirection>(null);
|
|
33
|
-
let
|
|
44
|
+
let internalCurrentPage = $state(externalCurrentPage || 1);
|
|
45
|
+
let internalPageSize = $state(pageSize);
|
|
34
46
|
|
|
35
|
-
//
|
|
36
|
-
|
|
47
|
+
// Use external current page if provided
|
|
48
|
+
$effect(() => {
|
|
49
|
+
if (externalCurrentPage !== undefined) {
|
|
50
|
+
internalCurrentPage = externalCurrentPage;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Pagination is automatically determined by pageSize and pagination prop
|
|
55
|
+
const showPaginationControls = $derived(
|
|
56
|
+
pagination &&
|
|
57
|
+
showPagination &&
|
|
58
|
+
(data.length > internalPageSize || totalItems > internalPageSize)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Calculate total items and pages
|
|
62
|
+
const effectiveTotalItems = $derived(totalItems !== undefined ? totalItems : data.length);
|
|
63
|
+
const totalPages = $derived(Math.ceil(effectiveTotalItems / internalPageSize));
|
|
37
64
|
|
|
38
65
|
const {
|
|
39
66
|
base: baseClass,
|
|
@@ -65,13 +92,28 @@
|
|
|
65
92
|
const thClasses = $derived(cn(thBaseClass(), thClass));
|
|
66
93
|
const tdClasses = $derived(cn(tdBaseClass(), tdClass));
|
|
67
94
|
const footerClasses = $derived(cn(footerBaseClass(), footerClass));
|
|
95
|
+
const paginationClasses = $derived(cn(paginationBaseClass(), paginationClass));
|
|
68
96
|
const emptyStateClasses = $derived(emptyStateBaseClass());
|
|
69
97
|
|
|
70
98
|
// Handle pagination
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
pagination
|
|
74
|
-
|
|
99
|
+
function getPaginatedData() {
|
|
100
|
+
// If no pagination or all data fits on one page, return all data
|
|
101
|
+
if (!pagination || data.length <= internalPageSize) {
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// If external data source might be handling pagination
|
|
106
|
+
if (totalItems !== undefined) {
|
|
107
|
+
// If data.length is less than or equal to pageSize, assume it's already paginated
|
|
108
|
+
if (data.length <= internalPageSize) {
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Otherwise, handle pagination internally
|
|
114
|
+
const startIndex = (internalCurrentPage - 1) * internalPageSize;
|
|
115
|
+
return data.slice(startIndex, startIndex + internalPageSize);
|
|
116
|
+
}
|
|
75
117
|
|
|
76
118
|
// Handle sorting
|
|
77
119
|
function toggleSort(column: string) {
|
|
@@ -115,29 +157,265 @@
|
|
|
115
157
|
}
|
|
116
158
|
|
|
117
159
|
function handleRowClick(row: any, index: number) {
|
|
118
|
-
onrowclick(row, index);
|
|
160
|
+
onrowclick?.(row, index);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function goToFirstPage() {
|
|
164
|
+
if (internalCurrentPage !== 1) {
|
|
165
|
+
internalCurrentPage = 1;
|
|
166
|
+
onpagechange?.(internalCurrentPage);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function goToLastPage() {
|
|
171
|
+
if (internalCurrentPage !== totalPages) {
|
|
172
|
+
internalCurrentPage = totalPages;
|
|
173
|
+
onpagechange?.(internalCurrentPage);
|
|
174
|
+
}
|
|
119
175
|
}
|
|
120
176
|
|
|
121
177
|
function nextPage() {
|
|
122
|
-
if (
|
|
123
|
-
|
|
178
|
+
if (internalCurrentPage < totalPages) {
|
|
179
|
+
internalCurrentPage++;
|
|
180
|
+
onpagechange?.(internalCurrentPage);
|
|
124
181
|
}
|
|
125
182
|
}
|
|
126
183
|
|
|
127
184
|
function prevPage() {
|
|
128
|
-
if (
|
|
129
|
-
|
|
185
|
+
if (internalCurrentPage > 1) {
|
|
186
|
+
internalCurrentPage--;
|
|
187
|
+
onpagechange?.(internalCurrentPage);
|
|
130
188
|
}
|
|
131
189
|
}
|
|
132
190
|
|
|
133
191
|
function goToPage(page: number) {
|
|
134
|
-
if (page >= 1 && page <= totalPages) {
|
|
135
|
-
|
|
192
|
+
if (page >= 1 && page <= totalPages && page !== internalCurrentPage) {
|
|
193
|
+
internalCurrentPage = page;
|
|
194
|
+
onpagechange?.(internalCurrentPage);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function handlePageSizeChange(event: Event) {
|
|
199
|
+
const select = event.target as HTMLSelectElement;
|
|
200
|
+
const newPageSize = parseInt(select.value, 10);
|
|
201
|
+
internalPageSize = newPageSize;
|
|
202
|
+
|
|
203
|
+
// Adjust current page if it would exceed the new total pages
|
|
204
|
+
const newTotalPages = Math.ceil(effectiveTotalItems / newPageSize);
|
|
205
|
+
if (internalCurrentPage > newTotalPages) {
|
|
206
|
+
internalCurrentPage = newTotalPages || 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
onpagesizechange?.(newPageSize);
|
|
210
|
+
onpagechange?.(internalCurrentPage);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getPageNumbers(): number[] {
|
|
214
|
+
const pages: number[] = [];
|
|
215
|
+
const maxPages = 5;
|
|
216
|
+
const halfMax = Math.floor(maxPages / 2);
|
|
217
|
+
|
|
218
|
+
let start = Math.max(1, internalCurrentPage - halfMax);
|
|
219
|
+
let end = Math.min(totalPages, start + maxPages - 1);
|
|
220
|
+
|
|
221
|
+
if (end - start + 1 < maxPages) {
|
|
222
|
+
start = Math.max(1, end - maxPages + 1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
for (let i = start; i <= end; i++) {
|
|
226
|
+
pages.push(i);
|
|
136
227
|
}
|
|
228
|
+
|
|
229
|
+
return pages;
|
|
137
230
|
}
|
|
138
231
|
</script>
|
|
139
232
|
|
|
140
233
|
<div class={baseClasses}>
|
|
234
|
+
{#if showPaginationControls && (paginationPosition === 'top' || paginationPosition === 'both')}
|
|
235
|
+
<div class={footerClasses}>
|
|
236
|
+
<div class={paginationClasses}>
|
|
237
|
+
<div class="flex items-center gap-2">
|
|
238
|
+
{#if showPageSize}
|
|
239
|
+
<div class="flex items-center gap-2">
|
|
240
|
+
<label for="table-page-size" class="text-default-500 text-sm">Show</label>
|
|
241
|
+
<select
|
|
242
|
+
id="table-page-size"
|
|
243
|
+
class="border-default-200 rounded-md border px-2 py-1 text-sm"
|
|
244
|
+
value={internalPageSize}
|
|
245
|
+
onchange={handlePageSizeChange}
|
|
246
|
+
>
|
|
247
|
+
{#each pageSizeOptions as option}
|
|
248
|
+
<option value={option}>{option}</option>
|
|
249
|
+
{/each}
|
|
250
|
+
</select>
|
|
251
|
+
<span class="text-default-500 text-sm">entries</span>
|
|
252
|
+
</div>
|
|
253
|
+
{/if}
|
|
254
|
+
<span class="text-default-500 text-sm">
|
|
255
|
+
Showing {Math.min(
|
|
256
|
+
(internalCurrentPage - 1) * internalPageSize + 1,
|
|
257
|
+
effectiveTotalItems
|
|
258
|
+
)}
|
|
259
|
+
to {Math.min(internalCurrentPage * internalPageSize, effectiveTotalItems)} of {effectiveTotalItems}
|
|
260
|
+
entries
|
|
261
|
+
</span>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<div class="flex items-center gap-1">
|
|
265
|
+
{#if paginationTemplate === 'full'}
|
|
266
|
+
<!-- First page button -->
|
|
267
|
+
<button
|
|
268
|
+
type="button"
|
|
269
|
+
class={cn(
|
|
270
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
271
|
+
internalCurrentPage === 1
|
|
272
|
+
? 'text-default-300 cursor-not-allowed'
|
|
273
|
+
: 'text-default-700 hover:bg-default-100'
|
|
274
|
+
)}
|
|
275
|
+
onclick={goToFirstPage}
|
|
276
|
+
disabled={internalCurrentPage === 1}
|
|
277
|
+
aria-label="First page"
|
|
278
|
+
>
|
|
279
|
+
<!-- Double Chevron Left SVG -->
|
|
280
|
+
<svg
|
|
281
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
282
|
+
width="16"
|
|
283
|
+
height="16"
|
|
284
|
+
viewBox="0 0 24 24"
|
|
285
|
+
fill="none"
|
|
286
|
+
stroke="currentColor"
|
|
287
|
+
stroke-width="2"
|
|
288
|
+
stroke-linecap="round"
|
|
289
|
+
stroke-linejoin="round"
|
|
290
|
+
class="h-4 w-4"
|
|
291
|
+
>
|
|
292
|
+
<path d="m11 17-5-5 5-5"></path>
|
|
293
|
+
<path d="m18 17-5-5 5-5"></path>
|
|
294
|
+
</svg>
|
|
295
|
+
</button>
|
|
296
|
+
{/if}
|
|
297
|
+
|
|
298
|
+
<!-- Previous page button -->
|
|
299
|
+
<button
|
|
300
|
+
type="button"
|
|
301
|
+
class={cn(
|
|
302
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
303
|
+
internalCurrentPage === 1
|
|
304
|
+
? 'text-default-300 cursor-not-allowed'
|
|
305
|
+
: 'text-default-700 hover:bg-default-100'
|
|
306
|
+
)}
|
|
307
|
+
onclick={prevPage}
|
|
308
|
+
disabled={internalCurrentPage === 1}
|
|
309
|
+
aria-label="Previous page"
|
|
310
|
+
>
|
|
311
|
+
<!-- Chevron Left SVG -->
|
|
312
|
+
<svg
|
|
313
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
314
|
+
width="16"
|
|
315
|
+
height="16"
|
|
316
|
+
viewBox="0 0 24 24"
|
|
317
|
+
fill="none"
|
|
318
|
+
stroke="currentColor"
|
|
319
|
+
stroke-width="2"
|
|
320
|
+
stroke-linecap="round"
|
|
321
|
+
stroke-linejoin="round"
|
|
322
|
+
class="h-4 w-4"
|
|
323
|
+
>
|
|
324
|
+
<path d="m15 18-6-6 6-6"></path>
|
|
325
|
+
</svg>
|
|
326
|
+
</button>
|
|
327
|
+
|
|
328
|
+
<!-- Page numbers -->
|
|
329
|
+
{#if paginationTemplate === 'full'}
|
|
330
|
+
{#each getPageNumbers() as pageNum}
|
|
331
|
+
<button
|
|
332
|
+
type="button"
|
|
333
|
+
class={cn(
|
|
334
|
+
'relative inline-flex items-center rounded-md px-3 py-1 text-sm font-medium',
|
|
335
|
+
internalCurrentPage === pageNum
|
|
336
|
+
? 'bg-primary-100 text-primary-700'
|
|
337
|
+
: 'text-default-700 hover:bg-default-100'
|
|
338
|
+
)}
|
|
339
|
+
onclick={() => goToPage(pageNum)}
|
|
340
|
+
aria-label={`Page ${pageNum}`}
|
|
341
|
+
aria-current={internalCurrentPage === pageNum ? 'page' : undefined}
|
|
342
|
+
>
|
|
343
|
+
{pageNum}
|
|
344
|
+
</button>
|
|
345
|
+
{/each}
|
|
346
|
+
{:else}
|
|
347
|
+
<span class="text-default-500 px-2 text-sm">
|
|
348
|
+
Page {internalCurrentPage} of {totalPages}
|
|
349
|
+
</span>
|
|
350
|
+
{/if}
|
|
351
|
+
|
|
352
|
+
<!-- Next page button -->
|
|
353
|
+
<button
|
|
354
|
+
type="button"
|
|
355
|
+
class={cn(
|
|
356
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
357
|
+
internalCurrentPage === totalPages
|
|
358
|
+
? 'text-default-300 cursor-not-allowed'
|
|
359
|
+
: 'text-default-700 hover:bg-default-100'
|
|
360
|
+
)}
|
|
361
|
+
onclick={nextPage}
|
|
362
|
+
disabled={internalCurrentPage === totalPages}
|
|
363
|
+
aria-label="Next page"
|
|
364
|
+
>
|
|
365
|
+
<!-- Chevron Right SVG -->
|
|
366
|
+
<svg
|
|
367
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
368
|
+
width="16"
|
|
369
|
+
height="16"
|
|
370
|
+
viewBox="0 0 24 24"
|
|
371
|
+
fill="none"
|
|
372
|
+
stroke="currentColor"
|
|
373
|
+
stroke-width="2"
|
|
374
|
+
stroke-linecap="round"
|
|
375
|
+
stroke-linejoin="round"
|
|
376
|
+
class="h-4 w-4"
|
|
377
|
+
>
|
|
378
|
+
<path d="m9 18 6-6-6-6"></path>
|
|
379
|
+
</svg>
|
|
380
|
+
</button>
|
|
381
|
+
|
|
382
|
+
{#if paginationTemplate === 'full'}
|
|
383
|
+
<!-- Last page button -->
|
|
384
|
+
<button
|
|
385
|
+
type="button"
|
|
386
|
+
class={cn(
|
|
387
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
388
|
+
internalCurrentPage === totalPages
|
|
389
|
+
? 'text-default-300 cursor-not-allowed'
|
|
390
|
+
: 'text-default-700 hover:bg-default-100'
|
|
391
|
+
)}
|
|
392
|
+
onclick={goToLastPage}
|
|
393
|
+
disabled={internalCurrentPage === totalPages}
|
|
394
|
+
aria-label="Last page"
|
|
395
|
+
>
|
|
396
|
+
<!-- Double Chevron Right SVG -->
|
|
397
|
+
<svg
|
|
398
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
399
|
+
width="16"
|
|
400
|
+
height="16"
|
|
401
|
+
viewBox="0 0 24 24"
|
|
402
|
+
fill="none"
|
|
403
|
+
stroke="currentColor"
|
|
404
|
+
stroke-width="2"
|
|
405
|
+
stroke-linecap="round"
|
|
406
|
+
stroke-linejoin="round"
|
|
407
|
+
class="h-4 w-4"
|
|
408
|
+
>
|
|
409
|
+
<path d="m13 17 5-5-5-5"></path>
|
|
410
|
+
<path d="m6 17 5-5-5-5"></path>
|
|
411
|
+
</svg>
|
|
412
|
+
</button>
|
|
413
|
+
{/if}
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
{/if}
|
|
418
|
+
|
|
141
419
|
<div class={wrapperClasses}>
|
|
142
420
|
<table class={tableClasses}>
|
|
143
421
|
<thead class={theadClasses}>
|
|
@@ -260,7 +538,7 @@
|
|
|
260
538
|
</div>
|
|
261
539
|
</td>
|
|
262
540
|
</tr>
|
|
263
|
-
{:else if
|
|
541
|
+
{:else if getPaginatedData().length === 0}
|
|
264
542
|
<tr>
|
|
265
543
|
<td
|
|
266
544
|
colspan={selectable ? columns.length + 1 : columns.length}
|
|
@@ -270,13 +548,12 @@
|
|
|
270
548
|
</td>
|
|
271
549
|
</tr>
|
|
272
550
|
{:else}
|
|
273
|
-
{#each
|
|
551
|
+
{#each getPaginatedData() as row, rowIndex}
|
|
274
552
|
<tr
|
|
275
|
-
class={cn(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
)}
|
|
553
|
+
class={cn(trClasses, rowclass(row, rowIndex), {
|
|
554
|
+
'bg-primary-100': selectable && isRowSelected(row),
|
|
555
|
+
'cursor-pointer': onrowclick
|
|
556
|
+
})}
|
|
280
557
|
onclick={() => handleRowClick(row, rowIndex)}
|
|
281
558
|
aria-selected={selectable && isRowSelected(row)}
|
|
282
559
|
>
|
|
@@ -326,91 +603,186 @@
|
|
|
326
603
|
</table>
|
|
327
604
|
</div>
|
|
328
605
|
|
|
329
|
-
{#if
|
|
606
|
+
{#if showPaginationControls && (paginationPosition === 'bottom' || paginationPosition === 'both')}
|
|
330
607
|
<div class={footerClasses}>
|
|
331
|
-
<div class={
|
|
608
|
+
<div class={paginationClasses}>
|
|
332
609
|
<div class="flex items-center gap-2">
|
|
610
|
+
{#if showPageSize}
|
|
611
|
+
<div class="flex items-center gap-2">
|
|
612
|
+
<label for="table-page-size-bottom" class="text-default-500 text-sm">Show</label>
|
|
613
|
+
<select
|
|
614
|
+
id="table-page-size-bottom"
|
|
615
|
+
class="border-default-200 rounded-md border px-2 py-1 text-sm"
|
|
616
|
+
value={internalPageSize}
|
|
617
|
+
onchange={handlePageSizeChange}
|
|
618
|
+
>
|
|
619
|
+
{#each pageSizeOptions as option}
|
|
620
|
+
<option value={option}>{option}</option>
|
|
621
|
+
{/each}
|
|
622
|
+
</select>
|
|
623
|
+
<span class="text-default-500 text-sm">entries</span>
|
|
624
|
+
</div>
|
|
625
|
+
{/if}
|
|
333
626
|
<span class="text-default-500 text-sm">
|
|
334
|
-
Showing {Math.min(
|
|
335
|
-
|
|
627
|
+
Showing {Math.min(
|
|
628
|
+
(internalCurrentPage - 1) * internalPageSize + 1,
|
|
629
|
+
effectiveTotalItems
|
|
630
|
+
)}
|
|
631
|
+
to {Math.min(internalCurrentPage * internalPageSize, effectiveTotalItems)} of {effectiveTotalItems}
|
|
632
|
+
entries
|
|
336
633
|
</span>
|
|
337
634
|
</div>
|
|
338
635
|
|
|
339
636
|
<div class="flex items-center gap-1">
|
|
637
|
+
{#if paginationTemplate === 'full'}
|
|
638
|
+
<!-- First page button -->
|
|
639
|
+
<button
|
|
640
|
+
type="button"
|
|
641
|
+
class={cn(
|
|
642
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
643
|
+
internalCurrentPage === 1
|
|
644
|
+
? 'text-default-300 cursor-not-allowed'
|
|
645
|
+
: 'text-default-700 hover:bg-default-100'
|
|
646
|
+
)}
|
|
647
|
+
onclick={goToFirstPage}
|
|
648
|
+
disabled={internalCurrentPage === 1}
|
|
649
|
+
aria-label="First page"
|
|
650
|
+
>
|
|
651
|
+
<!-- Double Chevron Left SVG -->
|
|
652
|
+
<svg
|
|
653
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
654
|
+
width="16"
|
|
655
|
+
height="16"
|
|
656
|
+
viewBox="0 0 24 24"
|
|
657
|
+
fill="none"
|
|
658
|
+
stroke="currentColor"
|
|
659
|
+
stroke-width="2"
|
|
660
|
+
stroke-linecap="round"
|
|
661
|
+
stroke-linejoin="round"
|
|
662
|
+
class="h-4 w-4"
|
|
663
|
+
>
|
|
664
|
+
<path d="m11 17-5-5 5-5"></path>
|
|
665
|
+
<path d="m18 17-5-5 5-5"></path>
|
|
666
|
+
</svg>
|
|
667
|
+
</button>
|
|
668
|
+
{/if}
|
|
669
|
+
|
|
670
|
+
<!-- Previous page button -->
|
|
340
671
|
<button
|
|
341
672
|
type="button"
|
|
342
673
|
class={cn(
|
|
343
674
|
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
344
|
-
|
|
675
|
+
internalCurrentPage === 1
|
|
345
676
|
? 'text-default-300 cursor-not-allowed'
|
|
346
677
|
: 'text-default-700 hover:bg-default-100'
|
|
347
678
|
)}
|
|
348
679
|
onclick={prevPage}
|
|
349
|
-
disabled={
|
|
680
|
+
disabled={internalCurrentPage === 1}
|
|
350
681
|
aria-label="Previous page"
|
|
351
682
|
>
|
|
683
|
+
<!-- Chevron Left SVG -->
|
|
352
684
|
<svg
|
|
353
685
|
xmlns="http://www.w3.org/2000/svg"
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
686
|
+
width="16"
|
|
687
|
+
height="16"
|
|
688
|
+
viewBox="0 0 24 24"
|
|
689
|
+
fill="none"
|
|
690
|
+
stroke="currentColor"
|
|
691
|
+
stroke-width="2"
|
|
692
|
+
stroke-linecap="round"
|
|
693
|
+
stroke-linejoin="round"
|
|
694
|
+
class="h-4 w-4"
|
|
357
695
|
>
|
|
358
|
-
<path
|
|
359
|
-
d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
|
|
360
|
-
/>
|
|
696
|
+
<path d="m15 18-6-6 6-6"></path>
|
|
361
697
|
</svg>
|
|
362
698
|
</button>
|
|
363
699
|
|
|
364
|
-
<!--
|
|
365
|
-
{#
|
|
366
|
-
{
|
|
367
|
-
currentPage <= 3
|
|
368
|
-
? i + 1
|
|
369
|
-
: currentPage >= totalPages - 2
|
|
370
|
-
? totalPages - 4 + i
|
|
371
|
-
: currentPage - 2 + i}
|
|
372
|
-
|
|
373
|
-
{#if pageNum > 0 && pageNum <= totalPages}
|
|
700
|
+
<!-- Page numbers -->
|
|
701
|
+
{#if paginationTemplate === 'full'}
|
|
702
|
+
{#each getPageNumbers() as pageNum}
|
|
374
703
|
<button
|
|
375
704
|
type="button"
|
|
376
705
|
class={cn(
|
|
377
706
|
'relative inline-flex items-center rounded-md px-3 py-1 text-sm font-medium',
|
|
378
|
-
|
|
707
|
+
internalCurrentPage === pageNum
|
|
379
708
|
? 'bg-primary-100 text-primary-700'
|
|
380
709
|
: 'text-default-700 hover:bg-default-100'
|
|
381
710
|
)}
|
|
382
711
|
onclick={() => goToPage(pageNum)}
|
|
383
712
|
aria-label={`Page ${pageNum}`}
|
|
384
|
-
aria-current={
|
|
713
|
+
aria-current={internalCurrentPage === pageNum ? 'page' : undefined}
|
|
385
714
|
>
|
|
386
715
|
{pageNum}
|
|
387
716
|
</button>
|
|
388
|
-
{/
|
|
389
|
-
{
|
|
717
|
+
{/each}
|
|
718
|
+
{:else}
|
|
719
|
+
<span class="text-default-500 px-2 text-sm">
|
|
720
|
+
Page {internalCurrentPage} of {totalPages}
|
|
721
|
+
</span>
|
|
722
|
+
{/if}
|
|
390
723
|
|
|
724
|
+
<!-- Next page button -->
|
|
391
725
|
<button
|
|
392
726
|
type="button"
|
|
393
727
|
class={cn(
|
|
394
728
|
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
395
|
-
|
|
729
|
+
internalCurrentPage === totalPages
|
|
396
730
|
? 'text-default-300 cursor-not-allowed'
|
|
397
731
|
: 'text-default-700 hover:bg-default-100'
|
|
398
732
|
)}
|
|
399
733
|
onclick={nextPage}
|
|
400
|
-
disabled={
|
|
734
|
+
disabled={internalCurrentPage === totalPages}
|
|
401
735
|
aria-label="Next page"
|
|
402
736
|
>
|
|
737
|
+
<!-- Chevron Right SVG -->
|
|
403
738
|
<svg
|
|
404
739
|
xmlns="http://www.w3.org/2000/svg"
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
740
|
+
width="16"
|
|
741
|
+
height="16"
|
|
742
|
+
viewBox="0 0 24 24"
|
|
743
|
+
fill="none"
|
|
744
|
+
stroke="currentColor"
|
|
745
|
+
stroke-width="2"
|
|
746
|
+
stroke-linecap="round"
|
|
747
|
+
stroke-linejoin="round"
|
|
748
|
+
class="h-4 w-4"
|
|
408
749
|
>
|
|
409
|
-
<path
|
|
410
|
-
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
|
|
411
|
-
/>
|
|
750
|
+
<path d="m9 18 6-6-6-6"></path>
|
|
412
751
|
</svg>
|
|
413
752
|
</button>
|
|
753
|
+
|
|
754
|
+
{#if paginationTemplate === 'full'}
|
|
755
|
+
<!-- Last page button -->
|
|
756
|
+
<button
|
|
757
|
+
type="button"
|
|
758
|
+
class={cn(
|
|
759
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
760
|
+
internalCurrentPage === totalPages
|
|
761
|
+
? 'text-default-300 cursor-not-allowed'
|
|
762
|
+
: 'text-default-700 hover:bg-default-100'
|
|
763
|
+
)}
|
|
764
|
+
onclick={goToLastPage}
|
|
765
|
+
disabled={internalCurrentPage === totalPages}
|
|
766
|
+
aria-label="Last page"
|
|
767
|
+
>
|
|
768
|
+
<!-- Double Chevron Right SVG -->
|
|
769
|
+
<svg
|
|
770
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
771
|
+
width="16"
|
|
772
|
+
height="16"
|
|
773
|
+
viewBox="0 0 24 24"
|
|
774
|
+
fill="none"
|
|
775
|
+
stroke="currentColor"
|
|
776
|
+
stroke-width="2"
|
|
777
|
+
stroke-linecap="round"
|
|
778
|
+
stroke-linejoin="round"
|
|
779
|
+
class="h-4 w-4"
|
|
780
|
+
>
|
|
781
|
+
<path d="m13 17 5-5-5-5"></path>
|
|
782
|
+
<path d="m6 17 5-5-5-5"></path>
|
|
783
|
+
</svg>
|
|
784
|
+
</button>
|
|
785
|
+
{/if}
|
|
414
786
|
</div>
|
|
415
787
|
</div>
|
|
416
788
|
</div>
|