import * as React from "react"; import { Download, FileText, PanelRight } from "lucide-react"; import { toast } from "sonner"; import { invokeTauri } from "@/shared/api/tauri"; import { useSmoothCorners } from "@/shared/ui/smoothCorners"; import { isRelayDownloadable } from "./mediaEntry"; import { isMarkdownDocFilename, MAX_MARKDOWN_DOC_BYTES, } from "./markdownDocFile"; import { useMarkdownDocViewer } from "./markdownDocViewerContext"; import { useMarkdownRuntime } from "./runtimeContext"; /** Human-readable byte size: "820 B", "12.4 KB", "3.1 MB". */ function formatFileSize(bytes: number): string { if (!Number.isFinite(bytes) || bytes < 0) return ""; if (bytes < 1024) return `${bytes} B`; const units = ["KB", "MB", "GB", "TB"]; let size = bytes / 1024; let i = 0; while (size >= 1024 && i < units.length - 1) { size /= 1024; i += 1; } return `${size < 10 ? size.toFixed(1) : Math.round(size)} ${units[i]}`; } /** * File card for a generic (non-image, non-video) attachment: icon, filename, * size, and a download action. * * Downloads go through the native `download_file` Tauri command (HTTP inside * the app's tunnel + a save dialog), not a plain `` link. A bare * link navigates the webview to the blob URL, which escapes to the OS browser * and gets bounced to a corporate CDN interstitial ("browser not supported"). * The native command mirrors the image-download path. * * Markdown attachments (`.md`/`.markdown`/`.mdx` by imeta filename) open the * in-app markdown viewer panel instead when a hosting surface provides one — * relay-hosted only, because the viewer fetches through the authenticated * `fetch_markdown_doc_bytes` command (native 2 MiB cap), which accepts * relay `/media/` origins alone. */ export function FileCard({ href, filename, size, }: { href: string; filename: string; size?: number; }) { const cardRef = React.useRef(null); const sizeLabel = size != null ? formatFileSize(size) : ""; useSmoothCorners(cardRef); const openMarkdownDoc = useMarkdownDocViewer(); const { relayOrigin } = useMarkdownRuntime(); const opensInViewer = openMarkdownDoc !== null && isMarkdownDocFilename(filename) && // Advertised-size pre-gate: skip fetching a doc the viewer would refuse // anyway. The imeta size is untrusted, so the decoder re-checks post-fetch. (size == null || size <= MAX_MARKDOWN_DOC_BYTES) && isRelayDownloadable(href, relayOrigin ?? undefined); return ( ); }