|
| 1 | +<script setup lang="ts"> |
| 2 | +import type { FileUIPart } from 'ai' |
| 3 | +import type { HTMLAttributes } from 'vue' |
| 4 | +import { Button } from '@repo/shadcn-vue/components/ui/button' |
| 5 | +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@repo/shadcn-vue/components/ui/tooltip' |
| 6 | +import { cn } from '@repo/shadcn-vue/lib/utils' |
| 7 | +import { PaperclipIcon, XIcon } from 'lucide-vue-next' |
| 8 | +import { computed } from 'vue' |
| 9 | +
|
| 10 | +interface Props { |
| 11 | + data: FileUIPart |
| 12 | + class?: HTMLAttributes['class'] |
| 13 | +} |
| 14 | +const props = defineProps<Props>() |
| 15 | +
|
| 16 | +const emits = defineEmits<{ |
| 17 | + (e: 'remove'): void |
| 18 | +}>() |
| 19 | +
|
| 20 | +const filename = computed(() => props.data.filename || '') |
| 21 | +const mediaType = computed(() => |
| 22 | + props.data.mediaType?.startsWith('image/') && props.data.url ? 'image' : 'file', |
| 23 | +) |
| 24 | +const isImage = computed(() => mediaType.value === 'image') |
| 25 | +const attachmentLabel = computed(() => |
| 26 | + filename.value || (isImage.value ? 'Image' : 'Attachment'), |
| 27 | +) |
| 28 | +</script> |
| 29 | + |
| 30 | +<template> |
| 31 | + <div |
| 32 | + :class=" |
| 33 | + cn( |
| 34 | + 'group relative size-24 overflow-hidden rounded-lg', |
| 35 | + props.class, |
| 36 | + ) |
| 37 | + " |
| 38 | + v-bind="$attrs" |
| 39 | + > |
| 40 | + <template v-if="isImage"> |
| 41 | + <img |
| 42 | + :src="props.data.url" |
| 43 | + :alt="filename || 'attachment'" |
| 44 | + class="size-full object-cover" |
| 45 | + height="100" |
| 46 | + width="100" |
| 47 | + > |
| 48 | + <Button |
| 49 | + aria-label="Remove attachment" |
| 50 | + class="absolute top-2 right-2 size-6 rounded-full bg-background/80 p-0 opacity-0 backdrop-blur-sm transition-opacity hover:bg-background group-hover:opacity-100 [&>svg]:size-3" |
| 51 | + type="button" |
| 52 | + variant="ghost" |
| 53 | + @click.stop="emits('remove')" |
| 54 | + > |
| 55 | + <XIcon /> |
| 56 | + <span class="sr-only">Remove</span> |
| 57 | + </Button> |
| 58 | + </template> |
| 59 | + |
| 60 | + <template v-else> |
| 61 | + <TooltipProvider> |
| 62 | + <Tooltip> |
| 63 | + <TooltipTrigger as-child> |
| 64 | + <div |
| 65 | + class="flex size-full shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground" |
| 66 | + > |
| 67 | + <PaperclipIcon class="size-4" /> |
| 68 | + </div> |
| 69 | + </TooltipTrigger> |
| 70 | + <TooltipContent> |
| 71 | + <p>{{ attachmentLabel }}</p> |
| 72 | + </TooltipContent> |
| 73 | + </Tooltip> |
| 74 | + </TooltipProvider> |
| 75 | + <Button |
| 76 | + aria-label="Remove attachment" |
| 77 | + class="size-6 shrink-0 rounded-full p-0 opacity-0 transition-opacity hover:bg-accent group-hover:opacity-100 [&>svg]:size-3" |
| 78 | + type="button" |
| 79 | + variant="ghost" |
| 80 | + @click.stop="emits('remove')" |
| 81 | + > |
| 82 | + <XIcon /> |
| 83 | + <span class="sr-only">Remove</span> |
| 84 | + </Button> |
| 85 | + </template> |
| 86 | + </div> |
| 87 | +</template> |
0 commit comments