feat: web UI chat render, panels, presence + analytics

This commit is contained in:
hh
2026-05-31 19:41:37 +02:00
parent 75425d1bee
commit ed469ba8dd
83 changed files with 6034 additions and 136 deletions
@@ -0,0 +1,79 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { page } from "$app/state";
import ChatListItem from "$lib/components/ChatListItem.svelte";
import SearchMessageItem from "$lib/components/search/SearchMessageItem.svelte";
import EmptyState from "$lib/components/ui/EmptyState.svelte";
import Spinner from "$lib/components/ui/Spinner.svelte";
import { search } from "$lib/stores/search.svelte";
import { ui } from "$lib/stores/ui.svelte";
const activeChatId = $derived(
page.params.chatId ? Number(page.params.chatId) : null
);
const hasChats = $derived(search.chatHits.length > 0);
const hasMessages = $derived(search.messageHits.length > 0);
const empty = $derived(!(search.loading || hasChats || hasMessages));
function openChat(chatId: number) {
search.close();
goto(`/app/${chatId}`);
}
function openHit(chatId: number, messageId: number) {
ui.requestJump(chatId, messageId);
search.close();
goto(`/app/${chatId}`);
}
</script>
<div class="search-results custom-scroll">
{#if hasChats}
<div class="section-label">Чаты</div>
{#each search.chatHits as chat (chat.chat_id)}
<ChatListItem
{chat}
selected={chat.chat_id === activeChatId}
onclick={() => openChat(chat.chat_id)}
/>
{/each}
{/if}
{#if search.loading && !hasMessages}
<div class="loading"><Spinner /></div>
{:else if hasMessages}
<div class="section-label">Сообщения</div>
{#each search.messageHits as hit (`${hit.chat_id}:${hit.message_id}`)}
<SearchMessageItem
{hit}
onclick={() => openHit(hit.chat_id, hit.message_id)}
/>
{/each}
{/if}
{#if empty}
<EmptyState title="Ничего не найдено" />
{/if}
</div>
<style lang="scss">
.search-results {
overflow-y: auto;
flex: 1;
padding: 0.25rem 0.4375rem;
}
.section-label {
padding: 0.625rem 0.75rem 0.375rem;
font-size: 0.875rem;
font-weight: var(--font-weight-medium);
color: var(--color-primary);
}
.loading {
display: flex;
justify-content: center;
padding: 2rem 0;
}
</style>