From 7ef15c2e1a5b9ff5745523ca9fd0f6ce1738c9d2 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Tue, 7 Apr 2026 10:51:30 +0100 Subject: [PATCH 1/3] feat: add progress bar support to Upload.Box component Add optional progress prop to file items in Upload.Box. When provided, renders an animated progress bar below each file row and shows the percentage instead of the Pending badge. Fully backwards compatible. --- v2/pink-sb/src/lib/upload/Box.svelte | 165 +++++++++++------- .../src/stories/upload/Box.stories.svelte | 39 +++++ 2 files changed, 142 insertions(+), 62 deletions(-) diff --git a/v2/pink-sb/src/lib/upload/Box.svelte b/v2/pink-sb/src/lib/upload/Box.svelte index 7211dc582a..27d47a83f4 100644 --- a/v2/pink-sb/src/lib/upload/Box.svelte +++ b/v2/pink-sb/src/lib/upload/Box.svelte @@ -22,6 +22,7 @@ size?: number; extension?: string; error?: string; + progress?: number; status?: 'failed' | 'pending' | 'success'; })[] = []; @@ -67,75 +68,96 @@
{#each files as file} {@const fileSize = file?.size ? humanFileSize(file.size) : false} + {@const hasProgress = typeof file?.progress === 'number'}
- - - - - - {file.name} - - {#if fileSize} - - - ({fileSize.value} - {fileSize.unit}) - + + + + + + + {file.name} - {/if} + {#if fileSize} + + + ({fileSize.value} + {fileSize.unit}) + + + {/if} + - - - {#if file?.status === 'success'} - - {:else} - {#if file?.error} - - - - {:else if file?.status === 'pending'} - - + {#if file?.status === 'success'} + + {:else} + {#if file?.error} + + + + {:else if hasProgress} + + {file.progress}% + + {:else if file?.status === 'pending'} + + + + {/if} + {/if} - - {/if} + + {#if hasProgress && file?.status !== 'success'} +
+
+
+ {/if}
{/each} @@ -171,4 +193,23 @@ flex-shrink: 1; } } + + .upload-progress-bar { + height: 4px; + width: 100%; + border-radius: var(--border-radius-XS, 4px); + background: var(--bgcolor-neutral-secondary, hsl(0 0% 90%)); + overflow: hidden; + + &-fill { + height: 100%; + border-radius: inherit; + background: var(--bgcolor-information, hsl(220 80% 55%)); + transition: width 0.3s ease; + } + + &.is-error &-fill { + background: var(--bgcolor-error, hsl(0 70% 55%)); + } + } diff --git a/v2/pink-sb/src/stories/upload/Box.stories.svelte b/v2/pink-sb/src/stories/upload/Box.stories.svelte index 86419fb66f..70288f5844 100644 --- a/v2/pink-sb/src/stories/upload/Box.stories.svelte +++ b/v2/pink-sb/src/stories/upload/Box.stories.svelte @@ -28,6 +28,38 @@ status: 'pending' } ]; + + let filesWithProgress = [ + { + name: 'uploading-file.png', + extension: 'png', + size: 15728640, + status: 'pending', + progress: 45 + }, + { + name: 'almost-done.pdf', + extension: 'pdf', + size: 8388608, + status: 'pending', + progress: 92 + }, + { + name: 'completed-file.jpg', + extension: 'jpg', + size: 41024, + status: 'success', + progress: 100 + }, + { + name: 'failed-upload.zip', + extension: 'zip', + size: 52428800, + status: 'failed', + error: 'File exceeds size limit', + progress: 60 + } + ];