feat(stream): surface source filename on official-assets cards
Image, album, and video bubbles in the official-assets category now render the attachment filename as a bottom-left overlay so editors can identify the source asset at a glance. Shared AttachmentFilenameLabel component mirrors the AttachmentDownloadPill style, uses filenameWithExtension so MIME-only attachments still get a sensible label, and is pointer-events-none so it never blocks the bubble's tap target.
This commit is contained in:
@@ -2,6 +2,7 @@ import { useI18n } from "../../../i18n";
|
||||
import type { Post } from "../../../types/post";
|
||||
import { ALBUM_GAP, ALBUM_MAX_HEIGHT } from "../../../constants/media";
|
||||
import { AttachmentDownloadPill } from "../AttachmentDownloadPill";
|
||||
import { AttachmentFilenameLabel } from "../AttachmentFilenameLabel";
|
||||
import { BubbleImage } from "../BubbleImage";
|
||||
import { useImageRatios } from "../hooks/useImageRatios";
|
||||
import { useLightbox } from "../overlays/ImageLightbox";
|
||||
@@ -19,6 +20,7 @@ export function AlbumBubble({ post }: { post: Post }) {
|
||||
const text = postDisplayText(post, lang);
|
||||
const visible = images.slice(0, MAX_VISIBLE);
|
||||
const extra = images.length - MAX_VISIBLE;
|
||||
const showFilename = post.categorySlug === "official-assets";
|
||||
|
||||
const sources = visible.map(
|
||||
(att) => att.thumbnailUrl ?? att.thumbUrl ?? att.url,
|
||||
@@ -90,6 +92,9 @@ export function AlbumBubble({ post }: { post: Post }) {
|
||||
adaptive
|
||||
/>
|
||||
) : null}
|
||||
{!isLastSlot && showFilename ? (
|
||||
<AttachmentFilenameLabel attachment={att} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -4,5 +4,11 @@ import { SingleImageFrame } from "./SingleImageFrame";
|
||||
export function ImageBubble({ post }: { post: Post }) {
|
||||
const att = post.attachments[0];
|
||||
if (!att) return null;
|
||||
return <SingleImageFrame postId={post.id} attachment={att} />;
|
||||
return (
|
||||
<SingleImageFrame
|
||||
postId={post.id}
|
||||
attachment={att}
|
||||
showFilename={post.categorySlug === "official-assets"}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@ export function ImageWithTextBubble({ post }: { post: Post }) {
|
||||
if (!att) return null;
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<SingleImageFrame postId={post.id} attachment={att} text={text} />
|
||||
<SingleImageFrame
|
||||
postId={post.id}
|
||||
attachment={att}
|
||||
text={text}
|
||||
showFilename={post.categorySlug === "official-assets"}
|
||||
/>
|
||||
{text ? (
|
||||
<CollapsibleText
|
||||
wrapperClassName="px-4 pt-3"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Attachment } from "../../../types/post";
|
||||
import { AttachmentDownloadPill } from "../AttachmentDownloadPill";
|
||||
import { AttachmentFilenameLabel } from "../AttachmentFilenameLabel";
|
||||
import { useLightbox } from "../overlays/ImageLightbox";
|
||||
import { AdaptiveImageFrame } from "./AdaptiveImageFrame";
|
||||
|
||||
@@ -11,10 +12,13 @@ export function SingleImageFrame({
|
||||
postId,
|
||||
attachment,
|
||||
text,
|
||||
showFilename = false,
|
||||
}: {
|
||||
postId: string;
|
||||
attachment: Attachment;
|
||||
text?: string;
|
||||
/** Show the source filename pinned bottom-left (used for 官方物料 cards). */
|
||||
showFilename?: boolean;
|
||||
}) {
|
||||
const { openLightbox } = useLightbox();
|
||||
return (
|
||||
@@ -29,6 +33,9 @@ export function SingleImageFrame({
|
||||
ariaLabel="View image"
|
||||
>
|
||||
<AttachmentDownloadPill postId={postId} attachment={attachment} />
|
||||
{showFilename ? (
|
||||
<AttachmentFilenameLabel attachment={attachment} />
|
||||
) : null}
|
||||
</AdaptiveImageFrame>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createPortal } from "react-dom";
|
||||
import { useI18n } from "../../../i18n";
|
||||
import type { Attachment, Post } from "../../../types/post";
|
||||
import { AttachmentDownloadPill } from "../AttachmentDownloadPill";
|
||||
import { AttachmentFilenameLabel } from "../AttachmentFilenameLabel";
|
||||
import { MessageInlineVideo } from "../MessageInlineVideo";
|
||||
import {
|
||||
useShouldUseMobilePreview,
|
||||
@@ -57,12 +58,15 @@ function VideoAttachmentCard({
|
||||
compact = false,
|
||||
overlayCount,
|
||||
onMoreClick,
|
||||
showFilename = false,
|
||||
}: {
|
||||
postId: string;
|
||||
attachment: Attachment;
|
||||
compact?: boolean;
|
||||
overlayCount?: number;
|
||||
onMoreClick?: () => void;
|
||||
/** Show the source filename pinned bottom-left (used for 官方物料 cards). */
|
||||
showFilename?: boolean;
|
||||
}) {
|
||||
const { openVideo } = useVideoPlayer();
|
||||
const [playing, setPlaying] = useState(false);
|
||||
@@ -117,6 +121,9 @@ function VideoAttachmentCard({
|
||||
leadingLabel={duration}
|
||||
/>
|
||||
) : null}
|
||||
{!overlayCount && showFilename ? (
|
||||
<AttachmentFilenameLabel attachment={attachment} />
|
||||
) : null}
|
||||
{overlayCount ? (
|
||||
<button
|
||||
type="button"
|
||||
@@ -324,6 +331,7 @@ export function VideoBubble({ post }: { post: Post }) {
|
||||
const [listOpen, setListOpen] = useState(false);
|
||||
const videos = post.attachments.filter(isVideoAttachment);
|
||||
const text = postDisplayText(post, lang);
|
||||
const showFilename = post.categorySlug === "official-assets";
|
||||
if (!videos.length) return null;
|
||||
|
||||
if (videos.length >= 2) {
|
||||
@@ -349,6 +357,7 @@ export function VideoBubble({ post }: { post: Post }) {
|
||||
compact
|
||||
overlayCount={isLastSlot ? extra : undefined}
|
||||
onMoreClick={() => setListOpen(true)}
|
||||
showFilename={showFilename}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -379,7 +388,11 @@ export function VideoBubble({ post }: { post: Post }) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<VideoAttachmentCard postId={post.id} attachment={videos[0]} />
|
||||
<VideoAttachmentCard
|
||||
postId={post.id}
|
||||
attachment={videos[0]}
|
||||
showFilename={showFilename}
|
||||
/>
|
||||
{text ? (
|
||||
<CollapsibleText
|
||||
wrapperClassName="px-4 pt-3"
|
||||
|
||||
Reference in New Issue
Block a user