import { Play } from "lucide-react"; import { Link, useNavigate } from "react-router-dom"; import { FavoriteButton } from "../favorites/FavoriteButton"; import { useI18n } from "../i18n"; import { useLocalizedPath } from "../useLocalizedPath"; import type { Attachment, Post } from "../types/post"; import { DownloadCloudIcon } from "./icons/DownloadCloudIcon"; import { fileIcon } from "./messageStream/utils/fileIcon"; import { filenameWithExtension, splitFilename, } from "./messageStream/utils/filenameDisplay"; import { formatBytes } from "./messageStream/utils/formatBytes"; import { formatDateTime } from "./messageStream/utils/formatTime"; import { postDisplayText } from "./messageStream/utils/postText"; import { autolink } from "./messageStream/utils/autolink"; function LatestActions({ post, attachment, }: { post: Post; attachment?: Attachment; }) { const { t } = useI18n(); const lp = useLocalizedPath(); const navigate = useNavigate(); const goToPost = () => { navigate(lp(`/browse?post=${encodeURIComponent(post.id)}`)); }; return (
{attachment ? ( ) : null}
); } function Footer({ post, attachment }: { post: Post; attachment?: Attachment }) { return (
); } function attachmentPreview(att: Attachment | undefined): string { if (!att) return ""; return att.thumbnailUrl ?? att.posterUrl ?? att.thumbUrl ?? att.url ?? ""; } function FileCard({ post, att }: { post: Post; att: Attachment }) { const { lang } = useI18n(); const { Icon, color } = fileIcon({ mime: att.mime, filename: att.filename }); const displayFilename = filenameWithExtension(att.filename, att.mime); const text = postDisplayText(post, lang); return (
{(() => { const { base, ext } = splitFilename(displayFilename); const tailChars = Math.min(8, base.length); const head = base.slice(0, base.length - tailChars); const tail = base.slice(base.length - tailChars) + ext; return ( <> {head} {tail} ); })()}
{formatBytes(att.sizeBytes)}
{text || post.title || displayFilename}
); } function PillDownloadIcon() { return ( ); } function MediaSizeChip({ att }: { att: Attachment }) { return (
{formatBytes(att.sizeBytes)}
); } function MediaTile({ att, showExtra, }: { att: Attachment; showExtra?: number; }) { const src = attachmentPreview(att); const isVideo = att.kind === "video" || att.mime.startsWith("video/"); return (
{src ? ( ) : null} {isVideo ? (
) : null} {showExtra ? (
+{showExtra}
) : null}
); } function MediaGrid({ attachments }: { attachments: Attachment[] }) { const visible = attachments.slice(0, 4); const extra = Math.max(0, attachments.length - visible.length); if (visible.length === 0) return
; if (visible.length === 1) return ; if (visible.length === 2) { return (
{visible.map((att) => ( ))}
); } if (visible.length === 3) { return (
); } return (
{visible.map((att, index) => ( 0 && index === visible.length - 1 ? extra : 0} /> ))}
); } function VisualCard({ post }: { post: Post }) { const { lang } = useI18n(); const att = post.attachments[0]; const isVideo = att?.kind === "video" || att?.mime.startsWith("video/"); const text = postDisplayText(post, lang); return (
{text || post.title ? (
{autolink(text || post.title || "")}
) : null}
); } function CardLink({ postId }: { postId: string }) { const lp = useLocalizedPath(); return ( ); } export function LatestUpdateCard({ post }: { post: Post }) { const first = post.attachments[0]; const isFile = !!first && !( first.kind === "image" || first.kind === "video" || first.mime.startsWith("image/") || first.mime.startsWith("video/") ); if (isFile) return ; return ; }