import { useMemo, useState } from "react"; import { FileIcon, Globe, Loader2, Plus, X } from "lucide-react"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import { Skeleton } from "@/components/ui/skeleton"; import { cn } from "@/lib/utils"; import type { LinkPreviewEntry } from "@/hooks/use-link-metadata"; import { AttachmentLightbox, getAttachmentHandler, type AttachmentItem, } from "@/features/attachments/attachment-lightbox"; import { platform } from "@/lib/platform"; export interface PendingAttachment { id: string; file: File; thumbnailUrl?: string; status: "pending" | "uploading" | "uploaded" | "error"; } interface AttachmentStripProps { attachments: PendingAttachment[]; onRemove: (id: string) => void; onAddClick: () => void; linkPreviews?: LinkPreviewEntry[]; } function pendingToItem(p: PendingAttachment): AttachmentItem { return { id: p.id, filename: p.file.name, mimeType: p.file.type || "application/octet-stream", sizeBytes: p.file.size, source: { kind: "local", file: p.file }, }; } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } function AttachmentThumbnail({ attachment, onRemove, onPreview, }: { attachment: PendingAttachment; onRemove: () => void; onPreview?: () => void; }) { const isImage = attachment.file.type.startsWith("image/"); const isUploading = attachment.status === "uploading"; const isError = attachment.status === "error"; const previewable = getAttachmentHandler(attachment.file.type) === "lightbox"; return (
{isImage && attachment.thumbnailUrl ? ( {attachment.file.name} ) : (
{attachment.file.name} {formatFileSize(attachment.file.size)}
)} {isUploading && (
)}
); } function LinkPreviewThumbnail({ entry }: { entry: LinkPreviewEntry }) { if (entry.isLoading) { return (
); } if (!entry.metadata) return null; const { metadata } = entry; return ( ); } export function AttachmentStrip({ attachments, onRemove, onAddClick, linkPreviews, }: AttachmentStripProps) { const hasLinks = linkPreviews && linkPreviews.length > 0; // Lightbox state — only previewable attachments go in. const previewable = useMemo( () => attachments.filter((a) => getAttachmentHandler(a.file.type) === "lightbox"), [attachments], ); const items = useMemo(() => previewable.map(pendingToItem), [previewable]); const [openIndex, setOpenIndex] = useState(null); if (attachments.length === 0 && !hasLinks) return null; return ( <>
{attachments.map((a) => ( onRemove(a.id)} onPreview={() => { const idx = previewable.indexOf(a); if (idx >= 0) setOpenIndex(idx); }} /> ))} {linkPreviews?.map((entry) => ( ))}
{items.length > 0 && ( onRemove(item.id)} /> )} ); }