@makolabs/ripple 0.0.1-dev.21 → 0.0.1-dev.23
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.
|
@@ -8,11 +8,8 @@
|
|
|
8
8
|
maxSize,
|
|
9
9
|
class: className = '',
|
|
10
10
|
dropzoneClass = '',
|
|
11
|
-
previewClass = '',
|
|
12
11
|
id = 'file-upload',
|
|
13
|
-
onfiles = undefined
|
|
14
|
-
ondelete = undefined,
|
|
15
|
-
files = []
|
|
12
|
+
onfiles = undefined
|
|
16
13
|
}: FileUploadProps = $props();
|
|
17
14
|
|
|
18
15
|
const disabled = $derived(maxFiles <= 0);
|
|
@@ -25,10 +22,6 @@
|
|
|
25
22
|
if (onfiles) onfiles(newFiles);
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
function handleDeleteFile(fileId: string, index: number) {
|
|
29
|
-
if (ondelete) ondelete(fileId, index);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
25
|
function handleDragEnter(e: DragEvent) {
|
|
33
26
|
e.preventDefault();
|
|
34
27
|
e.stopPropagation();
|
|
@@ -130,84 +123,4 @@
|
|
|
130
123
|
</div>
|
|
131
124
|
</div>
|
|
132
125
|
</label>
|
|
133
|
-
|
|
134
|
-
<!-- File List -->
|
|
135
|
-
{#if files.length > 0}
|
|
136
|
-
<ul class={cn('mt-6 space-y-3', previewClass)}>
|
|
137
|
-
{#each files as file, i (i)}
|
|
138
|
-
<li
|
|
139
|
-
class={cn('flex items-center justify-between rounded-xl p-4 ring-4', {
|
|
140
|
-
'bg-danger-50 ring-danger-100': file.status === 'error',
|
|
141
|
-
'bg-success-50 ring-success-100': file.status === 'success',
|
|
142
|
-
'ring-primary-100/30 bg-white': file.status === 'uploading'
|
|
143
|
-
})}
|
|
144
|
-
>
|
|
145
|
-
<div class="flex flex-1 items-center gap-3">
|
|
146
|
-
<!-- File Icon -->
|
|
147
|
-
<div
|
|
148
|
-
class={cn('flex size-10 items-center justify-center rounded-full', {
|
|
149
|
-
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
150
|
-
'bg-success-100 text-success-500': file.status === 'success',
|
|
151
|
-
'bg-primary-100 text-primary-500': file.status === 'uploading'
|
|
152
|
-
})}
|
|
153
|
-
>
|
|
154
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24">
|
|
155
|
-
<path
|
|
156
|
-
fill="currentColor"
|
|
157
|
-
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
|
|
158
|
-
/>
|
|
159
|
-
</svg>
|
|
160
|
-
</div>
|
|
161
|
-
|
|
162
|
-
<div class="flex-1">
|
|
163
|
-
<!-- Filename and Size -->
|
|
164
|
-
<div class="mb-1 flex items-center justify-between">
|
|
165
|
-
<span class="text-default-700 font-medium">{file.OriginalFilename}</span>
|
|
166
|
-
<span class="text-default-500 text-sm">{formatFileSize(file.Size)}</span>
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<!-- Status Information -->
|
|
170
|
-
{#if file.status === 'uploading'}
|
|
171
|
-
<div class="bg-default-100 h-1.5 w-full rounded-full">
|
|
172
|
-
<div
|
|
173
|
-
class="bg-primary-500 h-1.5 rounded-full transition-all duration-300"
|
|
174
|
-
style="width: {file.progress || 0}%"
|
|
175
|
-
></div>
|
|
176
|
-
</div>
|
|
177
|
-
<span class="text-default-500 mt-1 text-sm">{file.progress || 0}%</span>
|
|
178
|
-
{:else if file.status === 'error'}
|
|
179
|
-
<div class="flex items-center justify-between">
|
|
180
|
-
<span class="text-danger-500 text-sm">Upload failed!</span>
|
|
181
|
-
<span class="text-danger-600 cursor-help text-sm font-medium"
|
|
182
|
-
>Please try again!</span
|
|
183
|
-
>
|
|
184
|
-
</div>
|
|
185
|
-
{:else if file.status === 'success'}
|
|
186
|
-
<p class="text-success-500 text-sm">Upload Successful!</p>
|
|
187
|
-
{/if}
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
<button
|
|
192
|
-
type="button"
|
|
193
|
-
aria-label="Delete file"
|
|
194
|
-
class={cn('ml-4 flex size-6 cursor-pointer items-center justify-center rounded-lg', {
|
|
195
|
-
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
196
|
-
'bg-success-100 text-success-500': file.status === 'success',
|
|
197
|
-
'bg-default-100 text-default-500': file.status === 'uploading'
|
|
198
|
-
})}
|
|
199
|
-
onclick={() => (file.FileID ? handleDeleteFile(file.FileID, i) : ondelete?.('', i))}
|
|
200
|
-
disabled={file.status === 'uploading'}
|
|
201
|
-
>
|
|
202
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24">
|
|
203
|
-
<path
|
|
204
|
-
fill="currentColor"
|
|
205
|
-
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41z"
|
|
206
|
-
/>
|
|
207
|
-
</svg>
|
|
208
|
-
</button>
|
|
209
|
-
</li>
|
|
210
|
-
{/each}
|
|
211
|
-
</ul>
|
|
212
|
-
{/if}
|
|
213
126
|
</div>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import type { FilePreviewProps } from '../../index.js';
|
|
4
|
+
|
|
5
|
+
let { files = [], ondelete, class: className = '' }: FilePreviewProps = $props();
|
|
6
|
+
|
|
7
|
+
function formatFileSize(bytes: number): string {
|
|
8
|
+
if (bytes === 0) return '0 B';
|
|
9
|
+
const k = 1024;
|
|
10
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
11
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
12
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))}${sizes[i]}`;
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
{#if files.length > 0}
|
|
17
|
+
<ul class={cn('mt-6 space-y-3', className)}>
|
|
18
|
+
{#each files as file, i (i)}
|
|
19
|
+
<li
|
|
20
|
+
class={cn('flex items-center justify-between rounded-xl p-4 ring-4', {
|
|
21
|
+
'bg-danger-50 ring-danger-100': file.status === 'error',
|
|
22
|
+
'bg-success-50 ring-success-100': file.status === 'success',
|
|
23
|
+
'ring-primary-100/30 bg-white': file.status === 'uploading'
|
|
24
|
+
})}
|
|
25
|
+
>
|
|
26
|
+
<div class="flex flex-1 items-center gap-3">
|
|
27
|
+
<!-- File Icon -->
|
|
28
|
+
<div
|
|
29
|
+
class={cn('flex size-10 items-center justify-center rounded-full', {
|
|
30
|
+
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
31
|
+
'bg-success-100 text-success-500': file.status === 'success',
|
|
32
|
+
'bg-primary-100 text-primary-500': file.status === 'uploading'
|
|
33
|
+
})}
|
|
34
|
+
>
|
|
35
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24">
|
|
36
|
+
<path
|
|
37
|
+
fill="currentColor"
|
|
38
|
+
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="flex-1">
|
|
44
|
+
<!-- Filename and Size -->
|
|
45
|
+
<div class="mb-1 flex items-center justify-between">
|
|
46
|
+
<span class="text-default-700 font-medium">{file.OriginalFilename}</span>
|
|
47
|
+
<span class="text-default-500 text-sm">{formatFileSize(file.Size)}</span>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Status Information -->
|
|
51
|
+
{#if file.status === 'uploading'}
|
|
52
|
+
<div class="bg-default-100 h-1.5 w-full rounded-full">
|
|
53
|
+
<div
|
|
54
|
+
class="bg-primary-500 h-1.5 rounded-full transition-all duration-300"
|
|
55
|
+
style="width: {file.progress || 0}%"
|
|
56
|
+
></div>
|
|
57
|
+
</div>
|
|
58
|
+
<span class="text-default-500 mt-1 text-sm">{file.progress || 0}%</span>
|
|
59
|
+
{:else if file.status === 'error'}
|
|
60
|
+
<div class="flex items-center justify-between">
|
|
61
|
+
<span class="text-danger-500 text-sm">Upload failed!</span>
|
|
62
|
+
<span class="text-danger-600 cursor-help text-sm font-medium"
|
|
63
|
+
>Please try again!</span
|
|
64
|
+
>
|
|
65
|
+
</div>
|
|
66
|
+
{:else if file.status === 'success'}
|
|
67
|
+
<p class="text-success-500 text-sm">Upload Successful!</p>
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
aria-label="Delete file"
|
|
75
|
+
class={cn('ml-4 flex size-6 cursor-pointer items-center justify-center rounded-lg', {
|
|
76
|
+
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
77
|
+
'bg-success-100 text-success-500': file.status === 'success',
|
|
78
|
+
'bg-default-100 text-default-500': file.status === 'uploading'
|
|
79
|
+
})}
|
|
80
|
+
onclick={() => (file.FileID ? ondelete?.(file.FileID, i) : ondelete?.('', i))}
|
|
81
|
+
disabled={file.status === 'uploading'}
|
|
82
|
+
>
|
|
83
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24">
|
|
84
|
+
<path
|
|
85
|
+
fill="currentColor"
|
|
86
|
+
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41z"
|
|
87
|
+
/>
|
|
88
|
+
</svg>
|
|
89
|
+
</button>
|
|
90
|
+
</li>
|
|
91
|
+
{/each}
|
|
92
|
+
</ul>
|
|
93
|
+
{/if}
|
package/dist/index.d.ts
CHANGED
|
@@ -459,7 +459,7 @@ export interface FileUploadProps {
|
|
|
459
459
|
*/
|
|
460
460
|
allowedMimeTypes?: string[];
|
|
461
461
|
/**
|
|
462
|
-
* Maximum file size in bytes
|
|
462
|
+
* Maximum file size in bytes
|
|
463
463
|
*/
|
|
464
464
|
maxSize?: number;
|
|
465
465
|
/**
|
|
@@ -475,10 +475,6 @@ export interface FileUploadProps {
|
|
|
475
475
|
* CSS class for the dropzone
|
|
476
476
|
*/
|
|
477
477
|
dropzoneClass?: string;
|
|
478
|
-
/**
|
|
479
|
-
* CSS class for the preview area
|
|
480
|
-
*/
|
|
481
|
-
previewClass?: string;
|
|
482
478
|
/**
|
|
483
479
|
* ID for the file input element
|
|
484
480
|
* @default 'file-upload'
|
|
@@ -488,34 +484,11 @@ export interface FileUploadProps {
|
|
|
488
484
|
* Callback when files are selected or dropped
|
|
489
485
|
*/
|
|
490
486
|
onfiles?: (files: FileList | File[]) => void;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
487
|
+
}
|
|
488
|
+
export interface FilePreviewProps {
|
|
489
|
+
files: UploadedFile[];
|
|
494
490
|
ondelete?: (fileId: string, index: number) => void;
|
|
495
|
-
|
|
496
|
-
* Current files array to display
|
|
497
|
-
*/
|
|
498
|
-
files?: UploadedFile[];
|
|
499
|
-
/**
|
|
500
|
-
* API URL for file upload
|
|
501
|
-
*/
|
|
502
|
-
apiUrl?: string;
|
|
503
|
-
/**
|
|
504
|
-
* Authorization token for API requests
|
|
505
|
-
*/
|
|
506
|
-
apiToken?: string;
|
|
507
|
-
/**
|
|
508
|
-
* Handler for unsuccessful file uploads
|
|
509
|
-
*/
|
|
510
|
-
onerror?: (error: string) => void;
|
|
511
|
-
/**
|
|
512
|
-
* Expired time in days
|
|
513
|
-
*/
|
|
514
|
-
expiry?: `${string}d`;
|
|
515
|
-
/**
|
|
516
|
-
* Additional metadata to be sent with the file
|
|
517
|
-
*/
|
|
518
|
-
metadata?: Record<string, string>;
|
|
491
|
+
class?: string;
|
|
519
492
|
}
|
|
520
493
|
export interface UploadedFile {
|
|
521
494
|
FileID: string;
|
|
@@ -540,6 +513,7 @@ export interface UploadedFile {
|
|
|
540
513
|
error?: string;
|
|
541
514
|
}
|
|
542
515
|
export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
|
|
516
|
+
export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
|
|
543
517
|
export { default as Toaster } from './sonner/sonner.svelte';
|
|
544
518
|
export interface FormProps<T extends Record<string, unknown>> {
|
|
545
519
|
form: SuperForm<any>;
|
package/dist/index.js
CHANGED
|
@@ -48,6 +48,7 @@ export { selectTV } from './elements/dropdown/select.js';
|
|
|
48
48
|
export { breadcrumbs } from './header/breadcrumbs.js';
|
|
49
49
|
export { default as Chart } from './charts/Chart.svelte';
|
|
50
50
|
export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
|
|
51
|
+
export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
|
|
51
52
|
// Toaster: Should be registered in +layout.svelte
|
|
52
53
|
export { default as Toaster } from './sonner/sonner.svelte';
|
|
53
54
|
// Form Component Exports
|