feat(frontend): profiles chip in the feed shows name, username, photo and title changes

This commit is contained in:
hh committed 2026-10-19 03:25:48 +00:00
1 parent 8e0f828dd4
commit 98dda99c5c
9 files changed
+181 -14

No files matched your search

@@ -2,6 +2,7 @@
import { ripple } from "#lib/actions/ripple.js";
import type { FeedItem, MessageView } from "#lib/api/types.js";
import FeedBulk from "#lib/components/feed/FeedBulk.svelte";
import FeedPhoto from "#lib/components/feed/FeedPhoto.svelte";
import FeedText from "#lib/components/feed/FeedText.svelte";
import Avatar from "#lib/components/ui/Avatar.svelte";
import Icon from "#lib/components/ui/Icon.svelte";
@@ -20,6 +21,14 @@
let { item, onopen, inChat = false }: Props = $props();
const FIELD_KEYS = {
name: "feed.field.name",
photo: "feed.field.photo",
title: "feed.field.title",
username: "feed.field.username",
} as const;
const FIELD_ORDER = ["name", "title", "username", "photo"] as const;
let expanded = $state(false);
const ownId = $derived(accounts.selected?.tg_user_id ?? null);
@@ -67,8 +76,14 @@
? t("chat.deletedAccount")
: t("chat.fallbackTitle", { id: item.chat.chat_id }))
);
const profile = $derived(item.kind === "profile");
const fields = $derived(
FIELD_ORDER.filter((field) => item.detail?.[field]).map(
(field) => [field, item.detail?.[field] ?? [null, null]] as const
)
);
const title = $derived.by(() => {
if (!inChat) {
if (!inChat || profile) {
return chatTitle;
}
if (bulk) {
@@ -77,7 +92,7 @@
return senderName(item.sender_id, item.sender_name);
});
const avatar = $derived.by(() => {
if (!inChat) {
if (!inChat || profile) {
return {
has: item.chat.has_avatar,
id: item.chat.chat_id,
@@ -92,7 +107,7 @@
};
});
const prefix = $derived.by(() => {
if (inChat) {
if (inChat || profile) {
return "";
}
if (item.outgoing) {
@@ -107,6 +122,13 @@
: null
);
function shown(field: string, value: string | null): string {
if (!value) {
return t("feed.noText");
}
return field === "username" ? `@${value}` : value;
}
function open() {
if (bulk) {
expanded = !expanded;
@@ -142,7 +164,27 @@
{formatListDate(item.at)}
</time>
</span>
{#if bulk}
{#if profile}
{#each fields as [field, pair] (field)}
<span class="change now">
<span class="tag">{t(FIELD_KEYS[field])}</span>
{#if field === "photo"}
<FeedPhoto ownerId={item.chat.chat_id} uniqueId={pair[0]} />
<span class="arrow">→</span>
<FeedPhoto ownerId={item.chat.chat_id} uniqueId={pair[1]} />
{:else}
<span class="was">{shown(field, pair[0])}</span>
<span class="arrow">→</span>
{shown(field, pair[1])}
{/if}
</span>
{/each}
{#if item.message_count > fields.length}
<span class="count">
{t("feed.profileCount", { count: item.message_count })}
</span>
{/if}
{:else if bulk}
<span class="mark">
<Icon name="delete" size="0.875rem" />
{inChat
@@ -360,4 +402,18 @@
.missing {
font-style: italic;
}
.was {
color: var(--color-text-secondary);
}
.arrow {
margin-inline: 0.25rem;
color: var(--color-text-secondary);
}
.count {
font-size: 0.8125rem;
color: var(--color-text-secondary);
}
</style>