feat: web UI chat render, panels, presence + analytics
This commit is contained in:
1 parent
75425d1bee
commit
ed469ba8dd
83 files changed
+6034
-136
No files matched your search
@@ -0,0 +1,101 @@
|
||||
import { searchMessages } from "$lib/api/endpoints";
|
||||
import type { SearchHit } from "$lib/api/types";
|
||||
import { chats } from "$lib/stores/chats.svelte";
|
||||
|
||||
const DEBOUNCE_MS = 250;
|
||||
const MIN_LENGTH = 1;
|
||||
|
||||
function createSearch() {
|
||||
let active = $state(false);
|
||||
let query = $state("");
|
||||
let messageHits = $state<SearchHit[]>([]);
|
||||
let loading = $state(false);
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
let seq = 0;
|
||||
|
||||
const trimmed = $derived(query.trim());
|
||||
const chatHits = $derived.by(() => {
|
||||
const needle = trimmed.toLowerCase();
|
||||
if (needle.length < MIN_LENGTH) {
|
||||
return [];
|
||||
}
|
||||
return chats.list.filter((chat) =>
|
||||
(chat.title ?? "").toLowerCase().includes(needle)
|
||||
);
|
||||
});
|
||||
|
||||
async function run(value: string) {
|
||||
const current = ++seq;
|
||||
try {
|
||||
const hits = await searchMessages(value);
|
||||
if (current === seq) {
|
||||
messageHits = hits;
|
||||
}
|
||||
} catch {
|
||||
if (current === seq) {
|
||||
messageHits = [];
|
||||
}
|
||||
} finally {
|
||||
if (current === seq) {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function schedule() {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
const value = trimmed;
|
||||
if (value.length < MIN_LENGTH) {
|
||||
seq++;
|
||||
messageHits = [];
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
loading = true;
|
||||
timer = setTimeout(() => {
|
||||
run(value).catch(() => undefined);
|
||||
}, DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
return {
|
||||
get active() {
|
||||
return active;
|
||||
},
|
||||
get query() {
|
||||
return query;
|
||||
},
|
||||
get trimmed() {
|
||||
return trimmed;
|
||||
},
|
||||
get loading() {
|
||||
return loading;
|
||||
},
|
||||
get messageHits() {
|
||||
return messageHits;
|
||||
},
|
||||
get chatHits() {
|
||||
return chatHits;
|
||||
},
|
||||
open() {
|
||||
active = true;
|
||||
},
|
||||
setQuery(value: string) {
|
||||
query = value;
|
||||
schedule();
|
||||
},
|
||||
close() {
|
||||
active = false;
|
||||
query = "";
|
||||
messageHits = [];
|
||||
loading = false;
|
||||
seq++;
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const search = createSearch();
|
||||
Reference in new issue
Block a user