Files
doc_ai_frontend/src/components/FilePreview.tsx

113 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-12-22 17:37:41 +08:00
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>
);
}