Skip to content

Commit 668f9fe

Browse files
committed
refac
1 parent 975c9f9 commit 668f9fe

6 files changed

Lines changed: 534 additions & 332 deletions

File tree

src/lib/components/chat/MessageInput/InputMenu.svelte

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,12 @@
122122
</Tooltip>
123123

124124
<div slot="content">
125-
<DropdownMenu
126-
className="w-70 max-h-72 overflow-y-auto overflow-x-hidden scrollbar-thin transition"
127-
>
125+
<DropdownMenu className="w-70 max-h-72 overflow-hidden transition">
128126
{#if tab === ''}
129-
<div in:fly={{ x: -20, duration: 150 }}>
127+
<div
128+
class="max-h-72 overflow-y-auto overflow-x-hidden scrollbar-thin"
129+
in:fly={{ x: -20, duration: 150 }}
130+
>
130131
<Tooltip
131132
content={fileUploadCapableModels.length !== selectedModels.length
132133
? $i18n.t('Model(s) do not support file upload')
@@ -486,9 +487,9 @@
486487
{/if}
487488
</div>
488489
{:else if tab === 'knowledge'}
489-
<div in:fly={{ x: 20, duration: 150 }}>
490+
<div class="flex max-h-72 flex-col overflow-hidden" in:fly={{ x: 20, duration: 150 }}>
490491
<button
491-
class="flex w-full justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
492+
class="flex w-full shrink-0 justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
492493
on:click={() => {
493494
tab = '';
494495
}}
@@ -505,9 +506,9 @@
505506
<Knowledge {onSelect} />
506507
</div>
507508
{:else if tab === 'notes'}
508-
<div in:fly={{ x: 20, duration: 150 }}>
509+
<div class="flex max-h-72 flex-col overflow-hidden" in:fly={{ x: 20, duration: 150 }}>
509510
<button
510-
class="flex w-full justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
511+
class="flex w-full shrink-0 justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
511512
on:click={() => {
512513
tab = '';
513514
}}
@@ -524,9 +525,9 @@
524525
<Notes {onSelect} />
525526
</div>
526527
{:else if tab === 'files'}
527-
<div in:fly={{ x: 20, duration: 150 }}>
528+
<div class="flex max-h-72 flex-col overflow-hidden" in:fly={{ x: 20, duration: 150 }}>
528529
<button
529-
class="flex w-full justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
530+
class="flex w-full shrink-0 justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
530531
on:click={() => {
531532
tab = '';
532533
}}
@@ -543,9 +544,9 @@
543544
<Files {onSelect} />
544545
</div>
545546
{:else if tab === 'chats'}
546-
<div in:fly={{ x: 20, duration: 150 }}>
547+
<div class="flex max-h-72 flex-col overflow-hidden" in:fly={{ x: 20, duration: 150 }}>
547548
<button
548-
class="flex w-full justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
549+
class="flex w-full shrink-0 justify-between gap-2 items-center h-[1.6875rem] px-2 text-[13px] font-normal select-none cursor-pointer rounded-xl hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
549550
on:click={() => {
550551
tab = '';
551552
}}

src/lib/components/chat/MessageInput/InputMenu/Chats.svelte

Lines changed: 104 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<script lang="ts">
22
import dayjs from 'dayjs';
3-
import { onMount, tick, getContext } from 'svelte';
3+
import { onDestroy, onMount, tick, getContext } from 'svelte';
44
55
import { decodeString } from '$lib/utils';
6-
import { getChatList } from '$lib/apis/chats';
6+
import { getChatList, getChatListBySearchText } from '$lib/apis/chats';
77
88
import Tooltip from '$lib/components/common/Tooltip.svelte';
99
import Spinner from '$lib/components/common/Spinner.svelte';
1010
import Loader from '$lib/components/common/Loader.svelte';
1111
import { chatId } from '$lib/stores';
12+
import SearchInput from './SearchInput.svelte';
1213
1314
const i18n = getContext('i18n');
1415
@@ -18,22 +19,52 @@
1819
1920
let items = [];
2021
let selectedIdx = 0;
22+
let query = '';
2123
2224
let page = 1;
2325
let itemsLoading = false;
2426
let allItemsLoaded = false;
27+
let initialized = false;
28+
let searchDebounceTimer: ReturnType<typeof setTimeout>;
29+
let requestId = 0;
30+
31+
$: if (initialized) {
32+
query;
33+
scheduleSearch();
34+
}
35+
36+
const scheduleSearch = () => {
37+
clearTimeout(searchDebounceTimer);
38+
searchDebounceTimer = setTimeout(init, 200);
39+
};
40+
41+
const init = async () => {
42+
requestId += 1;
43+
page = 1;
44+
items = [];
45+
selectedIdx = 0;
46+
allItemsLoaded = false;
47+
itemsLoading = false;
48+
await tick();
49+
await getItemsPage(requestId);
50+
};
2551
2652
const loadMoreItems = async () => {
2753
if (allItemsLoaded) return;
2854
page += 1;
29-
await getItemsPage();
55+
await getItemsPage(requestId);
3056
};
3157
32-
const getItemsPage = async () => {
58+
const getItemsPage = async (activeRequestId = requestId) => {
3359
itemsLoading = true;
34-
let res = await getChatList(localStorage.token, page, true, true).catch(() => {
35-
return [];
36-
});
60+
const res = query.trim()
61+
? await getChatListBySearchText(localStorage.token, query.trim(), page).catch(() => {
62+
return [];
63+
})
64+
: await getChatList(localStorage.token, page, true, true).catch(() => {
65+
return [];
66+
});
67+
if (activeRequestId !== requestId) return res;
3768
3869
if ((res ?? []).length === 0) {
3970
allItemsLoaded = true;
@@ -50,7 +81,7 @@
5081
...item,
5182
type: 'chat',
5283
name: item.title,
53-
description: dayjs(item.updated_at * 1000).fromNow()
84+
description: item.snippet || dayjs(item.updated_at * 1000).fromNow()
5485
};
5586
})
5687
];
@@ -64,60 +95,78 @@
6495
await tick();
6596
6697
loaded = true;
98+
initialized = true;
99+
});
100+
101+
onDestroy(() => {
102+
clearTimeout(searchDebounceTimer);
67103
});
68104
</script>
69105

