Files
Arkie-Library-Frontend/src/components/messageStream/MessageBubble.tsx

80 lines
2.6 KiB
TypeScript
Raw Normal View History

import type { ComponentType } from "react";
import type { Post } from "../../types/post";
import { TextBubble } from "./bubbles/TextBubble";
import { FileDocBubble } from "./bubbles/FileDocBubble";
import { ImageBubble } from "./bubbles/ImageBubble";
import { ImageWithTextBubble } from "./bubbles/ImageWithTextBubble";
import { AlbumBubble } from "./bubbles/AlbumBubble";
import { VideoBubble } from "./bubbles/VideoBubble";
import { LinkPreviewCard } from "./LinkPreviewCard";
import { formatDateTime } from "./utils/formatTime";
2026-06-02 00:36:11 +08:00
import { FavoriteButton } from "../../favorites/FavoriteButton";
type BubbleComponent = ComponentType<{ post: Post }>;
export function pickBubble(post: Post): BubbleComponent {
const a = post.attachments;
if (a.length === 0) return TextBubble;
if (a.length >= 2 && a.every((x) => x.kind === "image")) return AlbumBubble;
const only = a[0];
if (only.kind === "video") return VideoBubble;
if (only.kind === "image") {
return post.text ? ImageWithTextBubble : ImageBubble;
}
return FileDocBubble;
}
export function MessageBubble({
post,
fluid = false,
}: {
post: Post;
/** When true, fill the parent container instead of applying the standalone
* feed max-widths. Used by the desktop 3-column masonry on the home page. */
fluid?: boolean;
}) {
const Bubble = pickBubble(post);
const isVisual =
Bubble === AlbumBubble ||
Bubble === VideoBubble ||
Bubble === ImageBubble ||
Bubble === ImageWithTextBubble;
return (
<div
id={`post-${post.id}`}
className={
fluid
? "w-full scroll-mt-[82px] md:scroll-mt-[98px]"
: "mx-auto w-full max-w-[358px] scroll-mt-[82px] md:max-w-[680px] md:scroll-mt-[98px] lg:max-w-[900px] xl:max-w-[1120px]"
}
>
<article
className={`relative w-full overflow-hidden rounded-2xl bg-[#272632] text-left shadow-sm ${
isVisual ? "p-0" : "px-4 py-3"
}`}
>
2026-06-02 00:36:11 +08:00
<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"}>
<LinkPreviewCard preview={post.linkPreview} />
</div>
) : null}
<time
dateTime={post.publishedAt}
className={`block text-right text-[12px] leading-[19px] text-[#A8A9AE] ${
isVisual ? "px-4 pb-3 pt-0.5" : "mt-3"
}`}
>
{formatDateTime(post.publishedAt)}
</time>
</article>
</div>
);
}