2025-08-15 14:43:30 +01:00
|
|
|
import React from 'react';
|
2025-08-22 17:12:14 +01:00
|
|
|
import { Box, Center } from '@mantine/core';
|
|
|
|
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
2025-09-16 15:08:11 +01:00
|
|
|
import { StirlingFileStub } from '../../types/fileContext';
|
2025-08-15 14:43:30 +01:00
|
|
|
import DocumentThumbnail from './filePreview/DocumentThumbnail';
|
|
|
|
import DocumentStack from './filePreview/DocumentStack';
|
|
|
|
import HoverOverlay from './filePreview/HoverOverlay';
|
|
|
|
import NavigationArrows from './filePreview/NavigationArrows';
|
|
|
|
|
|
|
|
export interface FilePreviewProps {
|
|
|
|
// Core file data
|
2025-09-16 15:08:11 +01:00
|
|
|
file: File | StirlingFileStub | null;
|
2025-08-15 14:43:30 +01:00
|
|
|
thumbnail?: string | null;
|
|
|
|
|
|
|
|
// Optional features
|
|
|
|
showStacking?: boolean;
|
|
|
|
showHoverOverlay?: boolean;
|
|
|
|
showNavigation?: boolean;
|
|
|
|
|
|
|
|
// State
|
|
|
|
totalFiles?: number;
|
|
|
|
isAnimating?: boolean;
|
|
|
|
|
|
|
|
// Event handlers
|
2025-09-16 15:08:11 +01:00
|
|
|
onFileClick?: (file: File | StirlingFileStub | null) => void;
|
2025-08-15 14:43:30 +01:00
|
|
|
onPrevious?: () => void;
|
|
|
|
onNext?: () => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FilePreview: React.FC<FilePreviewProps> = ({
|
|
|
|
file,
|
|
|
|
thumbnail,
|
|
|
|
showStacking = false,
|
|
|
|
showHoverOverlay = false,
|
|
|
|
showNavigation = false,
|
|
|
|
totalFiles = 1,
|
|
|
|
isAnimating = false,
|
|
|
|
onFileClick,
|
|
|
|
onPrevious,
|
|
|
|
onNext
|
|
|
|
}) => {
|
2025-08-22 17:12:14 +01:00
|
|
|
if (!file) {
|
|
|
|
return (
|
|
|
|
<Box style={{ width: '100%', height: '100%' }}>
|
|
|
|
<Center style={{ width: '100%', height: '100%' }}>
|
|
|
|
<InsertDriveFileIcon
|
|
|
|
style={{
|
|
|
|
fontSize: '4rem',
|
|
|
|
color: 'var(--mantine-color-gray-4)',
|
|
|
|
opacity: 0.6
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Center>
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
}
|
2025-08-15 14:43:30 +01:00
|
|
|
|
|
|
|
const hasMultipleFiles = totalFiles > 1;
|
|
|
|
|
|
|
|
// Animation styles
|
|
|
|
const animationStyle = isAnimating ? {
|
|
|
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
|
|
transform: 'scale(0.95) translateX(1.25rem)',
|
|
|
|
opacity: 0.7
|
|
|
|
} : {};
|
|
|
|
|
|
|
|
// Build the component composition
|
|
|
|
let content = (
|
|
|
|
<DocumentThumbnail
|
|
|
|
file={file}
|
|
|
|
thumbnail={thumbnail}
|
|
|
|
style={animationStyle}
|
|
|
|
onClick={() => onFileClick?.(file)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
// Wrap with hover overlay if needed
|
|
|
|
if (showHoverOverlay && onFileClick) {
|
|
|
|
content = <HoverOverlay>{content}</HoverOverlay>;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap with document stack if needed
|
|
|
|
if (showStacking) {
|
|
|
|
content = (
|
|
|
|
<DocumentStack totalFiles={totalFiles}>
|
|
|
|
{content}
|
|
|
|
</DocumentStack>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap with navigation if needed
|
|
|
|
if (showNavigation && hasMultipleFiles && onPrevious && onNext) {
|
|
|
|
content = (
|
|
|
|
<NavigationArrows
|
|
|
|
onPrevious={onPrevious}
|
|
|
|
onNext={onNext}
|
|
|
|
disabled={isAnimating}
|
|
|
|
>
|
|
|
|
{content}
|
|
|
|
</NavigationArrows>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Box style={{ width: '100%', height: '100%' }}>
|
|
|
|
{content}
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default FilePreview;
|