--- title: "官方物料 cards — bottom-left filename overlay" type: quick-work date: 2026-06-03 --- # 官方物料 cards — bottom-left filename overlay ## Task In every content card classified as 官方物料 (`categorySlug === "official-assets"`), display the source filename at the bottom-left of the card — image filename for image bubbles, video filename for video bubbles. ## Data Source — Confirmed - Endpoint: `/api/posts` (list, called by `src/components/messageStream/hooks/usePostStream.ts:89`) and `/api/posts/:id` (single, used by `MessageStream` deep-links). - Field: `Post.attachments[*].filename` (`src/types/post.ts`). - Category gate: `Post.categorySlug === "official-assets"` (also referenced in `src/lib/categorySvgSlug.ts:13`, `src/pages/Categories/index.tsx:23`, `src/pages/Home/index.tsx:33`). - No additional API call is needed — `filename` already ships with the post payload. ## Changes - `src/components/messageStream/AttachmentFilenameLabel.tsx` (new) — small dark pill overlay using `filenameWithExtension(att.filename, att.mime)`, positioned `absolute bottom-2 left-2`, with `pointer-events-none`, `max-w-[calc(100%-1rem)]`, `truncate`, and a `title` attribute so the full filename is available on hover. Style mirrors the `AttachmentDownloadPill` (`bg-black/80` + `ring-white/20` + `backdrop-blur-md`) for visual consistency. - `src/components/messageStream/bubbles/SingleImageFrame.tsx` — accepts new `showFilename?: boolean` prop; when true, renders `AttachmentFilenameLabel` alongside the existing top-left download pill. - `src/components/messageStream/bubbles/ImageBubble.tsx` — passes `showFilename={post.categorySlug === "official-assets"}`. - `src/components/messageStream/bubbles/ImageWithTextBubble.tsx` — same gate, threaded through `SingleImageFrame`. - `src/components/messageStream/bubbles/AlbumBubble.tsx` — when category matches, renders the filename label inside each visible tile (skipping the `+N` overflow tile so its overlay stays clean). - `src/components/messageStream/bubbles/VideoBubble.tsx` — `VideoAttachmentCard` accepts `showFilename`, threaded into both the multi-video grid layout and the single-video layout. Skipped on the `+N` overflow tile. ## Verification - `npx tsc --noEmit` — clean. - `npm run format` then `npm run format:check` — clean. - `npm test` — 49/49 passing. - Visual confirmation pending on a posts feed that contains `official-assets` content. ## Notes - Reuses existing `filenameWithExtension` util so attachments without an extension still get a sensible label from their MIME type. - The label is `pointer-events-none` so it never blocks the bubble's own tap target (open lightbox / play video). - Only single/album/video bubbles surface this. `FileDocBubble` already renders the filename inline, so no overlay is needed there. - If a future requirement adds more "show filename" categories, switch `showFilename` from a boolean gate to a derived util (e.g. `shouldShowAttachmentFilename(post)`).