import {AnimatePresence, m} from 'framer-motion'; import {Fragment, ReactNode, useContext, useMemo} from 'react'; import clsx from 'clsx'; import {getPreviewForEntry} from './available-previews'; import {FileEntry} from '../file-entry'; import {FilePreviewContext} from './file-preview-context'; import {IconButton} from '../../ui/buttons/icon-button'; import {ChevronLeftIcon} from '../../icons/material/ChevronLeft'; import {ChevronRightIcon} from '../../icons/material/ChevronRight'; import {FileDownloadIcon} from '../../icons/material/FileDownload'; import {downloadFileFromUrl} from '../utils/download-file-from-url'; import {useFileEntryUrls} from '../hooks/file-entry-urls'; import {Trans} from '../../i18n/trans'; import {Button} from '../../ui/buttons/button'; import {CloseIcon} from '../../icons/material/Close'; import {FileThumbnail} from '../file-type-icon/file-thumbnail'; import {useMediaQuery} from '../../utils/hooks/use-media-query'; import {KeyboardArrowLeftIcon} from '../../icons/material/KeyboardArrowLeft'; import {KeyboardArrowRightIcon} from '../../icons/material/KeyboardArrowRight'; import {useControlledState} from '@react-stately/utils'; import {opacityAnimation} from '../../ui/animation/opacity-animation'; export interface FilePreviewContainerProps { entries: FileEntry[]; activeIndex?: number; defaultActiveIndex?: number; onActiveIndexChange?: (index: number) => void; onClose?: () => void; showHeader?: boolean; headerActionsLeft?: ReactNode; className?: string; allowDownload?: boolean; } export function FilePreviewContainer({ entries, onClose, showHeader = true, className, headerActionsLeft, allowDownload = true, ...props }: FilePreviewContainerProps) { const isMobile = useMediaQuery('(max-width: 1024px)'); const [activeIndex, setActiveIndex] = useControlledState( props.activeIndex, props.defaultActiveIndex || 0, props.onActiveIndexChange ); const activeEntry = entries[activeIndex]; const contextValue = useMemo(() => { return {entries, activeIndex}; }, [entries, activeIndex]); const Preview = getPreviewForEntry(activeEntry); if (!activeEntry) { onClose?.(); return null; } const canOpenNext = entries.length - 1 > activeIndex; const openNext = () => { setActiveIndex(activeIndex + 1); }; const canOpenPrevious = activeIndex > 0; const openPrevious = () => { setActiveIndex(activeIndex - 1); }; return ( {showHeader && (
)}
{isMobile && ( )} {isMobile && ( )}
); } interface HeaderProps { onNext?: () => void; onPrevious?: () => void; onClose?: () => void; isMobile: boolean | null; actionsLeft?: ReactNode; allowDownload?: boolean; } function Header({ onNext, onPrevious, onClose, isMobile, actionsLeft, allowDownload, }: HeaderProps) { const {entries, activeIndex} = useContext(FilePreviewContext); const activeEntry = entries[activeIndex]; const {downloadUrl} = useFileEntryUrls(activeEntry); const desktopDownloadButton = ( ); const mobileDownloadButton = ( { if (downloadUrl) { downloadFileFromUrl(downloadUrl); } }} > ); const downloadButton = isMobile ? mobileDownloadButton : desktopDownloadButton; return (
{actionsLeft} {allowDownload ? downloadButton : undefined}
{activeEntry.name}
{!isMobile && (
{activeIndex + 1}
/
{entries.length}
)}
); }