2 import { Plus } from '@lucide/svelte';
3 import { Button } from '$lib/components/ui/button';
4 import * as Tooltip from '$lib/components/ui/tooltip';
5 import * as Sheet from '$lib/components/ui/sheet';
6 import { TOOLTIP_DELAY_DURATION } from '$lib/constants';
9 ATTACHMENT_EXTRA_ITEMS,
11 ATTACHMENT_TOOLTIP_TEXT
12 } from '$lib/constants/attachment-menu';
13 import { ChatFormActionToolsSubmenu, ChatFormActionMcpServersSubmenu } from '$lib/components/app';
14 import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte';
15 import { AttachmentMenuItemId } from '$lib/enums';
20 hasAudioModality?: boolean;
21 hasVisionModality?: boolean;
22 hasMcpPromptsSupport?: boolean;
23 hasMcpResourcesSupport?: boolean;
24 onFileUpload?: () => void;
25 onSystemPromptClick?: () => void;
26 onMcpPromptClick?: () => void;
27 onMcpSettingsClick?: () => void;
28 onMcpResourcesClick?: () => void;
32 class: className = '',
34 hasAudioModality = false,
35 hasVisionModality = false,
36 hasMcpPromptsSupport = false,
37 hasMcpResourcesSupport = false,
45 let sheetOpen = $state(false);
47 const attachmentMenu = useAttachmentMenu(
48 () => ({ hasVisionModality, hasAudioModality, hasMcpPromptsSupport, hasMcpResourcesSupport }),
49 () => ({ onFileUpload, onSystemPromptClick, onMcpPromptClick, onMcpResourcesClick }),
55 function handleMcpSettingsClick() {
57 onMcpSettingsClick?.();
60 const sheetItemClass =
61 'flex w-full items-center gap-3 rounded-md px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent active:bg-accent disabled:cursor-not-allowed disabled:opacity-50';
64 <div class="flex items-center gap-1 {className}">
65 <Sheet.Root bind:open={sheetOpen}>
67 class="file-upload-button h-8 w-8 rounded-full p-0"
71 onclick={() => (sheetOpen = true)}
73 <span class="sr-only">{ATTACHMENT_TOOLTIP_TEXT}</span>
75 <Plus class="h-4 w-4" />
78 <Sheet.Content side="bottom" class="max-h-[85vh] gap-0 overflow-y-auto">
80 <Sheet.Title>Add to chat</Sheet.Title>
82 <Sheet.Description class="sr-only">
83 Add files, system prompt or configure MCP servers
87 <div class="flex flex-col gap-1 px-1.5 pb-2">
88 {#each ATTACHMENT_FILE_ITEMS as item (item.id)}
89 {@const enabled = attachmentMenu.isItemEnabled(item.enabledWhen)}
93 class={sheetItemClass}
94 onclick={() => attachmentMenu.callbacks[item.action]()}
96 <item.icon class="h-4 w-4 shrink-0" />
98 <span>{item.label}</span>
100 {:else if item.disabledTooltip}
101 <Tooltip.Root delayDuration={TOOLTIP_DELAY_DURATION}>
103 <button type="button" class={sheetItemClass} disabled>
104 <item.icon class="h-4 w-4 shrink-0" />
106 <span>{item.label}</span>
110 <Tooltip.Content side="right">
111 <p>{item.disabledTooltip}</p>
117 {#if !attachmentMenu.isItemEnabled('hasVisionModality')}
118 {@const pdfItem = ATTACHMENT_FILE_ITEMS.find((i) => i.id === AttachmentMenuItemId.PDF)}
120 <Tooltip.Root delayDuration={TOOLTIP_DELAY_DURATION}>
124 class={sheetItemClass}
125 onclick={() => attachmentMenu.callbacks[pdfItem.action]()}
127 <pdfItem.icon class="h-4 w-4 shrink-0" />
129 <span>{pdfItem.label}</span>
133 <Tooltip.Content side="right">
134 <p>PDFs will be converted to text. Image-based PDFs may not work properly.</p>
140 {#each ATTACHMENT_EXTRA_ITEMS as item (item.id)}
141 {#if item.id === AttachmentMenuItemId.SYSTEM_MESSAGE}
142 <Tooltip.Root delayDuration={TOOLTIP_DELAY_DURATION}>
146 class={sheetItemClass}
147 onclick={() => attachmentMenu.callbacks[item.action]()}
149 <item.icon class="h-4 w-4 shrink-0" />
151 <span>{item.label}</span>
155 <Tooltip.Content side="right">
156 <p>{attachmentMenu.getSystemMessageTooltip()}</p>
162 <div class="my-2 border-t"></div>
164 <ChatFormActionToolsSubmenu />
166 <ChatFormActionMcpServersSubmenu onMcpSettingsClick={handleMcpSettingsClick} />
168 {#each ATTACHMENT_MCP_ITEMS as item (item.id)}
169 {#if attachmentMenu.isItemVisible(item.visibleWhen)}
172 class={sheetItemClass}
173 onclick={() => attachmentMenu.callbacks[item.action]()}
175 <item.icon class="h-4 w-4 shrink-0" />
177 <span>{item.label}</span>