feat: add favorites state and buttons

This commit is contained in:
TerryM
2026-06-02 00:36:11 +08:00
parent 43700d9fdc
commit 337e8f7e67
16 changed files with 491 additions and 93 deletions

View File

@@ -24,6 +24,7 @@ import type { Post } from "../types/post";
import { downloadAttachment } from "./messageStream/utils/downloadFile";
import { mediaSaveKindFromType, useSaveToAlbumGuide } from "./SaveToAlbumGuide";
import { useToast } from "./Toast";
import { FavoriteButton } from "../favorites/FavoriteButton";
const MEDALS = ["🥇", "🥈", "🥉"];
const MAX_ITEMS = 5;
@@ -174,6 +175,7 @@ function PopularRankRow({
</div>
<div className="relative z-10 flex shrink-0 items-center gap-1">
<FavoriteButton resourceId={r.id} />
{r.isDownloadable ? (
<button
type="button"

View File

@@ -15,6 +15,7 @@ import {
} from "./messageStream/utils/downloadFile";
import { mediaSaveKindFromType, useSaveToAlbumGuide } from "./SaveToAlbumGuide";
import { useToast } from "./Toast";
import { FavoriteButton } from "../favorites/FavoriteButton";
function isPlaceholderAsset(path: string | undefined | null) {
return !path || path.includes("placeholder-cover");
@@ -133,6 +134,11 @@ export function RecommendedCard({
{r.badgeLabel}
</span>
) : null}
<FavoriteButton
resourceId={r.id}
size="sm"
className="absolute right-3 top-3 z-20 shadow-lg shadow-black/30"
/>
</div>
<div
className={

View File

@@ -8,6 +8,7 @@ import { AlbumBubble } from "./bubbles/AlbumBubble";
import { VideoBubble } from "./bubbles/VideoBubble";
import { LinkPreviewCard } from "./LinkPreviewCard";
import { formatDateTime } from "./utils/formatTime";
import { FavoriteButton } from "../../favorites/FavoriteButton";
type BubbleComponent = ComponentType<{ post: Post }>;
@@ -53,6 +54,11 @@ export function MessageBubble({
isVisual ? "p-0" : "px-4 py-3"
}`}
>
<FavoriteButton
resourceId={post.id}
size="sm"
className="absolute right-3 top-3 z-20 shadow-lg shadow-black/30"
/>
<Bubble post={post} />
{post.linkPreview ? (
<div className={isVisual ? "px-4 pt-3" : "mt-3"}>

View File

@@ -9,6 +9,7 @@ import { FilterChips } from "./FilterChips";
import { MessageBubble } from "./MessageBubble";
import { useGroupedByDay } from "./hooks/useGroupedByDay";
import { usePostStream } from "./hooks/usePostStream";
import { useFavorites } from "../../favorites/FavoritesProvider";
export type MessageStreamProps = {
scope: PostScope;
@@ -30,9 +31,14 @@ export function MessageStream({ scope }: MessageStreamProps) {
const { items, isLoading, error, hasMore, loadMore, reset } =
usePostStream(params);
const { ensureFavoriteIds } = useFavorites();
const groups = useGroupedByDay(items, lang);
const retryLabel = lang === "zh-CN" ? "重试" : "Retry";
useEffect(() => {
void ensureFavoriteIds(items.map((item) => item.id)).catch(() => undefined);
}, [ensureFavoriteIds, items]);
const sentinelRef = useRef<HTMLDivElement>(null);
const filterBarRef = useRef<HTMLDivElement>(null);
const hasMoreRef = useRef(hasMore);