feat(frontend): feed of deleted and edited messages above the chat list and per chat in the changes panel
This commit is contained in:
1 parent
010fa29ce0
commit
9f16e2aa56
23 files changed
+1915
-71
No files matched your search
@@ -0,0 +1,151 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { ripple } from "#lib/actions/ripple.js";
|
||||
import { listFeedMessages } from "#lib/api/endpoints.js";
|
||||
import type { FeedItem, MessageView } from "#lib/api/types.js";
|
||||
import FeedText from "#lib/components/feed/FeedText.svelte";
|
||||
import Spinner from "#lib/components/ui/Spinner.svelte";
|
||||
import { formatDayTime, formatFull } from "#lib/format/datetime.js";
|
||||
import { t } from "#lib/i18n/locale.svelte.js";
|
||||
|
||||
interface Props {
|
||||
item: FeedItem;
|
||||
onopen: (messageId: number) => void;
|
||||
senderOf: (message: MessageView) => string;
|
||||
}
|
||||
|
||||
let { item, onopen, senderOf }: Props = $props();
|
||||
|
||||
const PAGE = 50;
|
||||
|
||||
let messages = $state<MessageView[]>([]);
|
||||
let cursor = $state<string | null>(null);
|
||||
let loading = $state(false);
|
||||
let failed = $state(false);
|
||||
|
||||
async function load(next: string | null) {
|
||||
loading = true;
|
||||
failed = false;
|
||||
try {
|
||||
const page = await listFeedMessages(item.id, {
|
||||
cursor: next ?? undefined,
|
||||
limit: PAGE,
|
||||
});
|
||||
messages = [...messages, ...page.messages];
|
||||
cursor = page.next_cursor;
|
||||
} catch {
|
||||
failed = true;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
load(null);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="bulk">
|
||||
{#each messages as message (message.message_id)}
|
||||
<button
|
||||
class="member"
|
||||
onclick={() => onopen(message.message_id)}
|
||||
type="button"
|
||||
use:ripple
|
||||
>
|
||||
<FeedText deleted {message} prefix={senderOf(message)} />
|
||||
<time
|
||||
class="date"
|
||||
datetime={message.date}
|
||||
title={formatFull(message.date)}
|
||||
>
|
||||
{formatDayTime(message.date)}
|
||||
</time>
|
||||
</button>
|
||||
{/each}
|
||||
{#if loading}
|
||||
<div class="state"><Spinner /></div>
|
||||
{:else if failed}
|
||||
<button class="more" onclick={() => load(cursor)} type="button">
|
||||
{t("feed.retry")}
|
||||
</button>
|
||||
{:else if cursor !== null}
|
||||
<button class="more" onclick={() => load(cursor)} type="button">
|
||||
{t("feed.more")}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.bulk {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
|
||||
margin: 0 0 0.375rem 4.125rem;
|
||||
padding-inline-start: 0.625rem;
|
||||
border-inline-start: 2px solid var(--color-borders);
|
||||
}
|
||||
|
||||
.member {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: baseline;
|
||||
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.5rem;
|
||||
border: 0;
|
||||
border-radius: var(--border-radius-default-small);
|
||||
|
||||
font: inherit;
|
||||
text-align: start;
|
||||
color: var(--color-text);
|
||||
|
||||
background: none;
|
||||
|
||||
--ripple-color: var(--color-interactive-element-hover);
|
||||
|
||||
:global(.feed-text) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
&:hover {
|
||||
background-color: var(--color-chat-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.75rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.more {
|
||||
cursor: pointer;
|
||||
|
||||
margin-top: 0.25rem;
|
||||
padding: 0.5rem;
|
||||
border: 0;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
font: inherit;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-primary);
|
||||
|
||||
background-color: var(--color-background-secondary);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user