aboutsummaryrefslogtreecommitdiff
path: root/llama.cpp/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsViewAll.svelte
blob: 279b2e22273bd40a3e1b37005d9cfff354506b81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<script lang="ts">
	import {
		ChatAttachmentThumbnailImage,
		ChatAttachmentThumbnailFile,
		DialogChatAttachmentPreview
	} from '$lib/components/app';
	import { getAttachmentDisplayItems } from '$lib/utils';

	interface Props {
		uploadedFiles?: ChatUploadedFile[];
		attachments?: DatabaseMessageExtra[];
		readonly?: boolean;
		onFileRemove?: (fileId: string) => void;
		imageHeight?: string;
		imageWidth?: string;
		imageClass?: string;
		activeModelId?: string;
	}

	let {
		uploadedFiles = [],
		attachments = [],
		readonly = false,
		onFileRemove,
		imageHeight = 'h-24',
		imageWidth = 'w-auto',
		imageClass = '',
		activeModelId
	}: Props = $props();

	let previewDialogOpen = $state(false);
	let previewItem = $state<ChatAttachmentPreviewItem | null>(null);

	let displayItems = $derived(getAttachmentDisplayItems({ uploadedFiles, attachments }));
	let imageItems = $derived(displayItems.filter((item) => item.isImage));
	let fileItems = $derived(displayItems.filter((item) => !item.isImage));

	function openPreview(item: (typeof displayItems)[0], event?: Event) {
		if (event) {
			event.preventDefault();
			event.stopPropagation();
		}

		previewItem = {
			uploadedFile: item.uploadedFile,
			attachment: item.attachment,
			preview: item.preview,
			name: item.name,
			size: item.size,
			textContent: item.textContent
		};
		previewDialogOpen = true;
	}
</script>

<div class="space-y-4">
	<div class="min-h-0 flex-1 space-y-6 overflow-y-auto px-1">
		{#if fileItems.length > 0}
			<div>
				<h3 class="mb-3 text-sm font-medium text-foreground">Files ({fileItems.length})</h3>
				<div class="flex flex-wrap items-start gap-3">
					{#each fileItems as item (item.id)}
						<ChatAttachmentThumbnailFile
							class="cursor-pointer"
							id={item.id}
							name={item.name}
							size={item.size}
							{readonly}
							onRemove={onFileRemove}
							textContent={item.textContent}
							attachment={item.attachment}
							uploadedFile={item.uploadedFile}
							onClick={(event?: MouseEvent) => openPreview(item, event)}
						/>
					{/each}
				</div>
			</div>
		{/if}

		{#if imageItems.length > 0}
			<div>
				<h3 class="mb-3 text-sm font-medium text-foreground">Images ({imageItems.length})</h3>
				<div class="flex flex-wrap items-start gap-3">
					{#each imageItems as item (item.id)}
						{#if item.preview}
							<ChatAttachmentThumbnailImage
								class="cursor-pointer"
								id={item.id}
								name={item.name}
								preview={item.preview}
								{readonly}
								onRemove={onFileRemove}
								height={imageHeight}
								width={imageWidth}
								{imageClass}
								onClick={(event) => openPreview(item, event)}
							/>
						{/if}
					{/each}
				</div>
			</div>
		{/if}
	</div>
</div>

{#if previewItem}
	<DialogChatAttachmentPreview
		bind:open={previewDialogOpen}
		uploadedFile={previewItem.uploadedFile}
		attachment={previewItem.attachment}
		preview={previewItem.preview}
		name={previewItem.name}
		size={previewItem.size}
		textContent={previewItem.textContent}
		{activeModelId}
	/>
{/if}