"use client"; // Small presentational components for chat attachments. Kept in a // separate file so ChatTab.tsx stays focused on state + send/receive // orchestration. Both variants share the file-icon + name + size // layout; the only difference is the trailing action (remove for // pending, download for completed). import type { ChatAttachment } from "./types"; function formatSize(bytes: number | undefined): string { if (bytes == null) return ""; if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } /** Inline pill for a file that the user has picked but not yet sent. * Renders above the textarea; clicking × pops it from the pending * list without uploading. */ export function PendingAttachmentPill({ file, onRemove, }: { file: File; onRemove: () => void; }) { return (
{file.name} {formatSize(file.size)}
); } /** Chip rendered inside a message bubble for a sent/received file. * Clicking triggers the download via the passed onDownload callback * so the parent controls workspace-scoped URL resolution. */ export function AttachmentChip({ attachment, onDownload, tone, }: { attachment: ChatAttachment; onDownload: (a: ChatAttachment) => void; tone: "user" | "agent"; }) { const toneClasses = tone === "user" ? "border-blue-400/30 bg-accent-strong/20 hover:bg-accent-strong/30 text-blue-100" : "border-line/50 bg-surface-card/40 hover:bg-surface-card/50 text-ink"; return ( ); } function FileGlyph({ className }: { className?: string }) { return ( ); } function DownloadGlyph({ className }: { className?: string }) { return ( ); }