113 lines
4.7 KiB
TypeScript
113 lines
4.7 KiB
TypeScript
|
|
import { useState } from 'react';
|
||
|
|
import { ChevronLeft, ChevronRight, File as FileIcon, MinusCircle, PlusCircle } from 'lucide-react';
|
||
|
|
import { FileRecord } from '../types';
|
||
|
|
|
||
|
|
interface FilePreviewProps {
|
||
|
|
file: FileRecord | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function FilePreview({ file }: FilePreviewProps) {
|
||
|
|
const [zoom, setZoom] = useState(100);
|
||
|
|
const [page, setPage] = useState(1);
|
||
|
|
const totalPages = 1;
|
||
|
|
|
||
|
|
const handleZoomIn = () => setZoom((prev) => Math.min(prev + 10, 200));
|
||
|
|
const handleZoomOut = () => setZoom((prev) => Math.max(prev - 10, 50));
|
||
|
|
|
||
|
|
if (!file) {
|
||
|
|
return (
|
||
|
|
<div className="flex-1 flex flex-col items-center justify-center bg-white p-8 text-center border border-white border-solid">
|
||
|
|
<div className="w-32 h-32 bg-gray-100 rounded-full flex items-center justify-center mb-6 shadow-inner">
|
||
|
|
<FileIcon size={48} className="text-gray-900" />
|
||
|
|
</div>
|
||
|
|
<h3 className="text-xl font-semibold text-gray-900 mb-2">Upload file</h3>
|
||
|
|
<p className="text-gray-500 max-w-xs">
|
||
|
|
Click, Drop, or Paste a file to start parsing
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex flex-col h-full bg-gray-100/50">
|
||
|
|
{/* Top Bar */}
|
||
|
|
<div className="h-16 flex items-center justify-between px-6 bg-white border-b border-gray-200 z-10 relative">
|
||
|
|
<div className="flex items-center gap-3 overflow-hidden z-20">
|
||
|
|
<div className="p-2 bg-blue-50 text-blue-600 rounded-lg">
|
||
|
|
<FileIcon size={18} />
|
||
|
|
</div>
|
||
|
|
<h2 className="text-sm font-semibold text-gray-900 truncate max-w-[200px]" title={file.filename}>
|
||
|
|
{file.filename}
|
||
|
|
</h2>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 flex items-center gap-4 z-10">
|
||
|
|
{totalPages >= 1 && (
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<button
|
||
|
|
onClick={() => setPage(p => Math.max(1, p - 1))}
|
||
|
|
disabled={page === 1}
|
||
|
|
className="p-1 hover:bg-white hover:shadow-sm rounded-md text-gray-500 disabled:opacity-30 disabled:hover:bg-transparent disabled:hover:shadow-none transition-all"
|
||
|
|
>
|
||
|
|
<ChevronLeft size={16} />
|
||
|
|
</button>
|
||
|
|
<span className="text-xs font-medium text-gray-600 px-1 select-none min-w-[3rem] text-center">
|
||
|
|
{page} / {totalPages}
|
||
|
|
</span>
|
||
|
|
<button
|
||
|
|
onClick={() => setPage(p => Math.min(totalPages, p + 1))}
|
||
|
|
disabled={page === totalPages}
|
||
|
|
className="p-1 hover:bg-white hover:shadow-sm rounded-md text-gray-500 disabled:opacity-30 disabled:hover:bg-transparent disabled:hover:shadow-none transition-all"
|
||
|
|
>
|
||
|
|
<ChevronRight size={16} />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<button
|
||
|
|
onClick={handleZoomOut}
|
||
|
|
className="p-1 hover:bg-white hover:shadow-sm rounded-md text-gray-500 transition-all"
|
||
|
|
title="缩小"
|
||
|
|
>
|
||
|
|
<MinusCircle size={16} />
|
||
|
|
</button>
|
||
|
|
<span className="text-xs font-medium text-gray-600 min-w-[2.5rem] text-center select-none">
|
||
|
|
{zoom}%
|
||
|
|
</span>
|
||
|
|
<button
|
||
|
|
onClick={handleZoomIn}
|
||
|
|
className="p-1 hover:bg-white hover:shadow-sm rounded-md text-gray-500 transition-all"
|
||
|
|
title="放大"
|
||
|
|
>
|
||
|
|
<PlusCircle size={16} />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Preview Content */}
|
||
|
|
<div className="flex-1 overflow-auto p-8 relative custom-scrollbar flex items-center justify-center border-r border-gray-200">
|
||
|
|
<div
|
||
|
|
className="bg-white shadow-2xl shadow-gray-200/50 transition-transform duration-200 ease-out origin-center max-w-full max-h-full flex items-center justify-center"
|
||
|
|
style={{ transform: `scale(${zoom / 100})` }}
|
||
|
|
>
|
||
|
|
{file.file_type === 'application/pdf' ? (
|
||
|
|
// Placeholder for PDF rendering - ideally use react-pdf or similar
|
||
|
|
<div className="w-[595px] h-[842px] flex items-center justify-center bg-gray-50 border border-gray-100">
|
||
|
|
<p className="text-gray-400">PDF Preview Not Implemented</p>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<img
|
||
|
|
src={file.file_path || 'https://images.pexels.com/photos/326514/pexels-photo-326514.jpeg?auto=compress&cs=tinysrgb&w=800'}
|
||
|
|
alt={file.filename}
|
||
|
|
className="max-w-full max-h-full object-contain block"
|
||
|
|
draggable={false}
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|