feat: 1-to-1 message render + web data-lake backend

This commit is contained in:
hh
2026-05-31 01:45:05 +02:00
parent f0afb7ec5b
commit 75425d1bee
110 changed files with 10199 additions and 54 deletions
@@ -0,0 +1,104 @@
<script lang="ts">
import { getPeer } from "$lib/api/endpoints";
import type { PeerView } from "$lib/api/types";
import Avatar from "$lib/components/ui/Avatar.svelte";
import { peerName } from "$lib/format/peer";
import { accounts } from "$lib/stores/accounts.svelte";
import { chats } from "$lib/stores/chats.svelte";
interface Props {
chatId: number;
}
let { chatId }: Props = $props();
const isDm = $derived(chatId > 0);
const chat = $derived(chats.byId(chatId));
let peer = $state<PeerView | null>(null);
$effect(() => {
if (accounts.selectedId === null || !isDm) {
peer = null;
return;
}
let active = true;
peer = null;
getPeer(chatId)
.then((result) => {
if (active) {
peer = result;
}
})
.catch(() => {
if (active) {
peer = null;
}
});
return () => {
active = false;
};
});
const fallbackTitle = $derived(chat?.title ?? `Chat ${chatId}`);
const title = $derived(isDm && peer ? peerName(peer) : fallbackTitle);
const subtitle = $derived.by(() => {
if (isDm) {
if (peer?.username) {
return `@${peer.username}`;
}
return peer?.phone ?? `ID ${chatId}`;
}
const count = chat?.message_count ?? 0;
return count > 0 ? `${count} messages` : "group";
});
const avatarKind = $derived(isDm ? "peer" : "chat");
const hasAvatar = $derived(chat?.has_avatar ?? Boolean(peer?.has_avatar));
</script>
<header class="chat-header">
<Avatar
name={title}
colorKey={chatId}
size={2.5}
avatar={{ kind: avatarKind, id: chatId }}
{hasAvatar}
deleted={peer?.is_deleted_account ?? false}
/>
<div class="info">
<h2 class="title">{title}</h2>
<span class="subtitle">{subtitle}</span>
</div>
</header>
<style lang="scss">
.chat-header {
display: flex;
align-items: center;
gap: 0.625rem;
height: var(--header-height);
padding: 0 1rem;
border-bottom: 1px solid var(--color-borders);
background-color: var(--color-background);
}
.info {
overflow: hidden;
min-width: 0;
}
.title {
overflow: hidden;
margin: 0;
font-size: 1rem;
font-weight: var(--font-weight-medium);
text-overflow: ellipsis;
white-space: nowrap;
}
.subtitle {
font-size: 0.8125rem;
color: var(--color-text-secondary);
}
</style>