feat(backend,frontend): feed gets a bots tab so private is people only, a folder's context menu opens the feed of its chats

This commit is contained in:
hh committed 2026-10-26 01:50:44 +00:00
1 parent b9e8a96774
commit c2180e80ad
11 files changed
+128 -16

No files matched your search

@@ -2,8 +2,10 @@
import ContextMenu from "#lib/components/ui/ContextMenu.svelte";
import ContextMenuItem from "#lib/components/ui/ContextMenuItem.svelte";
import { t } from "#lib/i18n/locale.svelte.js";
import { feed } from "#lib/stores/feed.svelte.js";
import { folders } from "#lib/stores/folders.svelte.js";
import { policyUi } from "#lib/stores/policy.svelte.js";
import { page } from "$app/state";
interface Tab {
id: number | null;
@@ -93,6 +95,12 @@
</button>
{/snippet}
{#snippet menu()}
<ContextMenuItem
icon="recent"
onselect={() => feed.open(page.url, tab.id)}
>
{t("feed.folder")}
</ContextMenuItem>
<ContextMenuItem icon="settings" onselect={() => editPolicy(tab)}>
{t("settings.policy")}
</ContextMenuItem>
@@ -1,16 +1,32 @@
<script lang="ts">
import type { FeedChatKind, FeedKind } from "#lib/api/types.js";
import Icon from "#lib/components/ui/Icon.svelte";
import { t } from "#lib/i18n/locale.svelte.js";
import { FEED_CHAT_KINDS, FEED_KINDS } from "#lib/stores/feed.svelte.js";
import { folders } from "#lib/stores/folders.svelte.js";
interface Props {
chats?: FeedChatKind | null;
folder?: number | null;
kind: FeedKind;
onchats?: (chats: FeedChatKind | null) => void;
onfolder?: (folder: number | null) => void;
onkind: (kind: FeedKind) => void;
}
let { kind, chats = null, onkind, onchats }: Props = $props();
let {
kind,
chats = null,
folder = null,
onkind,
onchats,
onfolder,
}: Props = $props();
const folderTitle = $derived(
folders.list.find((item) => item.folder_id === folder)?.title ??
t("feed.folder")
);
const KIND_KEYS = {
all: "feed.filter.all",
@@ -20,6 +36,7 @@
} as const;
const CHAT_KEYS = {
bot: "feed.chats.bot",
channel: "feed.chats.channel",
dm: "feed.chats.dm",
group: "feed.chats.group",
@@ -55,6 +72,20 @@
{/each}
</div>
{/if}
{#if folder !== null && onfolder}
<div class="group">
<button
aria-pressed="true"
class="chip on"
onclick={() => onfolder(null)}
type="button"
>
<Icon name="folder" size="0.875rem" />
{folderTitle}
<Icon name="close" size="0.875rem" />
</button>
</div>
{/if}
</div>
<style lang="scss">
@@ -78,6 +109,7 @@
cursor: pointer;
display: inline-flex;
gap: 0.25rem;
align-items: center;
height: 1.75rem;
@@ -14,11 +14,12 @@
interface Props {
chatId?: number;
chats?: FeedChatKind | null;
folderId?: number | null;
kind: FeedKind;
onopen: (item: FeedItem, messageId: number) => void;
}
let { kind, chats = null, chatId, onopen }: Props = $props();
let { kind, chats = null, folderId = null, chatId, onopen }: Props = $props();
const PAGE = 30;
const EMPTY_KEYS = {
@@ -38,6 +39,7 @@
const filter = $derived<FeedQuery>({
chat_id: chatId,
chat_kind: chats ?? undefined,
folder_id: folderId ?? undefined,
kind,
limit: PAGE,
});
@@ -55,12 +55,19 @@
</header>
<FeedFilters
chats={filter.chats}
folder={filter.folder}
kind={filter.kind}
onchats={(chats) => feed.filter(page.url, { ...filter, chats })}
onfolder={(folder) => feed.filter(page.url, { ...filter, folder })}
onkind={(kind) => feed.filter(page.url, { ...filter, kind })}
/>
<div class="feed-body custom-scroll">
<FeedList chats={filter.chats} kind={filter.kind} onopen={open} />
<FeedList
chats={filter.chats}
folderId={filter.folder}
kind={filter.kind}
onopen={open}
/>
</div>
</div>