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 { domainFromUrl } from '@/lib/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}
{formatFileSize(attachment.file.size)}
)}
{isUploading && (
)}
);
}
function LinkPreviewThumbnail({ entry }: { entry: LinkPreviewEntry }) {
if (entry.isLoading) {
return (
);
}
// Metadata fetch can fail; fall back to the bare URL so the link stays usable.
const { metadata } = entry;
const domain = metadata?.domain ?? domainFromUrl(entry.url);
const title = metadata?.title ?? entry.url;
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)}
/>
)}
>
);
}