This commit is contained in:
Timothy Jaeryang Baek
2026-07-14 17:07:39 -04:00
parent e39ff71532
commit eb11029eac
6 changed files with 136 additions and 135 deletions
@@ -53,106 +53,103 @@
}
</script>
<DropdownMenu
className="{(filteredItems ?? []).length > 0
? ''
: 'hidden'} w-72 font-sans text-xs"
id="suggestions-container"
>
<div class="overflow-y-auto scrollbar-thin max-h-60">
{#if char === '/'}
<Prompts
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
<div class={(filteredItems ?? []).length > 0 ? '' : 'hidden'} id="suggestions-container">
<DropdownMenu className="w-72 font-sans text-xs">
<div class="overflow-y-auto scrollbar-thin max-h-60">
{#if char === '/'}
<Prompts
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'prompt') {
insertTextHandler(data.content);
}
}}
/>
{:else if char === '#'}
<Knowledge
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'prompt') {
insertTextHandler(data.content);
}
}}
/>
{:else if char === '#'}
<Knowledge
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'knowledge') {
insertTextHandler('');
if (type === 'knowledge') {
insertTextHandler('');
onUpload({
type: 'file',
data: data
});
} else if (type === 'web') {
insertTextHandler('');
onUpload({
type: 'file',
data: data
});
} else if (type === 'web') {
insertTextHandler('');
onUpload({
type: 'web',
data: data
});
}
}}
/>
{:else if char === '@'}
<Models
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
onUpload({
type: 'web',
data: data
});
}
}}
/>
{:else if char === '@'}
<Models
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'model') {
insertTextHandler('');
if (type === 'model') {
insertTextHandler('');
onSelect({
type: 'model',
data: data
});
}
}}
/>
{:else if char === '$'}
<Skills
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
onSelect({
type: 'model',
data: data
});
}
}}
/>
{:else if char === '$'}
<Skills
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'skill') {
command({
id: `${data.id}|${data.name}`,
label: data.name
});
if (type === 'skill') {
command({
id: `${data.id}|${data.name}`,
label: data.name
});
onSelect({
type: 'skill',
data: data
});
}
}}
/>
{:else if char === ':'}
<Emojis
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
onSelect({
type: 'skill',
data: data
});
}
}}
/>
{:else if char === ':'}
<Emojis
bind:this={suggestionElement}
{query}
bind:filteredItems
onSelect={(e) => {
const { type, data } = e;
if (type === 'emoji') {
command({
id: data.name,
label: data.shortCodes[0]
});
}
}}
/>
{/if}
</div>
</DropdownMenu>
if (type === 'emoji') {
command({
id: data.name,
label: data.shortCodes[0]
});
}
}}
/>
{/if}
</div>
</DropdownMenu>
</div>
@@ -64,14 +64,15 @@
</script>
{#if filteredItems.length > 0}
<div class="px-2 text-xs text-gray-500 py-1">
<div class="px-2 py-1 text-[11px] text-gray-500 dark:text-gray-400">
{$i18n.t('Emojis')}
</div>
{#each filteredItems as emoji, emojiIdx}
<button
class="px-2.5 py-1.5 rounded-xl w-full text-left {emojiIdx === selectedIdx
? 'bg-gray-50 dark:bg-gray-800 selected-command-option-button'
class="flex h-[1.6875rem] w-full items-center rounded-xl px-2 text-left text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 {emojiIdx ===
selectedIdx
? 'bg-gray-50/40 dark:bg-gray-800/40 selected-command-option-button'
: ''}"
type="button"
on:click={() => {
@@ -83,14 +84,14 @@
on:focus={() => {}}
data-selected={emojiIdx === selectedIdx}
>
<div class="flex items-center gap-2 text-black dark:text-gray-100">
<div class="flex min-w-0 items-center gap-2 text-black dark:text-gray-100">
<img
src="{WEBUI_BASE_URL}/assets/emojis/{emoji.name.toLowerCase()}.svg"
alt={emoji.name}
class="size-5 flex-shrink-0"
class="size-4.5 flex-shrink-0"
loading="lazy"
/>
<div class="truncate text-sm">
<div class="truncate text-[13px]">
:{emoji.shortCodes[0]}:
</div>
</div>
@@ -142,7 +142,7 @@
{#if filteredItems.length > 0 || query.startsWith('http')}
{#each filteredItems as item, idx}
{#if idx === 0 || item?.type !== items[idx - 1]?.type}
<div class="px-2 text-xs text-gray-500 py-1">
<div class="px-2 py-1 text-[11px] text-gray-500 dark:text-gray-400">
{#if item?.type === 'folder'}
{$i18n.t('Folders')}
{:else if item?.type === 'collection'}
@@ -155,9 +155,9 @@
{#if !['youtube', 'web'].includes(item.type)}
<button
class=" px-2 py-1 rounded-xl w-full text-left flex justify-between items-center {idx ===
class="flex h-[1.6875rem] w-full items-center justify-between rounded-xl px-2 text-left text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 {idx ===
selectedIdx
? ' bg-gray-50 dark:bg-gray-800 dark:text-gray-100 selected-command-option-button'
? 'bg-gray-50/40 dark:bg-gray-800/40 dark:text-gray-100 selected-command-option-button'
: ''}"
type="button"
on:click={() => {
@@ -172,7 +172,7 @@
}}
data-selected={idx === selectedIdx}
>
<div class=" text-black dark:text-gray-100 flex items-center gap-1">
<div class="flex min-w-0 items-center gap-1.5 text-black dark:text-gray-100">
<Tooltip
content={item?.legacy
? $i18n.t('Legacy')
@@ -184,16 +184,16 @@
placement="top"
>
{#if item?.type === 'collection'}
<Database className="size-4" />
<Database className="size-3.5" />
{:else if item?.type === 'folder'}
<Folder className="size-4" />
<Folder className="size-3.5" />
{:else}
<DocumentPage className="size-4" />
<DocumentPage className="size-3.5" />
{/if}
</Tooltip>
<Tooltip content={`${decodeString(item?.name)}`} placement="top-start">
<div class="line-clamp-1 flex-1">
<div class="min-w-0 flex-1 truncate">
{decodeString(item?.name)}
</div>
</Tooltip>
@@ -204,7 +204,7 @@
{#if isYoutubeUrl(query)}
<button
class="px-2 py-1 rounded-xl w-full text-left bg-gray-50 dark:bg-gray-800 dark:text-gray-100 selected-command-option-button"
class="flex h-[1.6875rem] w-full items-center rounded-xl bg-gray-50/40 px-2 text-left text-[13px] dark:bg-gray-800/40 dark:text-gray-100 selected-command-option-button"
type="button"
data-selected={selectedIdx === filteredItems.findIndex((i) => i.type === 'youtube')}
on:click={() => {
@@ -220,19 +220,19 @@
}
}}
>
<div class=" text-black dark:text-gray-100 line-clamp-1 flex items-center gap-1">
<div class="flex min-w-0 items-center gap-1.5 text-black dark:text-gray-100">
<Tooltip content={$i18n.t('YouTube')} placement="top">
<Youtube className="size-4" />
<Youtube className="size-3.5" />
</Tooltip>
<div class="truncate flex-1">
<div class="min-w-0 flex-1 truncate">
{query}
</div>
</div>
</button>
{:else if query.startsWith('http')}
<button
class="px-2 py-1 rounded-xl w-full text-left bg-gray-50 dark:bg-gray-800 dark:text-gray-100 selected-command-option-button"
class="flex h-[1.6875rem] w-full items-center rounded-xl bg-gray-50/40 px-2 text-left text-[13px] dark:bg-gray-800/40 dark:text-gray-100 selected-command-option-button"
type="button"
data-selected={selectedIdx === filteredItems.findIndex((i) => i.type === 'web')}
on:click={() => {
@@ -248,12 +248,12 @@
}
}}
>
<div class=" text-black dark:text-gray-100 line-clamp-1 flex items-center gap-1">
<div class="flex min-w-0 items-center gap-1.5 text-black dark:text-gray-100">
<Tooltip content={$i18n.t('Web')} placement="top">
<GlobeAlt className="size-4" />
<GlobeAlt className="size-3.5" />
</Tooltip>
<div class="truncate flex-1">
<div class="min-w-0 flex-1 truncate">
{query}
</div>
</div>
@@ -60,7 +60,7 @@
};
</script>
<div class="px-2 text-xs text-gray-500 py-1">
<div class="px-2 py-1 text-[11px] text-gray-500 dark:text-gray-400">
{$i18n.t('Models')}
</div>
@@ -68,8 +68,9 @@
{#each filteredItems as model, modelIdx}
<Tooltip content={model.id} placement="top-start">
<button
class="px-2.5 py-1.5 rounded-xl w-full text-left {modelIdx === selectedIdx
? 'bg-gray-50 dark:bg-gray-800 selected-command-option-button'
class="flex h-[1.6875rem] w-full items-center rounded-xl px-2 text-left text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 {modelIdx ===
selectedIdx
? 'bg-gray-50/40 dark:bg-gray-800/40 selected-command-option-button'
: ''}"
type="button"
on:click={() => {
@@ -81,16 +82,16 @@
on:focus={() => {}}
data-selected={modelIdx === selectedIdx}
>
<div class="flex text-black dark:text-gray-100 line-clamp-1">
<div class="flex min-w-0 items-center text-black dark:text-gray-100">
<img
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model.id}&lang=${$i18n.language}`}
alt={model?.name ?? model.id}
class="rounded-full size-5 items-center mr-2"
class="mr-2 size-4.5 rounded-full object-cover"
on:error={(e) => {
e.currentTarget.src = '/favicon.png';
}}
/>
<div class="truncate">
<div class="min-w-0 truncate">
{model.name}
</div>
</div>
@@ -57,18 +57,19 @@
};
</script>
<div class="px-2 text-xs text-gray-500 py-1">
<div class="px-2 py-1 text-[11px] text-gray-500 dark:text-gray-400">
{$i18n.t('Prompts')}
</div>
{#if filteredItems.length > 0}
<div class=" space-y-0.5 scrollbar-hidden">
<div class="scrollbar-hidden">
{#each filteredItems as promptItem, promptIdx}
<Tooltip content={promptItem.name} placement="top-start">
<button
class=" px-3 py-1 rounded-xl w-full text-left {promptIdx === selectedPromptIdx
? ' bg-gray-50 dark:bg-gray-800 selected-command-option-button'
: ''} truncate"
class="flex h-[1.6875rem] w-full items-center gap-1.5 rounded-xl px-2 text-left text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 {promptIdx ===
selectedPromptIdx
? 'bg-gray-50/40 dark:bg-gray-800/40 selected-command-option-button'
: ''}"
type="button"
on:click={() => {
onSelect({ type: 'prompt', data: promptItem });
@@ -79,11 +80,11 @@
on:focus={() => {}}
data-selected={promptIdx === selectedPromptIdx}
>
<span class=" font-normal text-black dark:text-gray-100">
<span class="shrink-0 font-normal text-black dark:text-gray-100">
{promptItem.command}
</span>
<span class=" text-xs text-gray-600 dark:text-gray-100">
<span class="min-w-0 truncate text-xs text-gray-500 dark:text-gray-400">
{promptItem.name}
</span>
</button>
@@ -69,7 +69,7 @@
};
</script>
<div class="px-2 text-xs text-gray-500 py-1">
<div class="px-2 py-1 text-[11px] text-gray-500 dark:text-gray-400">
{$i18n.t('Skills')}
</div>
@@ -81,8 +81,9 @@
tippyOptions={{ maxWidth: '20rem' }}
>
<button
class="px-2.5 py-1.5 rounded-xl w-full text-left {skillIdx === selectedIdx
? 'bg-gray-50 dark:bg-gray-800 selected-command-option-button'
class="flex h-[1.6875rem] w-full items-center rounded-xl px-2 text-left text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 {skillIdx ===
selectedIdx
? 'bg-gray-50/40 dark:bg-gray-800/40 selected-command-option-button'
: ''}"
type="button"
on:click={() => {
@@ -95,13 +96,13 @@
data-selected={skillIdx === selectedIdx}
>
<div class="flex w-full min-w-0 items-center text-black dark:text-gray-100">
<div class="flex items-center justify-center size-5 mr-2 shrink-0">
<Cube className="size-4" />
<div class="mr-2 flex size-4.5 shrink-0 items-center justify-center">
<Cube className="size-3.5" />
</div>
<div class="truncate min-w-0 flex-1">
{skill.name}
</div>
<div class="ml-2 max-w-24 shrink-0 truncate text-xs text-gray-500">
<div class="ml-2 max-w-24 shrink-0 truncate text-xs text-gray-500 dark:text-gray-400">
{skill.id}
</div>
</div>