Skip to content

Commit b00c7f0

Browse files
Merge pull request #3 from allozaur/allozaur/models-search
Several structural & UX improvements for Models Selector component
2 parents eda1c18 + 56f758b commit b00c7f0

File tree

15 files changed

+417
-338
lines changed

15 files changed

+417
-338
lines changed

tools/server/public/index.html.gz

2.76 KB
Binary file not shown.

tools/server/webui/package-lock.json

Lines changed: 22 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/server/webui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"@tailwindcss/vite": "^4.0.0",
4444
"@types/node": "^22",
4545
"@vitest/browser": "^3.2.3",
46-
"bits-ui": "^2.8.11",
46+
"bits-ui": "^2.14.4",
4747
"clsx": "^2.1.1",
4848
"dexie": "^4.0.11",
4949
"eslint": "^9.18.0",

tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@
331331
class="{INPUT_CLASSES} border-radius-bottom-none mx-auto max-w-[48rem] overflow-hidden rounded-3xl backdrop-blur-md {disabled
332332
? 'cursor-not-allowed opacity-60'
333333
: ''} {className}"
334+
data-slot="chat-form"
334335
>
335336
<ChatAttachmentsList
336337
bind:uploadedFiles
Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script lang="ts">
2-
import { Input } from '$lib/components/ui/input';
3-
import { Search } from '@lucide/svelte';
2+
import { SearchInput } from '$lib/components/app';
43
54
interface Props {
65
value?: string;
@@ -15,19 +14,6 @@
1514
onInput,
1615
class: className
1716
}: Props = $props();
18-
19-
function handleInput(event: Event) {
20-
const target = event.target as HTMLInputElement;
21-
22-
value = target.value;
23-
onInput?.(target.value);
24-
}
2517
</script>
2618

27-
<div class="relative mb-4 {className}">
28-
<Search
29-
class="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-muted-foreground"
30-
/>
31-
32-
<Input bind:value class="pl-10" oninput={handleInput} {placeholder} type="search" />
33-
</div>
19+
<SearchInput bind:value {placeholder} {onInput} class="mb-4 {className}" />

tools/server/webui/src/lib/components/app/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export { default as CopyToClipboardIcon } from './misc/CopyToClipboardIcon.svelt
6262
export { default as KeyboardShortcutInfo } from './misc/KeyboardShortcutInfo.svelte';
6363
export { default as MarkdownContent } from './misc/MarkdownContent.svelte';
6464
export { default as RemoveButton } from './misc/RemoveButton.svelte';
65+
export { default as SearchInput } from './misc/SearchInput.svelte';
6566
export { default as SyntaxHighlightedCode } from './misc/SyntaxHighlightedCode.svelte';
6667
export { default as ModelsSelector } from './models/ModelsSelector.svelte';
6768

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script lang="ts">
2+
import { Input } from '$lib/components/ui/input';
3+
import { Search, X } from '@lucide/svelte';
4+
5+
interface Props {
6+
value?: string;
7+
placeholder?: string;
8+
onInput?: (value: string) => void;
9+
onClose?: () => void;
10+
onKeyDown?: (event: KeyboardEvent) => void;
11+
class?: string;
12+
id?: string;
13+
ref?: HTMLInputElement | null;
14+
}
15+
16+
let {
17+
value = $bindable(''),
18+
placeholder = 'Search...',
19+
onInput,
20+
onClose,
21+
onKeyDown,
22+
class: className,
23+
id,
24+
ref = $bindable(null)
25+
}: Props = $props();
26+
27+
let showClearButton = $derived(!!value || !!onClose);
28+
29+
function handleInput(event: Event) {
30+
const target = event.target as HTMLInputElement;
31+
32+
value = target.value;
33+
onInput?.(target.value);
34+
}
35+
36+
function handleClear() {
37+
if (value) {
38+
value = '';
39+
onInput?.('');
40+
ref?.focus();
41+
} else {
42+
onClose?.();
43+
}
44+
}
45+
</script>
46+
47+
<div class="relative {className}">
48+
<Search
49+
class="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-muted-foreground"
50+
/>
51+
52+
<Input
53+
{id}
54+
bind:value
55+
bind:ref
56+
class="pl-9 {showClearButton ? 'pr-9' : ''}"
57+
oninput={handleInput}
58+
onkeydown={onKeyDown}
59+
{placeholder}
60+
type="search"
61+
/>
62+
63+
{#if showClearButton}
64+
<button
65+
type="button"
66+
class="absolute top-1/2 right-3 -translate-y-1/2 transform text-muted-foreground transition-colors hover:text-foreground"
67+
onclick={handleClear}
68+
aria-label={value ? 'Clear search' : 'Close'}
69+
>
70+
<X class="h-4 w-4" />
71+
</button>
72+
{/if}
73+
</div>

0 commit comments

Comments
 (0)