70106
{#if loaded}
71-
{#if items.length === 0}
72-
<div class="text-center text-xs text-gray-500 py-3">{$i18n.t('No chats found')}</div>
73-
{:else}
74-
<div class="flex flex-col gap-0.5">
75-
{#each items as item, idx}
76-
<button
77-
class=" h-[1.6875rem] px-2 rounded-xl w-full text-left flex justify-between items-center text-[13px] font-normal {idx ===
78-
selectedIdx
79-
? ' bg-gray-50/40 dark:bg-gray-800/40 dark:text-gray-100 selected-command-option-button'
80-
: ''}"
81-
type="button"
82-
on:click={() => {
83-
onSelect(item);
84-
}}
85-
on:mousemove={() => {
86-
selectedIdx = idx;
87-
}}
88-
on:mouseleave={() => {
89-
if (idx === 0) {
90-
selectedIdx = -1;
91-
}
92-
}}
93-
data-selected={idx === selectedIdx}
94-
>
95-
<div class="text-black dark:text-gray-100 flex items-center gap-1.5">
96-
<Tooltip content={item.description || decodeString(item?.name)} placement="top-start">
97-
<div class="line-clamp-1 flex-1">
98-
{decodeString(item?.name)}
107+
<div class="flex min-h-0 flex-1 flex-col gap-0.5 overflow-hidden">
108+
<SearchInput bind:value={query} placeholder={$i18n.t('Search Chats')} />
109+
110+
<div class="min-h-0 flex-1 overflow-y-auto overflow-x-hidden scrollbar-thin">
111+
{#if items.length === 0 && itemsLoading}
112+
<div class="py-4.5">
113+
<Spinner />
114+
</div>
115+
{:else if items.length === 0}
116+
<div class="text-center text-xs text-gray-500 py-3">{$i18n.t('No chats found')}</div>
117+
{:else}
118+
<div class="flex flex-col gap-0.5">
119+
{#each items as item, idx}
120+
<button
121+
class=" h-[1.6875rem] px-2 rounded-xl w-full text-left flex justify-between items-center text-[13px] font-normal {idx ===
122+
selectedIdx
123+
? ' bg-gray-50/40 dark:bg-gray-800/40 dark:text-gray-100 selected-command-option-button'
124+
: ''}"
125+
type="button"
126+
on:click={() => {
127+
onSelect(item);
128+
}}
129+
on:mousemove={() => {
130+
selectedIdx = idx;
131+
}}
132+
on:mouseleave={() => {
133+
if (idx === 0) {
134+
selectedIdx = -1;
135+
}
136+
}}
137+
data-selected={idx === selectedIdx}
138+
>
139+
<div class="text-black dark:text-gray-100 flex items-center gap-1.5">
140+
<Tooltip
141+
content={item.description || decodeString(item?.name)}
142+
placement="top-start"
143+
>
144+
<div class="line-clamp-1 flex-1">
145+
{decodeString(item?.name)}
146+
</div>
147+
</Tooltip>
99148
</div>
100-
</Tooltip>
101-
</div>
102-
</button>
103-
{/each}
104-
105-
{#if !allItemsLoaded}
106-
<Loader
107-
on:visible={(e) => {
108-
if (!itemsLoading) {
109-
loadMoreItems();
110-
}
111-
}}
112-
>
113-
<div class="w-full flex justify-center py-4 text-xs animate-pulse items-center gap-2">
114-
<Spinner className=" size-4" />
115-
<div class=" ">{$i18n.t('Loading...')}</div>
116-
</div>
117-
</Loader>
149+
</button>
150+
{/each}
151+
152+
{#if !allItemsLoaded}
153+
<Loader
154+
on:visible={(e) => {
155+
if (!itemsLoading) {
156+
loadMoreItems();
157+
}
158+
}}
159+
>
160+
<div class="w-full flex justify-center py-4 text-xs animate-pulse items-center gap-2">
161+
<Spinner className=" size-4" />
162+
<div class=" ">{$i18n.t('Loading...')}</div>
163+
</div>
164+
</Loader>
165+
{/if}
166+
</div>
118167
{/if}
119168
</div>
120-
{/if}
169+
</div>
121170
{:else}
122171
<div class="py-4.5">
123172
<Spinner />

0 commit comments

Comments
 (0)