import { ArrowDownToLine, LoaderCircle, X } from "lucide-react";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { useI18n } from "../../../i18n";
import type { Attachment, Post } from "../../../types/post";
import { useLightbox } from "../overlays/ImageLightbox";
import { autolink } from "../utils/autolink";
import { downloadAttachment } from "../utils/downloadFile";
import { formatBytes } from "../utils/formatBytes";
import { postDisplayText } from "../utils/postText";
const MAX_VISIBLE = 4;
function imageRatio(att: Attachment) {
return att.width && att.height ? `${att.width} / ${att.height}` : "4 / 3";
}
function ImageListDownloadButton({
postId,
attachment,
}: {
postId: string;
attachment: Attachment;
}) {
const { t } = useI18n();
const [isDownloading, setIsDownloading] = useState(false);
const handleDownload = () => {
if (isDownloading) return;
setIsDownloading(true);
void downloadAttachment(postId, attachment.id, attachment.filename)
.finally(() => setIsDownloading(false))
.catch(() => {});
};
return (
);
}
function ImageListDialog({
postId,
images,
onClose,
onPick,
}: {
postId: string;
images: Attachment[];
onClose: () => void;
onPick: (index: number) => void;
}) {
useEffect(() => {
const onKey = (event: KeyboardEvent) => {
if (event.key === "Escape") onClose();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [onClose]);
return createPortal(
e.stopPropagation()}
>
{images.map((image, index) => (
))}
,
document.body,
);
}
export function AlbumBubble({ post }: { post: Post }) {
const { openLightbox } = useLightbox();
const { lang } = useI18n();
const [listOpen, setListOpen] = useState(false);
const images = post.attachments;
const text = postDisplayText(post, lang);
const shouldMerge = images.length > MAX_VISIBLE;
if (!shouldMerge) {
return (
{images.map((att, i) => (
))}
{text ? (
{autolink(text)}
) : null}
);
}
const visible = images.slice(0, MAX_VISIBLE);
const extra = images.length - MAX_VISIBLE;
return (
{visible.map((att, i) => {
const isLastSlot = i === MAX_VISIBLE - 1 && extra > 0;
return (
);
})}
{text ? (
{autolink(text)}
) : null}
{listOpen ? (
setListOpen(false)}
onPick={(index) => {
setListOpen(false);
openLightbox(images, index, text, post.id);
}}
/>
) : null}
);
}