feat: Attachments UX improvements

This commit is contained in:
Aleksander Grygier 2025-11-21 21:23:20 +01:00
parent 69503aa519
commit 92585c7173
3 changed files with 82 additions and 43 deletions

View File

@ -30,7 +30,9 @@
}: Props = $props(); }: Props = $props();
</script> </script>
<div class="group relative overflow-hidden rounded-lg border border-border bg-muted {className}"> <div
class="group relative overflow-hidden rounded-lg bg-muted shadow-lg dark:border dark:border-muted {className}"
>
{#if onClick} {#if onClick}
<button <button
type="button" type="button"

View File

@ -183,26 +183,87 @@
{#if displayItems.length > 0} {#if displayItems.length > 0}
<div class={className} {style}> <div class={className} {style}>
<div class="relative"> {#if limitToSingleRow}
<button <div class="relative">
class="absolute top-1/2 left-4 z-10 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full bg-foreground/15 shadow-md backdrop-blur-xs transition-opacity hover:bg-foreground/35 {canScrollLeft <button
? 'opacity-100' class="absolute top-1/2 left-4 z-10 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full bg-foreground/15 shadow-md backdrop-blur-xs transition-opacity hover:bg-foreground/35 {canScrollLeft
: 'pointer-events-none opacity-0'}" ? 'opacity-100'
onclick={scrollLeft} : 'pointer-events-none opacity-0'}"
aria-label="Scroll left" onclick={scrollLeft}
> aria-label="Scroll left"
<ChevronLeft class="h-4 w-4" /> >
</button> <ChevronLeft class="h-4 w-4" />
</button>
<div <div
class="scrollbar-hide flex items-start gap-3 overflow-x-auto" class="scrollbar-hide flex items-start gap-3 overflow-x-auto"
bind:this={scrollContainer} bind:this={scrollContainer}
onscroll={updateScrollButtons} onscroll={updateScrollButtons}
> >
{#each displayItems as item (item.id)}
{#if item.isImage && item.preview}
<ChatAttachmentThumbnailImage
class="flex-shrink-0 cursor-pointer {limitToSingleRow
? 'first:ml-4 last:mr-4'
: ''}"
id={item.id}
name={item.name}
preview={item.preview}
{readonly}
onRemove={onFileRemove}
height={imageHeight}
width={imageWidth}
{imageClass}
onClick={(event) => openPreview(item, event)}
/>
{:else}
<ChatAttachmentThumbnailFile
class="flex-shrink-0 cursor-pointer {limitToSingleRow
? 'first:ml-4 last:mr-4'
: ''}"
id={item.id}
name={item.name}
type={item.type}
size={item.size}
{readonly}
onRemove={onFileRemove}
textContent={item.textContent}
onClick={(event) => openPreview(item, event)}
/>
{/if}
{/each}
</div>
<button
class="absolute top-1/2 right-4 z-10 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full bg-foreground/15 shadow-md backdrop-blur-xs transition-opacity hover:bg-foreground/35 {canScrollRight
? 'opacity-100'
: 'pointer-events-none opacity-0'}"
onclick={scrollRight}
aria-label="Scroll right"
>
<ChevronRight class="h-4 w-4" />
</button>
</div>
{#if showViewAll}
<div class="mt-2 -mr-2 flex justify-end px-4">
<Button
type="button"
variant="ghost"
size="sm"
class="h-6 text-xs text-muted-foreground hover:text-foreground"
onclick={() => (viewAllDialogOpen = true)}
>
View all ({displayItems.length})
</Button>
</div>
{/if}
{:else}
<div class="flex flex-wrap justify-end gap-3">
{#each displayItems as item (item.id)} {#each displayItems as item (item.id)}
{#if item.isImage && item.preview} {#if item.isImage && item.preview}
<ChatAttachmentThumbnailImage <ChatAttachmentThumbnailImage
class="flex-shrink-0 cursor-pointer {limitToSingleRow ? 'first:ml-4 last:mr-4' : ''}" class="cursor-pointer"
id={item.id} id={item.id}
name={item.name} name={item.name}
preview={item.preview} preview={item.preview}
@ -215,7 +276,7 @@
/> />
{:else} {:else}
<ChatAttachmentThumbnailFile <ChatAttachmentThumbnailFile
class="flex-shrink-0 cursor-pointer {limitToSingleRow ? 'first:ml-4 last:mr-4' : ''}" class="cursor-pointer"
id={item.id} id={item.id}
name={item.name} name={item.name}
type={item.type} type={item.type}
@ -228,30 +289,6 @@
{/if} {/if}
{/each} {/each}
</div> </div>
<button
class="absolute top-1/2 right-4 z-10 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full bg-foreground/15 shadow-md backdrop-blur-xs transition-opacity hover:bg-foreground/35 {canScrollRight
? 'opacity-100'
: 'pointer-events-none opacity-0'}"
onclick={scrollRight}
aria-label="Scroll right"
>
<ChevronRight class="h-4 w-4" />
</button>
</div>
{#if showViewAll}
<div class="mt-2 -mr-2 flex justify-end px-4">
<Button
type="button"
variant="ghost"
size="sm"
class="h-6 text-xs text-muted-foreground hover:text-foreground"
onclick={() => (viewAllDialogOpen = true)}
>
View all
</Button>
</div>
{/if} {/if}
</div> </div>
{/if} {/if}

View File

@ -224,7 +224,7 @@
<div class="space-y-1"> <div class="space-y-1">
<label <label
for={field.key} for={field.key}
class="cursor-pointer text-sm leading-none font-medium {isDisabled class="cursor-pointer pt-1 pb-0.5 text-sm leading-none font-medium {isDisabled
? 'text-muted-foreground' ? 'text-muted-foreground'
: ''} flex items-center gap-1.5" : ''} flex items-center gap-1.5"
> >