@makolabs/ripple 1.2.2 → 1.2.4
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/README.md +77 -0
- package/dist/adapters/ai/OpenAIAdapter.js +16 -11
- package/dist/adapters/ai/types.d.ts +3 -3
- package/dist/adapters/storage/BaseAdapter.d.ts +1 -1
- package/dist/adapters/storage/BaseAdapter.js +1 -1
- package/dist/adapters/storage/S3Adapter.js +2 -2
- package/dist/ai/AIChatInterface.svelte +32 -34
- package/dist/ai/AIChatInterface.svelte.d.ts +0 -1
- package/dist/ai/AIChatInterfaceTestWrapper.svelte +26 -0
- package/dist/ai/AIChatInterfaceTestWrapper.svelte.d.ts +17 -0
- package/dist/ai/ChatInput.svelte +7 -15
- package/dist/ai/ChatInput.svelte.d.ts +0 -2
- package/dist/ai/CodeRenderer.svelte +25 -12
- package/dist/ai/ComposeDropdown.svelte +17 -14
- package/dist/ai/MermaidRenderer.svelte +21 -17
- package/dist/ai/MermaidRenderer.svelte.d.ts +0 -1
- package/dist/ai/MessageBox.svelte +10 -7
- package/dist/ai/ThinkingDisplay.svelte +67 -43
- package/dist/ai/ai-chat-interface.d.ts +22 -21
- package/dist/ai/ai-chat-interface.js +8 -7
- package/dist/ai/content-detector.js +2 -2
- package/dist/button/ButtonTestWrapper.svelte +10 -0
- package/dist/button/ButtonTestWrapper.svelte.d.ts +7 -0
- package/dist/charts/Chart.svelte +6 -1
- package/dist/config/ai.js +1 -0
- package/dist/drawer/DrawerTestWrapper.svelte +19 -0
- package/dist/drawer/DrawerTestWrapper.svelte.d.ts +9 -0
- package/dist/drawer/drawer.d.ts +19 -18
- package/dist/drawer/drawer.js +7 -6
- package/dist/elements/accordion/Accordion.svelte +1 -1
- package/dist/elements/accordion/Accordion.svelte.d.ts +1 -1
- package/dist/elements/accordion/AccordionTestWrapper.svelte +21 -0
- package/dist/elements/accordion/AccordionTestWrapper.svelte.d.ts +10 -0
- package/dist/elements/badge/Badge.svelte +5 -4
- package/dist/elements/badge/BadgeTestWrapper.svelte +14 -0
- package/dist/elements/badge/BadgeTestWrapper.svelte.d.ts +9 -0
- package/dist/elements/badge/badge.d.ts +40 -39
- package/dist/elements/badge/badge.js +14 -13
- package/dist/elements/dropdown/Dropdown.svelte +0 -1
- package/dist/elements/pagination/Pagination.svelte +458 -0
- package/dist/elements/pagination/Pagination.svelte.d.ts +57 -0
- package/dist/elements/progress/Progress.svelte +3 -3
- package/dist/elements/timeline/Timeline.svelte +1 -1
- package/dist/file-browser/FileBrowser.svelte +7 -10
- package/dist/filters/CompactFilters.svelte +3 -3
- package/dist/forms/Checkbox.svelte +0 -1
- package/dist/forms/CheckboxTestWrapper.svelte +8 -0
- package/dist/forms/CheckboxTestWrapper.svelte.d.ts +4 -0
- package/dist/forms/DateRange.svelte +186 -198
- package/dist/forms/Form.svelte +1 -0
- package/dist/forms/Input.svelte +14 -5
- package/dist/forms/InputTestWrapper.svelte +8 -0
- package/dist/forms/InputTestWrapper.svelte.d.ts +4 -0
- package/dist/forms/NumberInput.svelte +2 -2
- package/dist/forms/RadioInputs.svelte +1 -1
- package/dist/forms/RadioPill.svelte +1 -1
- package/dist/forms/Slider.svelte +2 -2
- package/dist/forms/Tags.svelte +3 -3
- package/dist/forms/ToggleTestWrapper.svelte +8 -0
- package/dist/forms/ToggleTestWrapper.svelte.d.ts +7 -0
- package/dist/forms/slider.js +1 -1
- package/dist/header/PageHeader.svelte +2 -1
- package/dist/header/breadcrumbs.d.ts +47 -33
- package/dist/header/breadcrumbs.js +12 -11
- package/dist/index.d.ts +8 -2
- package/dist/index.js +3 -0
- package/dist/layout/activity-list/ActivityList.svelte +9 -11
- package/dist/layout/card/CardTestWrapper.svelte +15 -0
- package/dist/layout/card/CardTestWrapper.svelte.d.ts +7 -0
- package/dist/layout/card/RankedCard.svelte +2 -3
- package/dist/layout/navbar/navbar.d.ts +19 -18
- package/dist/layout/navbar/navbar.js +7 -6
- package/dist/layout/sidebar/NavGroup.svelte +1 -0
- package/dist/layout/table/Cells.svelte +5 -5
- package/dist/layout/table/Table.svelte +477 -594
- package/dist/layout/table/table.d.ts +28 -24
- package/dist/layout/table/table.js +9 -8
- package/dist/modal/Modal.svelte +1 -1
- package/dist/modal/ModalTestWrapper.svelte +20 -0
- package/dist/modal/ModalTestWrapper.svelte.d.ts +8 -0
- package/dist/modal/modal.d.ts +1 -20
- package/dist/pipeline/Pipeline.svelte +29 -17
- package/dist/user-management/README.md +417 -0
- package/dist/user-management/UserManagement.svelte +184 -0
- package/dist/user-management/UserManagement.svelte.d.ts +4 -0
- package/dist/user-management/UserManagementTestWrapper.svelte +47 -0
- package/dist/user-management/UserManagementTestWrapper.svelte.d.ts +7 -0
- package/dist/user-management/UserModal.svelte +303 -0
- package/dist/user-management/UserModal.svelte.d.ts +4 -0
- package/dist/user-management/UserModalTestWrapper.svelte +22 -0
- package/dist/user-management/UserModalTestWrapper.svelte.d.ts +7 -0
- package/dist/user-management/UserTable.svelte +219 -0
- package/dist/user-management/UserTable.svelte.d.ts +4 -0
- package/dist/user-management/UserTableTestWrapper.svelte +41 -0
- package/dist/user-management/UserTableTestWrapper.svelte.d.ts +7 -0
- package/dist/user-management/UserViewModal.svelte +282 -0
- package/dist/user-management/UserViewModal.svelte.d.ts +4 -0
- package/dist/user-management/UserViewModalTestWrapper.svelte +22 -0
- package/dist/user-management/UserViewModalTestWrapper.svelte.d.ts +7 -0
- package/dist/user-management/index.d.ts +10 -0
- package/dist/user-management/index.js +11 -0
- package/dist/user-management/user-management.d.ts +99 -0
- package/dist/user-management/user-management.js +42 -0
- package/package.json +3 -1
- package/dist/types/markdown.d.ts +0 -14
- package/dist/types/variants.d.ts +0 -1
- package/dist/types/variants.js +0 -1
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Pagination component props
|
|
7
|
+
*/
|
|
8
|
+
export interface PaginationProps {
|
|
9
|
+
/** Current page number (1-indexed). If not provided, component manages state internally. */
|
|
10
|
+
currentPage?: number;
|
|
11
|
+
/** Total number of items across all pages */
|
|
12
|
+
totalItems: number;
|
|
13
|
+
/** Number of items per page */
|
|
14
|
+
pageSize?: number;
|
|
15
|
+
/** Callback when page changes */
|
|
16
|
+
onPageChange?: (page: number) => void;
|
|
17
|
+
/** Callback when page size changes */
|
|
18
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
19
|
+
/** Callback when first page is clicked */
|
|
20
|
+
onFirstPage?: () => void;
|
|
21
|
+
/** Callback when last page is clicked */
|
|
22
|
+
onLastPage?: () => void;
|
|
23
|
+
/** Whether pagination controls are disabled */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Show page size selector */
|
|
26
|
+
showPageSize?: boolean;
|
|
27
|
+
/** Available page size options */
|
|
28
|
+
pageSizeOptions?: number[];
|
|
29
|
+
/** Pagination template mode: 'full' shows page numbers, 'compact' shows "Page X of Y" */
|
|
30
|
+
template?: 'full' | 'compact';
|
|
31
|
+
/** Show "Showing X to Y of Z results" text */
|
|
32
|
+
showInfo?: boolean;
|
|
33
|
+
/** Show navigation buttons (first, prev, next, last) */
|
|
34
|
+
showNavigation?: boolean;
|
|
35
|
+
/** Show first/last page buttons */
|
|
36
|
+
showFirstLast?: boolean;
|
|
37
|
+
/** Show page number buttons (only applies when template='full') */
|
|
38
|
+
showPageNumbers?: boolean;
|
|
39
|
+
/** Maximum number of visible page buttons */
|
|
40
|
+
maxVisiblePages?: number;
|
|
41
|
+
/** Always show first and last page numbers when there are many pages */
|
|
42
|
+
alwaysShowFirstLast?: boolean;
|
|
43
|
+
/** Hide pagination when there's only one page */
|
|
44
|
+
hideWhenSinglePage?: boolean;
|
|
45
|
+
/** Hide pagination when there are no items */
|
|
46
|
+
hideWhenNoItems?: boolean;
|
|
47
|
+
/** Custom class for wrapper */
|
|
48
|
+
class?: ClassValue;
|
|
49
|
+
/** Custom class for info text */
|
|
50
|
+
infoClass?: ClassValue;
|
|
51
|
+
/** Custom class for navigation buttons */
|
|
52
|
+
buttonClass?: ClassValue;
|
|
53
|
+
/** Custom class for active page button */
|
|
54
|
+
activeButtonClass?: ClassValue;
|
|
55
|
+
/** Use internal state management (when currentPage is not provided) */
|
|
56
|
+
internalState?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let {
|
|
60
|
+
currentPage: externalCurrentPage,
|
|
61
|
+
totalItems,
|
|
62
|
+
pageSize: externalPageSize,
|
|
63
|
+
onPageChange,
|
|
64
|
+
onPageSizeChange,
|
|
65
|
+
onFirstPage,
|
|
66
|
+
onLastPage,
|
|
67
|
+
disabled = false,
|
|
68
|
+
showPageSize = false,
|
|
69
|
+
pageSizeOptions = [5, 10, 25, 50, 100],
|
|
70
|
+
template = 'full',
|
|
71
|
+
showInfo = true,
|
|
72
|
+
showNavigation = true,
|
|
73
|
+
showFirstLast = true,
|
|
74
|
+
showPageNumbers = true,
|
|
75
|
+
maxVisiblePages = 5,
|
|
76
|
+
alwaysShowFirstLast = true,
|
|
77
|
+
hideWhenSinglePage = true,
|
|
78
|
+
hideWhenNoItems = true,
|
|
79
|
+
class: wrapperClass = '',
|
|
80
|
+
infoClass = '',
|
|
81
|
+
buttonClass = '',
|
|
82
|
+
activeButtonClass = '',
|
|
83
|
+
internalState = false
|
|
84
|
+
}: PaginationProps = $props();
|
|
85
|
+
|
|
86
|
+
// Internal state management
|
|
87
|
+
const defaultPageSize = 10;
|
|
88
|
+
let internalCurrentPage = $state(externalCurrentPage ?? 1);
|
|
89
|
+
let internalPageSize = $state(externalPageSize ?? defaultPageSize);
|
|
90
|
+
|
|
91
|
+
// Use external values if provided, otherwise use internal state or defaults
|
|
92
|
+
const currentPage = $derived(
|
|
93
|
+
externalCurrentPage !== undefined
|
|
94
|
+
? externalCurrentPage
|
|
95
|
+
: internalState
|
|
96
|
+
? internalCurrentPage
|
|
97
|
+
: 1
|
|
98
|
+
);
|
|
99
|
+
const pageSize = $derived(
|
|
100
|
+
externalPageSize !== undefined
|
|
101
|
+
? externalPageSize
|
|
102
|
+
: internalState
|
|
103
|
+
? internalPageSize
|
|
104
|
+
: defaultPageSize
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Sync external page size changes
|
|
108
|
+
$effect(() => {
|
|
109
|
+
if (externalPageSize !== undefined) {
|
|
110
|
+
internalPageSize = externalPageSize;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Sync external current page changes
|
|
115
|
+
$effect(() => {
|
|
116
|
+
if (externalCurrentPage !== undefined) {
|
|
117
|
+
internalCurrentPage = externalCurrentPage;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Validation: ensure pageSize is valid
|
|
122
|
+
const validPageSize = $derived(Math.max(1, pageSize));
|
|
123
|
+
// Validation: ensure totalItems is non-negative
|
|
124
|
+
const validTotalItems = $derived(Math.max(0, totalItems));
|
|
125
|
+
|
|
126
|
+
// Computed values
|
|
127
|
+
const totalPages = $derived(Math.ceil(validTotalItems / validPageSize));
|
|
128
|
+
const startItem = $derived(Math.min((currentPage - 1) * validPageSize + 1, validTotalItems));
|
|
129
|
+
const endItem = $derived(Math.min(currentPage * validPageSize, validTotalItems));
|
|
130
|
+
|
|
131
|
+
// Ensure currentPage is within valid range
|
|
132
|
+
const validCurrentPage = $derived(Math.max(1, Math.min(currentPage, totalPages || 1)));
|
|
133
|
+
|
|
134
|
+
// Navigation functions
|
|
135
|
+
function goToPage(page: number) {
|
|
136
|
+
if (!disabled && page >= 1 && page <= totalPages && page !== validCurrentPage) {
|
|
137
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
138
|
+
internalCurrentPage = page;
|
|
139
|
+
}
|
|
140
|
+
onPageChange?.(page);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function firstPage() {
|
|
145
|
+
if (!disabled && validCurrentPage > 1) {
|
|
146
|
+
const targetPage = 1;
|
|
147
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
148
|
+
internalCurrentPage = targetPage;
|
|
149
|
+
}
|
|
150
|
+
onPageChange?.(targetPage);
|
|
151
|
+
onFirstPage?.();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function lastPage() {
|
|
156
|
+
if (!disabled && validCurrentPage < totalPages) {
|
|
157
|
+
const targetPage = totalPages;
|
|
158
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
159
|
+
internalCurrentPage = targetPage;
|
|
160
|
+
}
|
|
161
|
+
onPageChange?.(targetPage);
|
|
162
|
+
onLastPage?.();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function nextPage() {
|
|
167
|
+
if (!disabled && validCurrentPage < totalPages) {
|
|
168
|
+
const targetPage = validCurrentPage + 1;
|
|
169
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
170
|
+
internalCurrentPage = targetPage;
|
|
171
|
+
}
|
|
172
|
+
onPageChange?.(targetPage);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function prevPage() {
|
|
177
|
+
if (!disabled && validCurrentPage > 1) {
|
|
178
|
+
const targetPage = validCurrentPage - 1;
|
|
179
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
180
|
+
internalCurrentPage = targetPage;
|
|
181
|
+
}
|
|
182
|
+
onPageChange?.(targetPage);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function handlePageSizeChange(event: Event) {
|
|
187
|
+
if (disabled) return;
|
|
188
|
+
const select = event.target as HTMLSelectElement;
|
|
189
|
+
const newPageSize = parseInt(select.value, 10);
|
|
190
|
+
|
|
191
|
+
if (isNaN(newPageSize) || newPageSize < 1) return;
|
|
192
|
+
|
|
193
|
+
// Calculate new total pages
|
|
194
|
+
const newTotalPages = Math.ceil(validTotalItems / newPageSize);
|
|
195
|
+
|
|
196
|
+
// Adjust current page if it would exceed the new total pages
|
|
197
|
+
let adjustedPage = validCurrentPage;
|
|
198
|
+
if (validCurrentPage > newTotalPages) {
|
|
199
|
+
adjustedPage = newTotalPages || 1;
|
|
200
|
+
if (internalState && externalCurrentPage === undefined) {
|
|
201
|
+
internalCurrentPage = adjustedPage;
|
|
202
|
+
}
|
|
203
|
+
onPageChange?.(adjustedPage);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Update page size
|
|
207
|
+
if (internalState && externalPageSize === undefined) {
|
|
208
|
+
internalPageSize = newPageSize;
|
|
209
|
+
}
|
|
210
|
+
onPageSizeChange?.(newPageSize);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Calculate which page numbers to display
|
|
215
|
+
*/
|
|
216
|
+
function getPageNumbers(): number[] {
|
|
217
|
+
if (totalPages <= maxVisiblePages) {
|
|
218
|
+
// Show all pages if total is less than or equal to max
|
|
219
|
+
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const pages: number[] = [];
|
|
223
|
+
const halfMax = Math.floor(maxVisiblePages / 2);
|
|
224
|
+
|
|
225
|
+
// Calculate start and end of visible range, centered around current page
|
|
226
|
+
let start = Math.max(1, validCurrentPage - halfMax);
|
|
227
|
+
let end = Math.min(totalPages, start + maxVisiblePages - 1);
|
|
228
|
+
|
|
229
|
+
// Adjust if we're near the end
|
|
230
|
+
if (end - start + 1 < maxVisiblePages) {
|
|
231
|
+
start = Math.max(1, end - maxVisiblePages + 1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Build page numbers array
|
|
235
|
+
for (let i = start; i <= end; i++) {
|
|
236
|
+
pages.push(i);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return pages;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Determine if we should show pagination
|
|
243
|
+
const shouldShowPagination = $derived(!hideWhenNoItems || validTotalItems > 0);
|
|
244
|
+
const shouldShowControls = $derived(!hideWhenSinglePage || totalPages > 1);
|
|
245
|
+
|
|
246
|
+
// Default classes using ripple-ui design system
|
|
247
|
+
const defaultWrapperClass = 'flex items-center justify-between p-4';
|
|
248
|
+
const defaultInfoClass = 'text-default-500 text-sm';
|
|
249
|
+
const defaultButtonClass =
|
|
250
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium';
|
|
251
|
+
const defaultActiveButtonClass = 'bg-primary-100 text-primary-700';
|
|
252
|
+
const defaultInactiveButtonClass = 'text-default-700 hover:bg-default-100';
|
|
253
|
+
const defaultDisabledButtonClass = 'text-default-300 cursor-not-allowed';
|
|
254
|
+
const defaultPageButtonClass =
|
|
255
|
+
'relative inline-flex items-center rounded-md px-3 py-1 text-sm font-medium';
|
|
256
|
+
</script>
|
|
257
|
+
|
|
258
|
+
{#if shouldShowPagination}
|
|
259
|
+
<div class={cn(defaultWrapperClass, wrapperClass)}>
|
|
260
|
+
{#if showInfo}
|
|
261
|
+
<div class="flex items-center gap-2">
|
|
262
|
+
{#if showPageSize}
|
|
263
|
+
<div class="flex items-center gap-2">
|
|
264
|
+
<label for="pagination-page-size" class="text-default-500 text-sm">Show</label>
|
|
265
|
+
<select
|
|
266
|
+
id="pagination-page-size"
|
|
267
|
+
class={cn(
|
|
268
|
+
'border-default-200 rounded-md border px-2 py-1 text-sm',
|
|
269
|
+
disabled && 'cursor-not-allowed opacity-50'
|
|
270
|
+
)}
|
|
271
|
+
value={pageSize}
|
|
272
|
+
onchange={handlePageSizeChange}
|
|
273
|
+
{disabled}
|
|
274
|
+
>
|
|
275
|
+
{#each pageSizeOptions as option (option)}
|
|
276
|
+
<option value={option}>{option}</option>
|
|
277
|
+
{/each}
|
|
278
|
+
</select>
|
|
279
|
+
<span class="text-default-500 text-sm">entries</span>
|
|
280
|
+
</div>
|
|
281
|
+
{/if}
|
|
282
|
+
<span class={cn(defaultInfoClass, infoClass)}>
|
|
283
|
+
Showing {startItem} to {endItem} of {validTotalItems} entries
|
|
284
|
+
</span>
|
|
285
|
+
</div>
|
|
286
|
+
{/if}
|
|
287
|
+
|
|
288
|
+
{#if shouldShowControls && showNavigation}
|
|
289
|
+
<div class="flex items-center gap-1">
|
|
290
|
+
{#if showFirstLast}
|
|
291
|
+
<button
|
|
292
|
+
onclick={firstPage}
|
|
293
|
+
disabled={disabled || validCurrentPage === 1}
|
|
294
|
+
class={cn(
|
|
295
|
+
defaultButtonClass,
|
|
296
|
+
buttonClass,
|
|
297
|
+
disabled || validCurrentPage === 1
|
|
298
|
+
? defaultDisabledButtonClass
|
|
299
|
+
: defaultInactiveButtonClass
|
|
300
|
+
)}
|
|
301
|
+
aria-label="First page"
|
|
302
|
+
type="button"
|
|
303
|
+
>
|
|
304
|
+
«
|
|
305
|
+
</button>
|
|
306
|
+
{/if}
|
|
307
|
+
|
|
308
|
+
<button
|
|
309
|
+
onclick={prevPage}
|
|
310
|
+
disabled={disabled || validCurrentPage === 1}
|
|
311
|
+
class={cn(
|
|
312
|
+
defaultButtonClass,
|
|
313
|
+
buttonClass,
|
|
314
|
+
disabled || validCurrentPage === 1
|
|
315
|
+
? defaultDisabledButtonClass
|
|
316
|
+
: defaultInactiveButtonClass
|
|
317
|
+
)}
|
|
318
|
+
aria-label="Previous page"
|
|
319
|
+
type="button"
|
|
320
|
+
>
|
|
321
|
+
‹
|
|
322
|
+
</button>
|
|
323
|
+
|
|
324
|
+
{#if template === 'full' && showPageNumbers}
|
|
325
|
+
{#if totalPages <= maxVisiblePages}
|
|
326
|
+
<!-- Show all pages if total is less than or equal to maxVisiblePages -->
|
|
327
|
+
{#each Array(totalPages) as page, i (page + i)}
|
|
328
|
+
{@const pageNum = i + 1}
|
|
329
|
+
<button
|
|
330
|
+
onclick={() => goToPage(pageNum)}
|
|
331
|
+
{disabled}
|
|
332
|
+
class={cn(
|
|
333
|
+
defaultPageButtonClass,
|
|
334
|
+
buttonClass,
|
|
335
|
+
validCurrentPage === pageNum
|
|
336
|
+
? cn(defaultActiveButtonClass, activeButtonClass)
|
|
337
|
+
: defaultInactiveButtonClass
|
|
338
|
+
)}
|
|
339
|
+
aria-label="Page {pageNum}"
|
|
340
|
+
aria-current={validCurrentPage === pageNum ? 'page' : undefined}
|
|
341
|
+
type="button"
|
|
342
|
+
>
|
|
343
|
+
{pageNum}
|
|
344
|
+
</button>
|
|
345
|
+
{/each}
|
|
346
|
+
{:else}
|
|
347
|
+
<!-- Smart pagination for many pages -->
|
|
348
|
+
{@const pageNumbers = getPageNumbers()}
|
|
349
|
+
{@const showFirst = alwaysShowFirstLast && pageNumbers[0] > 1}
|
|
350
|
+
{@const showLast =
|
|
351
|
+
alwaysShowFirstLast && pageNumbers[pageNumbers.length - 1] < totalPages}
|
|
352
|
+
|
|
353
|
+
{#if showFirst}
|
|
354
|
+
<button
|
|
355
|
+
onclick={() => goToPage(1)}
|
|
356
|
+
{disabled}
|
|
357
|
+
class={cn(
|
|
358
|
+
defaultPageButtonClass,
|
|
359
|
+
buttonClass,
|
|
360
|
+
validCurrentPage === 1
|
|
361
|
+
? cn(defaultActiveButtonClass, activeButtonClass)
|
|
362
|
+
: defaultInactiveButtonClass
|
|
363
|
+
)}
|
|
364
|
+
aria-label="Page 1"
|
|
365
|
+
aria-current={validCurrentPage === 1 ? 'page' : undefined}
|
|
366
|
+
type="button"
|
|
367
|
+
>
|
|
368
|
+
1
|
|
369
|
+
</button>
|
|
370
|
+
{#if pageNumbers[0] > 2}
|
|
371
|
+
<span class="text-default-400 px-2 text-sm">...</span>
|
|
372
|
+
{/if}
|
|
373
|
+
{/if}
|
|
374
|
+
|
|
375
|
+
{#each pageNumbers as pageNum (pageNum)}
|
|
376
|
+
<button
|
|
377
|
+
onclick={() => goToPage(pageNum)}
|
|
378
|
+
{disabled}
|
|
379
|
+
class={cn(
|
|
380
|
+
defaultPageButtonClass,
|
|
381
|
+
buttonClass,
|
|
382
|
+
validCurrentPage === pageNum
|
|
383
|
+
? cn(defaultActiveButtonClass, activeButtonClass)
|
|
384
|
+
: defaultInactiveButtonClass
|
|
385
|
+
)}
|
|
386
|
+
aria-label="Page {pageNum}"
|
|
387
|
+
aria-current={validCurrentPage === pageNum ? 'page' : undefined}
|
|
388
|
+
type="button"
|
|
389
|
+
>
|
|
390
|
+
{pageNum}
|
|
391
|
+
</button>
|
|
392
|
+
{/each}
|
|
393
|
+
|
|
394
|
+
{#if showLast}
|
|
395
|
+
{#if pageNumbers[pageNumbers.length - 1] < totalPages - 1}
|
|
396
|
+
<span class="text-default-400 px-2 text-sm">...</span>
|
|
397
|
+
{/if}
|
|
398
|
+
<button
|
|
399
|
+
onclick={() => goToPage(totalPages)}
|
|
400
|
+
{disabled}
|
|
401
|
+
class={cn(
|
|
402
|
+
defaultPageButtonClass,
|
|
403
|
+
buttonClass,
|
|
404
|
+
validCurrentPage === totalPages
|
|
405
|
+
? cn(defaultActiveButtonClass, activeButtonClass)
|
|
406
|
+
: defaultInactiveButtonClass
|
|
407
|
+
)}
|
|
408
|
+
aria-label="Page {totalPages}"
|
|
409
|
+
aria-current={validCurrentPage === totalPages ? 'page' : undefined}
|
|
410
|
+
type="button"
|
|
411
|
+
>
|
|
412
|
+
{totalPages}
|
|
413
|
+
</button>
|
|
414
|
+
{/if}
|
|
415
|
+
{/if}
|
|
416
|
+
{:else if template === 'compact'}
|
|
417
|
+
<span class="text-default-500 px-2 text-sm">
|
|
418
|
+
Page {validCurrentPage} of {totalPages}
|
|
419
|
+
</span>
|
|
420
|
+
{/if}
|
|
421
|
+
|
|
422
|
+
<button
|
|
423
|
+
onclick={nextPage}
|
|
424
|
+
disabled={disabled || validCurrentPage === totalPages}
|
|
425
|
+
class={cn(
|
|
426
|
+
defaultButtonClass,
|
|
427
|
+
buttonClass,
|
|
428
|
+
disabled || validCurrentPage === totalPages
|
|
429
|
+
? defaultDisabledButtonClass
|
|
430
|
+
: defaultInactiveButtonClass
|
|
431
|
+
)}
|
|
432
|
+
aria-label="Next page"
|
|
433
|
+
type="button"
|
|
434
|
+
>
|
|
435
|
+
›
|
|
436
|
+
</button>
|
|
437
|
+
|
|
438
|
+
{#if showFirstLast}
|
|
439
|
+
<button
|
|
440
|
+
onclick={lastPage}
|
|
441
|
+
disabled={disabled || validCurrentPage === totalPages}
|
|
442
|
+
class={cn(
|
|
443
|
+
defaultButtonClass,
|
|
444
|
+
buttonClass,
|
|
445
|
+
disabled || validCurrentPage === totalPages
|
|
446
|
+
? defaultDisabledButtonClass
|
|
447
|
+
: defaultInactiveButtonClass
|
|
448
|
+
)}
|
|
449
|
+
aria-label="Last page"
|
|
450
|
+
type="button"
|
|
451
|
+
>
|
|
452
|
+
»
|
|
453
|
+
</button>
|
|
454
|
+
{/if}
|
|
455
|
+
</div>
|
|
456
|
+
{/if}
|
|
457
|
+
</div>
|
|
458
|
+
{/if}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
+
/**
|
|
3
|
+
* Pagination component props
|
|
4
|
+
*/
|
|
5
|
+
export interface PaginationProps {
|
|
6
|
+
/** Current page number (1-indexed). If not provided, component manages state internally. */
|
|
7
|
+
currentPage?: number;
|
|
8
|
+
/** Total number of items across all pages */
|
|
9
|
+
totalItems: number;
|
|
10
|
+
/** Number of items per page */
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
/** Callback when page changes */
|
|
13
|
+
onPageChange?: (page: number) => void;
|
|
14
|
+
/** Callback when page size changes */
|
|
15
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
16
|
+
/** Callback when first page is clicked */
|
|
17
|
+
onFirstPage?: () => void;
|
|
18
|
+
/** Callback when last page is clicked */
|
|
19
|
+
onLastPage?: () => void;
|
|
20
|
+
/** Whether pagination controls are disabled */
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Show page size selector */
|
|
23
|
+
showPageSize?: boolean;
|
|
24
|
+
/** Available page size options */
|
|
25
|
+
pageSizeOptions?: number[];
|
|
26
|
+
/** Pagination template mode: 'full' shows page numbers, 'compact' shows "Page X of Y" */
|
|
27
|
+
template?: 'full' | 'compact';
|
|
28
|
+
/** Show "Showing X to Y of Z results" text */
|
|
29
|
+
showInfo?: boolean;
|
|
30
|
+
/** Show navigation buttons (first, prev, next, last) */
|
|
31
|
+
showNavigation?: boolean;
|
|
32
|
+
/** Show first/last page buttons */
|
|
33
|
+
showFirstLast?: boolean;
|
|
34
|
+
/** Show page number buttons (only applies when template='full') */
|
|
35
|
+
showPageNumbers?: boolean;
|
|
36
|
+
/** Maximum number of visible page buttons */
|
|
37
|
+
maxVisiblePages?: number;
|
|
38
|
+
/** Always show first and last page numbers when there are many pages */
|
|
39
|
+
alwaysShowFirstLast?: boolean;
|
|
40
|
+
/** Hide pagination when there's only one page */
|
|
41
|
+
hideWhenSinglePage?: boolean;
|
|
42
|
+
/** Hide pagination when there are no items */
|
|
43
|
+
hideWhenNoItems?: boolean;
|
|
44
|
+
/** Custom class for wrapper */
|
|
45
|
+
class?: ClassValue;
|
|
46
|
+
/** Custom class for info text */
|
|
47
|
+
infoClass?: ClassValue;
|
|
48
|
+
/** Custom class for navigation buttons */
|
|
49
|
+
buttonClass?: ClassValue;
|
|
50
|
+
/** Custom class for active page button */
|
|
51
|
+
activeButtonClass?: ClassValue;
|
|
52
|
+
/** Use internal state management (when currentPage is not provided) */
|
|
53
|
+
internalState?: boolean;
|
|
54
|
+
}
|
|
55
|
+
declare const Pagination: import("svelte").Component<PaginationProps, {}, "">;
|
|
56
|
+
type Pagination = ReturnType<typeof Pagination>;
|
|
57
|
+
export default Pagination;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
3
|
import { Color, Size } from '../../variants.js';
|
|
4
|
-
import type { ProgressProps,
|
|
4
|
+
import type { ProgressProps, VariantColors } from '../../index.js';
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
value,
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
aria-valuemax="100"
|
|
105
105
|
>
|
|
106
106
|
{#if segments}
|
|
107
|
-
{#each segmentPercentages as segment}
|
|
107
|
+
{#each segmentPercentages as segment (segment.label || segment.value)}
|
|
108
108
|
{#if segment.percentage > 0}
|
|
109
109
|
<div
|
|
110
110
|
class={cn(getColorClass(segment.color), barClass)}
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
|
|
121
121
|
{#if segments && (showLabels || showValues)}
|
|
122
122
|
<div class="mt-1 flex justify-between">
|
|
123
|
-
{#each segmentPercentages as segment}
|
|
123
|
+
{#each segmentPercentages as segment (segment.label || segment.value)}
|
|
124
124
|
{#if segment.percentage > 0}
|
|
125
125
|
<div class={labelTextClass}>
|
|
126
126
|
{#if showLabels && segment.label}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import type { TableColumn, FileBrowserProps } from '../index.js';
|
|
5
5
|
import { formatDate } from '../utils/dateUtils.js';
|
|
6
6
|
import type {
|
|
7
|
-
StorageAdapter,
|
|
8
7
|
FileItem,
|
|
9
8
|
Breadcrumb,
|
|
10
9
|
FileAction,
|
|
@@ -198,7 +197,9 @@
|
|
|
198
197
|
const folderFile = files.find((file) => file.key === folderPath);
|
|
199
198
|
if (folderFile && folderFile.name && adapter.getName() === 'Google Drive') {
|
|
200
199
|
// Assuming the adapter might have a setFolderName method
|
|
201
|
-
(adapter
|
|
200
|
+
if ('setFolderName' in adapter && typeof adapter.setFolderName === 'function') {
|
|
201
|
+
adapter.setFolderName(folderPath, folderFile.name);
|
|
202
|
+
}
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
// Store the currently selected files before navigation
|
|
@@ -416,13 +417,11 @@
|
|
|
416
417
|
// Check if any single action allows this file
|
|
417
418
|
const hasAllowedAction = actions.some((action) => {
|
|
418
419
|
// Only check single file actions for individual file selection
|
|
419
|
-
if ('action' in action && typeof action.action === 'function'
|
|
420
|
+
if ('action' in action && typeof action.action === 'function') {
|
|
420
421
|
return action.isAllowed(item);
|
|
421
422
|
}
|
|
422
423
|
return false;
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
// Always allow folders to be selected (for recursive selection)
|
|
424
|
+
}); // Always allow folders to be selected (for recursive selection)
|
|
426
425
|
return item.isFolder || hasAllowedAction;
|
|
427
426
|
});
|
|
428
427
|
|
|
@@ -446,9 +445,6 @@
|
|
|
446
445
|
newFolders.forEach((folder) => {
|
|
447
446
|
handleSelectFolder(folder);
|
|
448
447
|
});
|
|
449
|
-
|
|
450
|
-
// Update select all state
|
|
451
|
-
const nonFolderFiles = displayFiles.filter((file) => !file.isFolder);
|
|
452
448
|
}
|
|
453
449
|
|
|
454
450
|
async function fetchFilesFromFolder(folderKey: string, folderName: string) {
|
|
@@ -493,6 +489,7 @@
|
|
|
493
489
|
if (!folder.isFolder) return;
|
|
494
490
|
|
|
495
491
|
isFetchingRecursively = true;
|
|
492
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
496
493
|
processedFolders = new Set();
|
|
497
494
|
// Don't clear fileQueue entirely, it will lose files from other folders
|
|
498
495
|
// Store existing fileQueue
|
|
@@ -727,7 +724,7 @@
|
|
|
727
724
|
<span class="text-default-400 mx-1 text-sm">/</span>
|
|
728
725
|
|
|
729
726
|
<div class="flex flex-wrap items-center">
|
|
730
|
-
{#each breadcrumbs as crumb, i}
|
|
727
|
+
{#each breadcrumbs as crumb, i (crumb.path)}
|
|
731
728
|
{#if i > 0}
|
|
732
729
|
<span class="text-default-400 mx-1 text-sm">/</span>
|
|
733
730
|
{/if}
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
{#if !isExpanded}
|
|
101
101
|
<!-- Summary of selected filters when collapsed -->
|
|
102
102
|
<div class={cn('flex flex-wrap gap-2', summaryClass)}>
|
|
103
|
-
{#each filterGroups as group}
|
|
103
|
+
{#each filterGroups as group (group.label)}
|
|
104
104
|
{#if group.tabs.length > 0}
|
|
105
105
|
<div
|
|
106
106
|
class="bg-primary-50 text-primary-700 border-primary-200 flex items-center gap-1 rounded-full border px-3 py-1 text-xs"
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
</div>
|
|
114
114
|
{:else}
|
|
115
115
|
<div class={cn('flex flex-col gap-2', expandedClass)}>
|
|
116
|
-
{#each filterGroups as group, index}
|
|
116
|
+
{#each filterGroups as group, index (group.label)}
|
|
117
117
|
{#if group.tabs.length > 0}
|
|
118
118
|
<div
|
|
119
119
|
class={cn(
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
{group.label}
|
|
126
126
|
</div>
|
|
127
127
|
<div class="flex flex-wrap gap-2">
|
|
128
|
-
{#each group.tabs as tab}
|
|
128
|
+
{#each group.tabs as tab (tab.value)}
|
|
129
129
|
<button
|
|
130
130
|
onclick={() => group.onChange(tab.value)}
|
|
131
131
|
class={cn(
|