]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/blob
905c2fe6f05b9bc7938308043c66a54b84ba380d
[pkg/ggml/sources/llama.cpp] /
1 <script lang="ts">
2 import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
3 import { Plus, File, MessageSquare, Zap, FolderOpen } from '@lucide/svelte';
4 import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
5 import * as Tooltip from '$lib/components/ui/tooltip';
6 import { buttonVariants } from '$lib/components/ui/button';
7 import { cn } from '$lib/components/ui/utils';
8 import {
9 ATTACHMENT_FILE_ITEMS,
10 ATTACHMENT_TOOLTIP_TEXT,
11 TOOLTIP_DELAY_DURATION
12 } from '$lib/constants';
13 import {
14 ChatFormActionAddToolsSubmenu,
15 ChatFormActionAddMcpServersSubmenu,
16 ChatFormActionAddReasoningSubmenu
17 } from '$lib/components/app';
18 import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte';
19
20 interface Props {
21 class?: string;
22 disabled?: boolean;
23 hasAudioModality?: boolean;
24 hasVideoModality?: boolean;
25 hasVisionModality?: boolean;
26 hasMcpPromptsSupport?: boolean;
27 hasMcpResourcesSupport?: boolean;
28 onFileUpload?: () => void;
29 onSystemPromptClick?: () => void;
30 onMcpPromptClick?: () => void;
31 onMcpSettingsClick?: () => void;
32 onMcpResourcesClick?: () => void;
33 }
34
35 let {
36 class: className = '',
37 disabled = false,
38 hasAudioModality = false,
39 hasVideoModality = false,
40 hasVisionModality = false,
41 hasMcpPromptsSupport = false,
42 hasMcpResourcesSupport = false,
43 onFileUpload,
44 onSystemPromptClick,
45 onMcpPromptClick,
46 onMcpSettingsClick,
47 onMcpResourcesClick
48 }: Props = $props();
49
50 let dropdownOpen = $state(false);
51
52 function handleMcpSettingsClick() {
53 dropdownOpen = false;
54 onMcpSettingsClick?.();
55 }
56
57 const attachmentMenu = useAttachmentMenu(
58 () => ({
59 hasVisionModality,
60 hasAudioModality,
61 hasVideoModality,
62 hasMcpPromptsSupport,
63 hasMcpResourcesSupport
64 }),
65 () => ({ onFileUpload, onSystemPromptClick, onMcpPromptClick, onMcpResourcesClick }),
66 () => {
67 dropdownOpen = false;
68 }
69 );
70 </script>
71
72 <div class="flex items-center gap-1 {className}">
73 <DropdownMenu.Root bind:open={dropdownOpen}>
74 <!-- ignoreNonKeyboardFocus prevents the tooltip from flashing when the
75 menu closes and focus returns to the trigger -->
76 <Tooltip.Root ignoreNonKeyboardFocus>
77 <Tooltip.Trigger>
78 {#snippet child({ props })}
79 <DropdownMenu.Trigger
80 {...props}
81 class={cn(
82 buttonVariants({ variant: 'secondary' }),
83 'file-upload-button h-8 w-8 cursor-pointer rounded-full p-0'
84 )}
85 {disabled}
86 >
87 <span class="sr-only">{ATTACHMENT_TOOLTIP_TEXT}</span>
88
89 <Plus class={ICON_CLASS_DEFAULT} />
90 </DropdownMenu.Trigger>
91 {/snippet}
92 </Tooltip.Trigger>
93
94 <Tooltip.Content>
95 <p>{ATTACHMENT_TOOLTIP_TEXT}</p>
96 </Tooltip.Content>
97 </Tooltip.Root>
98
99 <DropdownMenu.Content align="start" class="w-52">
100 <ChatFormActionAddReasoningSubmenu />
101
102 <DropdownMenu.Separator />
103
104 <DropdownMenu.Sub>
105 <DropdownMenu.SubTrigger class="flex cursor-pointer items-center gap-2">
106 <File class={ICON_CLASS_DEFAULT} />
107
108 <span>Add files</span>
109 </DropdownMenu.SubTrigger>
110
111 <DropdownMenu.SubContent class="w-48">
112 {#each ATTACHMENT_FILE_ITEMS as item (item.id)}
113 {@const enabled = attachmentMenu.isItemEnabled(item.enabledWhen)}
114 {#if enabled}
115 <DropdownMenu.Item
116 class="{item.class ?? ''} flex cursor-pointer items-center gap-2"
117 onclick={() => attachmentMenu.callbacks[item.action]()}
118 >
119 <item.icon class={ICON_CLASS_DEFAULT} />
120
121 <span>{item.label}</span>
122 </DropdownMenu.Item>
123 {:else if item.disabledTooltip}
124 <Tooltip.Root delayDuration={TOOLTIP_DELAY_DURATION}>
125 <Tooltip.Trigger tabindex={-1}>
126 {#snippet child({ props })}
127 <div {...props} class="cursor-default">
128 <DropdownMenu.Item
129 class="{item.class ?? ''} flex items-center gap-2"
130 disabled
131 >
132 <item.icon class={ICON_CLASS_DEFAULT} />
133
134 <span>{item.label}</span>
135 </DropdownMenu.Item>
136 </div>
137 {/snippet}
138 </Tooltip.Trigger>
139
140 <Tooltip.Content side="right">
141 <p>{item.disabledTooltip}</p>
142 </Tooltip.Content>
143 </Tooltip.Root>
144 {/if}
145 {/each}
146 </DropdownMenu.SubContent>
147 </DropdownMenu.Sub>
148
149 <DropdownMenu.Item
150 class="flex cursor-pointer items-center gap-2"
151 onclick={onSystemPromptClick}
152 >
153 <MessageSquare class={ICON_CLASS_DEFAULT} />
154
155 <span>System Message</span>
156 </DropdownMenu.Item>
157
158 <ChatFormActionAddToolsSubmenu />
159
160 <ChatFormActionAddMcpServersSubmenu onMcpSettingsClick={handleMcpSettingsClick} />
161
162 {#if hasMcpPromptsSupport}
163 <DropdownMenu.Separator />
164
165 <DropdownMenu.Item
166 class="flex cursor-pointer items-center gap-2"
167 onclick={onMcpPromptClick}
168 >
169 <Zap class={ICON_CLASS_DEFAULT} />
170
171 <span>MCP Prompt</span>
172 </DropdownMenu.Item>
173 {/if}
174
175 {#if hasMcpResourcesSupport}
176 <DropdownMenu.Item
177 class="flex cursor-pointer items-center gap-2"
178 onclick={onMcpResourcesClick}
179 >
180 <FolderOpen class={ICON_CLASS_DEFAULT} />
181
182 <span>MCP Resources</span>
183 </DropdownMenu.Item>
184 {/if}
185 </DropdownMenu.Content>
186 </DropdownMenu.Root>
187 </div>