| 1 | import type { FilePreviewItem, FilePreviewSource } from "../components/FilePreviewModal.types"; |
| 2 | |
| 3 | export function filePreviewKey(source: FilePreviewItem): string { |
| 4 | if ("resource" in source) |
| 5 | return JSON.stringify([ |
| 6 | source.environmentId, |
| 7 | Object.entries(source.resource) |
| 8 | .filter(([key]) => key !== "mimeType" && key !== "fileName") |
| 9 | .sort(([a], [b]) => a.localeCompare(b)), |
| 10 | ]); |
| 11 | if ("attachment" in source) return `attachment:${source.attachment.id}`; |
| 12 | return source.uri; |
| 13 | } |
| 14 | |
| 15 | /** Preserve document order and the tapped image's transition source. */ |
| 16 | export function filePreviewGallery(source: FilePreviewSource, group: readonly FilePreviewItem[]) { |
| 17 | if (source.kind !== "image") return [source]; |
| 18 | const selectedKey = filePreviewKey(source); |
| 19 | const seen = new Set<string>(); |
| 20 | const items: FilePreviewItem[] = []; |
| 21 | for (const item of source.gallery ?? group) { |
| 22 | if (item.kind !== "image") continue; |
| 23 | const key = filePreviewKey(item); |
| 24 | if (seen.has(key)) continue; |
| 25 | seen.add(key); |
| 26 | items.push(key === selectedKey ? source : item); |
| 27 | } |
| 28 | if (!seen.has(selectedKey)) items.unshift(source); |
| 29 | return items; |
| 30 | } |
| 31 | |
| 32 | /** Markdown captions are display text, never filenames for native file type detection. */ |
| 33 | export function filePreviewName(source: FilePreviewItem): string { |
| 34 | const uriName = "uri" in source ? source.uri.split(/[?#]/)[0]?.split("/").pop() : undefined; |
| 35 | const name = |
| 36 | source.name ?? ("attachment" in source ? source.attachment.name : uriName) ?? "Preview"; |
| 37 | const extension = /\.(png|jpe?g|gif|webp|heic|heif|avif|svg|pdf|docx?|xlsx?|pptx?|txt|rtf)$/i; |
| 38 | const filename = |
| 39 | source.kind !== "image" || extension.test(name) |
| 40 | ? name |
| 41 | : uriName && extension.test(uriName) |
| 42 | ? uriName |
| 43 | : name.replace(/\./g, "_"); |
| 44 | return Array.from(filename, (character) => |
| 45 | character.charCodeAt(0) < 32 || "/:\\".includes(character) ? "_" : character, |
| 46 | ).join(""); |
| 47 | } |