import { useMemo, useState } from 'react' import { ImageGalleryModal } from './ImageGalleryModal' import { getBaseUrl } from '../../api/client' const IMAGE_EXTENSIONS = /\.(png|jpe?g|gif|webp|svg|bmp|avif|ico)$/i /** * Extracts absolute image file paths from text content. * Matches paths like /Users/.../image.png, /tmp/output.jpg, etc. */ export function extractImagePaths(text: string): string[] { // Match absolute paths ending with image extensions // Handles paths that may be wrapped in backticks, quotes, or standalone const regex = /(?:^|[\s`"'(])(\/?(?:[A-Za-z]:[\\/]|\/)[^\s`"')<>]+\.(?:png|jpe?g|gif|webp|svg|bmp|avif|ico))/gim const paths: string[] = [] const seen = new Set() let match: RegExpExecArray | null while ((match = regex.exec(text)) !== null) { const p = match[1]!.trim() if (!seen.has(p) && IMAGE_EXTENSIONS.test(p)) { seen.add(p) paths.push(p) } } return paths } function fileUrl(filePath: string): string { return `${getBaseUrl()}/api/filesystem/file?path=${encodeURIComponent(filePath)}` } function fileName(filePath: string): string { return filePath.split('/').pop() || filePath } type Props = { text: string } export function InlineImageGallery({ text }: Props) { const [activeIndex, setActiveIndex] = useState(null) const imagePaths = useMemo(() => extractImagePaths(text), [text]) const images = useMemo( () => imagePaths.map((p) => ({ src: fileUrl(p), name: fileName(p) })), [imagePaths], ) if (images.length === 0) return null return ( <>
image {images.length === 1 ? '1 image' : `${images.length} images`}
{images.map((img, i) => ( ))}
{activeIndex !== null && activeIndex >= 0 && ( setActiveIndex(null)} onSelect={setActiveIndex} /> )} ) }