@eternalheart/react-file-preview 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils/fileNormalizer.ts","../src/renderers/ImageRenderer.tsx","../src/utils/pdfConfig.ts","../src/renderers/PdfRenderer.tsx","../src/renderers/DocxRenderer.tsx","../src/renderers/XlsxRenderer.tsx","../src/renderers/PptxRenderer.tsx","../src/renderers/VideoRenderer.tsx","../src/renderers/AudioRenderer.tsx","../node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@18.3.1/node_modules/react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js","../src/renderers/MarkdownRenderer.tsx","../src/renderers/TextRenderer.tsx","../src/renderers/UnsupportedRenderer.tsx","../src/FilePreviewModal.tsx"],"sourcesContent":["import { PreviewFile, PreviewFileInput } from '../types';\n\n/**\n * 从 URL 字符串中提取文件名\n */\nfunction getFileNameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const fileName = pathname.split('/').pop() || 'file';\n return decodeURIComponent(fileName);\n } catch {\n // 如果不是有效的 URL,尝试从路径中提取\n const fileName = url.split('/').pop() || 'file';\n return decodeURIComponent(fileName);\n }\n}\n\n/**\n * 从文件名中推断 MIME 类型\n */\nfunction inferMimeType(fileName: string): string {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n \n const mimeTypes: Record<string, string> = {\n // 图片\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n \n // 视频\n mp4: 'video/mp4',\n webm: 'video/webm',\n ogg: 'video/ogg',\n ogv: 'video/ogg',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n m4v: 'video/x-m4v',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n \n // 音频\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n m4a: 'audio/mp4',\n aac: 'audio/aac',\n flac: 'audio/flac',\n \n // 文档\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n ppt: 'application/vnd.ms-powerpoint',\n \n // 文本\n txt: 'text/plain',\n md: 'text/markdown',\n markdown: 'text/markdown',\n json: 'application/json',\n xml: 'application/xml',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n jsx: 'text/javascript',\n tsx: 'text/typescript',\n py: 'text/x-python',\n java: 'text/x-java',\n cpp: 'text/x-c++src',\n c: 'text/x-csrc',\n cs: 'text/x-csharp',\n php: 'text/x-php',\n rb: 'text/x-ruby',\n go: 'text/x-go',\n rs: 'text/x-rust',\n yaml: 'text/yaml',\n yml: 'text/yaml',\n };\n \n return mimeTypes[ext] || 'application/octet-stream';\n}\n\n/**\n * 标准化文件输入为 PreviewFile 格式\n * 支持三种输入类型:\n * 1. File 对象(原生浏览器 File)\n * 2. PreviewFileLink 对象(包含 name, url, type 等属性)\n * 3. string(HTTP URL)\n */\nexport function normalizeFile(input: PreviewFileInput, index: number = 0): PreviewFile {\n // 情况 1: 原生 File 对象\n if (input instanceof File) {\n return {\n id: `file-${Date.now()}-${index}`,\n name: input.name,\n url: URL.createObjectURL(input),\n type: input.type || inferMimeType(input.name),\n size: input.size,\n };\n }\n \n // 情况 2: 字符串 URL\n if (typeof input === 'string') {\n const fileName = getFileNameFromUrl(input);\n return {\n id: `url-${Date.now()}-${index}`,\n name: fileName,\n url: input,\n type: inferMimeType(fileName),\n };\n }\n \n // 情况 3: PreviewFileLink 对象\n return {\n id: input.id || `link-${Date.now()}-${index}`,\n name: input.name,\n url: input.url,\n type: input.type || inferMimeType(input.name),\n size: input.size,\n };\n}\n\n/**\n * 批量标准化文件输入\n */\nexport function normalizeFiles(inputs: PreviewFileInput[]): PreviewFile[] {\n return inputs.map((input, index) => normalizeFile(input, index));\n}\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n onZoomChange?: (zoom: number) => void;\n}\n\nexport const ImageRenderer: React.FC<ImageRendererProps> = ({\n url,\n zoom,\n rotation,\n onZoomChange\n}) => {\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [internalZoom, setInternalZoom] = useState(1); // 内部缩放状态\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLoaded(false);\n setError(null);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n }, [url]);\n\n // 当外部 zoom 改变时,同步内部 zoom\n useEffect(() => {\n setInternalZoom(zoom);\n }, [zoom]);\n\n // 重置位置当缩放或旋转改变时\n useEffect(() => {\n setPosition({ x: 0, y: 0 });\n }, [zoom, rotation]);\n\n const handleLoad = () => {\n setLoaded(true);\n };\n\n const handleError = () => {\n setError('图片加载失败');\n setLoaded(true);\n };\n\n const handleDoubleClick = () => {\n // 双击重置位置\n setPosition({ x: 0, y: 0 });\n };\n\n // 鼠标滚轮缩放\n const handleWheel = useCallback((e: React.WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\n setInternalZoom(prev => {\n const newZoom = Math.max(0.5, Math.min(5, prev + delta)); // 限制缩放范围 0.5-5\n // 同步缩放比例到父组件\n if (onZoomChange) {\n onZoomChange(newZoom);\n }\n return newZoom;\n });\n }, [onZoomChange]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return; // 只响应左键\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n }, [isDragging, dragStart]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"flex items-center justify-center w-full h-full overflow-hidden\"\n onWheel={handleWheel}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {!loaded && !error && (\n <div className=\"flex items-center justify-center\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n )}\n\n {error && (\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n )}\n\n <motion.img\n src={url}\n alt=\"Preview\"\n className={`max-w-none select-none ${!loaded ? 'hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${internalZoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n </div>\n );\n};\n\n","import { pdfjs } from 'react-pdf';\n\n/**\n * PDF.js Worker 配置\n *\n * 配置策略:\n * 1. 优先尝试使用本地 public 目录中的 worker 文件\n * 2. 如果本地文件不存在,降级使用 CDN\n * 3. 使用 HTTPS CDN 确保安全性\n */\n\nconst pdfjsVersion = pdfjs.version;\n\n// 配置 worker 路径\n// 优先使用本地 worker,如果不存在则使用 CDN\nconst workerSrc = `/pdf.worker.min.mjs`;\n\n// 尝试使用本地 worker\npdfjs.GlobalWorkerOptions.workerSrc = workerSrc;\n\n// 添加错误处理,如果本地 worker 加载失败,自动降级到 CDN\nconst originalWorkerSrc = pdfjs.GlobalWorkerOptions.workerSrc;\nconst cdnWorkerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`;\n\n// 监听 worker 加载错误\nif (typeof window !== 'undefined') {\n window.addEventListener('error', (event) => {\n if (event.message?.includes('pdf.worker') && pdfjs.GlobalWorkerOptions.workerSrc === originalWorkerSrc) {\n console.warn('本地 PDF worker 加载失败,切换到 CDN:', cdnWorkerSrc);\n pdfjs.GlobalWorkerOptions.workerSrc = cdnWorkerSrc;\n }\n });\n}\n\nexport { pdfjs };\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Document, Page } from 'react-pdf';\nimport 'react-pdf/dist/esm/Page/AnnotationLayer.css';\nimport 'react-pdf/dist/esm/Page/TextLayer.css';\n\n// 导入 PDF.js 配置\nimport '../utils/pdfConfig';\n\ninterface PdfRendererProps {\n url: string;\n zoom: number;\n currentPage: number;\n onPageChange: (page: number) => void;\n onTotalPagesChange: (total: number) => void;\n}\n\nexport const PdfRenderer: React.FC<PdfRendererProps> = ({\n url,\n zoom,\n currentPage,\n onPageChange,\n onTotalPagesChange,\n}) => {\n const [numPages, setNumPages] = useState<number>(0);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n useEffect(() => {\n setError(null);\n }, [url]);\n\n const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {\n setNumPages(numPages);\n onTotalPagesChange(numPages);\n onPageChange(1);\n };\n\n const onDocumentLoadError = (error: Error) => {\n console.error('PDF 加载错误:', error);\n setError('PDF 文件加载失败');\n };\n\n // 滚动时更新当前页码\n const handleScroll = useCallback(() => {\n if (!containerRef.current) return;\n\n const container = containerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n // 找到当前可见的页面\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageRefs.current.forEach((pageElement, pageNumber) => {\n const rect = pageElement.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n onPageChange(currentVisiblePage);\n }\n }, [currentPage, onPageChange]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 设置页面引用\n const setPageRef = useCallback((pageNumber: number, element: HTMLDivElement | null) => {\n if (element) {\n pageRefs.current.set(pageNumber, element);\n } else {\n pageRefs.current.delete(pageNumber);\n }\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col items-center w-full h-full overflow-auto py-8 px-4\"\n >\n {error && (\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n )}\n\n {!error && (\n <Document\n file={url}\n onLoadSuccess={onDocumentLoadSuccess}\n onLoadError={onDocumentLoadError}\n loading={\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n }\n >\n <div className=\"flex flex-col gap-4\">\n {Array.from(new Array(numPages), (_, index) => {\n const pageNumber = index + 1;\n return (\n <div\n key={`page_${pageNumber}`}\n ref={(el) => setPageRef(pageNumber, el)}\n className=\"relative\"\n >\n <Page\n pageNumber={pageNumber}\n scale={zoom}\n loading={\n <div className=\"flex items-center justify-center p-8 bg-white/5 rounded-lg min-h-[600px]\">\n <div className=\"w-8 h-8 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n }\n renderTextLayer={true}\n renderAnnotationLayer={true}\n className=\"shadow-2xl\"\n />\n {/* 页码标签 */}\n <div className=\"absolute top-2 right-2 bg-black/60 backdrop-blur-sm text-white text-xs px-3 py-1 rounded-full\">\n {pageNumber}\n </div>\n </div>\n );\n })}\n </div>\n </Document>\n )}\n\n {/* 底部页码指示器 */}\n {numPages > 0 && (\n <div className=\"sticky bottom-4 mt-8 bg-black/60 backdrop-blur-xl text-white px-6 py-3 rounded-full text-sm font-medium shadow-2xl border border-white/10\">\n 第 {currentPage} 页 / 共 {numPages} 页\n </div>\n )}\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport mammoth from 'mammoth';\n\ninterface DocxRendererProps {\n url: string;\n}\n\nexport const DocxRenderer: React.FC<DocxRendererProps> = ({ url }) => {\n const [html, setHtml] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadDocx = async () => {\n setLoading(true);\n setError(null);\n setHtml('');\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer });\n setHtml(result.value);\n } catch (err) {\n console.error('Docx 解析错误:', err);\n setError('Word 文档解析失败');\n } finally {\n setLoading(false);\n }\n };\n\n loadDocx();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div\n className=\"max-w-4xl mx-auto bg-white rounded-lg shadow-2xl p-12\"\n dangerouslySetInnerHTML={{ __html: html }}\n style={{\n fontFamily: 'system-ui, -apple-system, sans-serif',\n lineHeight: '1.6',\n color: '#333',\n }}\n />\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport * as XLSX from 'xlsx';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const [sheets, setSheets] = useState<{ name: string; data: unknown[] }[]>([]);\n const [activeSheet, setActiveSheet] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadXlsx = async () => {\n setLoading(true);\n setError(null);\n setSheets([]);\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const workbook = XLSX.read(arrayBuffer, { type: 'array' });\n\n const parsedSheets = workbook.SheetNames.map((name) => {\n const worksheet = workbook.Sheets[name];\n const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });\n return { name, data };\n });\n\n setSheets(parsedSheets);\n setActiveSheet(0);\n } catch (err) {\n console.error('Excel 解析错误:', err);\n setError('Excel 文件解析失败');\n } finally {\n setLoading(false);\n }\n };\n\n loadXlsx();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n const currentSheet = sheets[activeSheet];\n\n return (\n <div className=\"w-full h-full flex flex-col overflow-hidden\">\n {/* Sheet Tabs */}\n {sheets.length > 1 && (\n <div className=\"flex gap-2 p-4 bg-black/20 backdrop-blur-sm overflow-x-auto border-b border-white/10\">\n {sheets.map((sheet, index) => (\n <button\n key={index}\n onClick={() => setActiveSheet(index)}\n className={`px-4 py-2 rounded-lg text-sm font-medium transition-all ${activeSheet === index\n ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-lg'\n : 'bg-white/10 text-white hover:bg-white/20'\n }`}\n >\n {sheet.name}\n </button>\n ))}\n </div>\n )}\n\n {/* Table */}\n <div className=\"flex-1 overflow-auto p-8\">\n <div className=\"inline-block min-w-full bg-gradient-to-br from-gray-800/90 to-gray-900/90 backdrop-blur-xl rounded-2xl shadow-2xl overflow-hidden border border-white/10\">\n <table className=\"min-w-full divide-y divide-white/10\">\n <tbody className=\"divide-y divide-white/10\">\n {currentSheet?.data.map((row, rowIndex) => (\n <tr\n key={rowIndex}\n className={`transition-colors ${rowIndex === 0\n ? 'bg-gradient-to-r from-purple-500/20 to-pink-500/20 font-semibold'\n : 'hover:bg-white/5'\n }`}\n >\n {(row as unknown[]).map((cell, cellIndex) => (\n <td\n key={cellIndex}\n className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-200 border-r border-white/10\"\n >\n {String(cell ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n );\n};\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Presentation } from 'lucide-react';\nimport { init } from 'pptx-preview';\n\ninterface PptxRendererProps {\n url: string;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url }) => {\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n\n const containerWidth = containerRef.current.clientWidth;\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n\n console.log('计算尺寸:', { width: containerWidth, height });\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current) return;\n\n console.log('重新初始化预览器...');\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch (e) {\n console.error('销毁预览器失败:', e);\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n console.log('重新初始化使用尺寸:', currentDimensions);\n\n // 初始化新的预览器\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: currentDimensions.height,\n });\n\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n console.log('重新初始化成功');\n } catch (e) {\n console.error('重新初始化失败:', e);\n }\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n const initialDimensions = calculateDimensions();\n lastDimensionsRef.current = initialDimensions;\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n console.log('尺寸变化太小,忽略');\n return; // 尺寸变化太小,不做任何操作\n }\n\n console.log('检测到尺寸变化:', {\n old: lastDimensions,\n new: newDimensions,\n diff: { width: widthDiff, height: heightDiff }\n });\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n console.log('尺寸变化,准备重新初始化');\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n let isMounted = true;\n\n const loadPptx = async () => {\n if (!containerRef.current) {\n console.log('Container ref not ready');\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n console.log('开始加载 PPTX:', url);\n\n // 获取文件\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n arrayBufferRef.current = arrayBuffer; // 保存到 ref\n console.log('文件加载成功,大小:', arrayBuffer.byteLength);\n\n if (!isMounted) return;\n\n // 清空容器\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n console.log('使用尺寸:', currentDimensions);\n\n // 初始化 pptx 预览器\n console.log('初始化预览器...');\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: currentDimensions.height,\n });\n\n previewerRef.current = previewer;\n\n // 预览 PPTX\n console.log('开始预览...');\n previewer.preview(arrayBuffer)\n .then(() => {\n console.log('预览成功');\n if (isMounted) {\n setLoading(false);\n }\n })\n .catch((previewErr) => {\n console.error('预览失败:', previewErr);\n if (isMounted) {\n setError('PPT 文件预览失败');\n setLoading(false);\n }\n });\n } catch (err) {\n console.error('PPTX 解析错误:', err);\n if (isMounted) {\n setError(err instanceof Error ? err.message : 'PPT 文件解析失败');\n setLoading(false);\n }\n }\n };\n\n // 延迟执行以确保 DOM 已准备好\n const timer = setTimeout(() => {\n loadPptx();\n }, 100);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n arrayBufferRef.current = null;\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch (e) {\n console.error('销毁预览器失败:', e);\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions]);\n\n return (\n <div className=\"relative flex flex-col items-center w-full h-full pt-[8px]\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm z-10 rounded-2xl\">\n <div className=\"text-center\">\n <div className=\"w-12 h-12 mx-auto mb-3 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n <p className=\"text-sm text-white/70 font-medium\">加载 PPT 中...</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm z-10 rounded-2xl\">\n <div className=\"text-center max-w-md\">\n <div className=\"w-32 h-32 mx-auto mb-6 rounded-3xl bg-gradient-to-br from-orange-500 via-red-500 to-pink-500 flex items-center justify-center shadow-2xl\">\n <Presentation className=\"w-16 h-16 text-white\" />\n </div>\n <p className=\"text-xl text-white/90 mb-3 font-medium\">PPT 预览</p>\n <p className=\"text-sm text-white/60 mb-6\">\n {error || '浏览器暂不支持直接预览 PPT 文件'}\n </p>\n <a\n href={url}\n download\n className=\"inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-xl hover:scale-105 transition-all shadow-lg\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n 下载文件\n </a>\n <p className=\"text-xs text-white/40 mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n )}\n\n {/* PPT 容器 - 始终渲染 */}\n <div\n ref={containerRef}\n className=\"pptx-wrapper w-full max-w-6xl\"\n />\n </div>\n );\n};\n\n","import { useRef, useEffect, useState } from 'react';\nimport videojs from 'video.js';\nimport 'video.js/dist/video-js.css';\n\ntype VideoJsPlayer = ReturnType<typeof videojs>;\n\ninterface VideoRendererProps {\n url: string;\n}\n\n// 根据 URL 获取视频 MIME 类型\nconst getVideoType = (url: string): string => {\n const ext = url.split('.').pop()?.toLowerCase().split('?')[0] || '';\n const typeMap: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n ogg: 'video/ogg',\n ogv: 'video/ogg',\n mov: 'video/quicktime', // MOV 使用 QuickTime MIME 类型\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n m4v: 'video/mp4',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n };\n return typeMap[ext] || 'video/mp4';\n};\n\nexport const VideoRenderer: React.FC<VideoRendererProps> = ({ url }) => {\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const videoRef = useRef<HTMLDivElement>(null);\n const playerRef = useRef<VideoJsPlayer | null>(null);\n\n useEffect(() => {\n // 确保 Video.js 播放器只初始化一次\n if (!playerRef.current && videoRef.current) {\n const videoElement = document.createElement('video-js');\n videoElement.classList.add('vjs-big-play-centered', 'vjs-theme-apple');\n videoRef.current.appendChild(videoElement);\n\n const videoType = getVideoType(url);\n\n // 为 MOV 格式提供多个 MIME 类型作为备用\n const sources = videoType === 'video/quicktime'\n ? [\n { src: url, type: 'video/quicktime' },\n { src: url, type: 'video/mp4' } // 备用方案\n ]\n : [{ src: url, type: videoType }];\n\n const player = videojs(videoElement, {\n controls: true,\n responsive: true,\n fluid: true,\n preload: 'auto',\n controlBar: {\n children: [\n 'playToggle',\n 'volumePanel',\n 'currentTimeDisplay',\n 'timeDivider',\n 'durationDisplay',\n 'progressControl',\n 'remainingTimeDisplay',\n 'fullscreenToggle'\n ],\n volumePanel: {\n inline: false\n }\n },\n html5: {\n vhs: {\n overrideNative: true\n },\n nativeVideoTracks: false,\n nativeAudioTracks: false,\n nativeTextTracks: false\n },\n sources\n });\n\n // 监听加载完成\n player.on('loadeddata', () => {\n setIsLoading(false);\n });\n\n player.on('error', () => {\n const error = player.error();\n console.error('Video.js error:', error);\n setError(`视频加载失败: ${error?.message || '未知错误'}`);\n setIsLoading(false);\n });\n\n playerRef.current = player;\n }\n }, [url]);\n\n // 清理函数\n useEffect(() => {\n const player = playerRef.current;\n\n return () => {\n if (player && !player.isDisposed()) {\n player.dispose();\n playerRef.current = null;\n }\n };\n }, []);\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-center\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-red-500/10 flex items-center justify-center\">\n <svg className=\"w-8 h-8 text-red-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n </div>\n <p className=\"text-lg font-medium text-white/90 mb-2\">视频加载失败</p>\n <p className=\"text-sm text-white/60\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center w-full h-full p-8\">\n <div className=\"w-full max-w-5xl relative\">\n {/* 加载状态 */}\n {isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/20 backdrop-blur-sm rounded-2xl z-10\">\n <div className=\"text-center\">\n <div className=\"w-12 h-12 mx-auto mb-3 border-3 border-white/20 border-t-white rounded-full animate-spin\" />\n <p className=\"text-sm text-white/70 font-medium\">加载视频中...</p>\n </div>\n </div>\n )}\n\n {/* 视频播放器容器 */}\n <div\n ref={videoRef}\n className=\"overflow-hidden\"\n style={{\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05)'\n }}\n />\n </div>\n </div>\n );\n};\n\n","import { useState, useRef, useEffect } from 'react';\nimport { Music, Play, Pause, Volume2, VolumeX, SkipBack, SkipForward } from 'lucide-react';\n\ninterface AudioRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const AudioRenderer: React.FC<AudioRendererProps> = ({ url, fileName }) => {\n const [error, setError] = useState<string | null>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [volume, setVolume] = useState(1);\n const [isMuted, setIsMuted] = useState(false);\n const audioRef = useRef<HTMLAudioElement>(null);\n\n useEffect(() => {\n const audio = audioRef.current;\n if (!audio) return;\n\n const updateTime = () => {\n if (!isNaN(audio.currentTime)) {\n setCurrentTime(audio.currentTime);\n }\n };\n\n const updateDuration = () => {\n if (!isNaN(audio.duration) && isFinite(audio.duration)) {\n setDuration(audio.duration);\n }\n };\n\n const handleEnded = () => setIsPlaying(false);\n const handleCanPlay = () => updateDuration();\n\n audio.addEventListener('timeupdate', updateTime);\n audio.addEventListener('loadedmetadata', updateDuration);\n audio.addEventListener('durationchange', updateDuration);\n audio.addEventListener('canplay', handleCanPlay);\n audio.addEventListener('ended', handleEnded);\n\n // 立即尝试获取时长\n if (audio.readyState >= 1) {\n updateDuration();\n }\n\n return () => {\n audio.removeEventListener('timeupdate', updateTime);\n audio.removeEventListener('loadedmetadata', updateDuration);\n audio.removeEventListener('durationchange', updateDuration);\n audio.removeEventListener('canplay', handleCanPlay);\n audio.removeEventListener('ended', handleEnded);\n };\n }, []);\n\n const togglePlay = () => {\n if (audioRef.current) {\n if (isPlaying) {\n audioRef.current.pause();\n } else {\n audioRef.current.play();\n }\n setIsPlaying(!isPlaying);\n }\n };\n\n const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {\n const time = parseFloat(e.target.value);\n setCurrentTime(time);\n if (audioRef.current) {\n audioRef.current.currentTime = time;\n }\n };\n\n const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const vol = parseFloat(e.target.value);\n setVolume(vol);\n if (audioRef.current) {\n audioRef.current.volume = vol;\n }\n if (vol > 0) setIsMuted(false);\n };\n\n const toggleMute = () => {\n if (audioRef.current) {\n audioRef.current.muted = !isMuted;\n setIsMuted(!isMuted);\n }\n };\n\n const skip = (seconds: number) => {\n if (audioRef.current) {\n audioRef.current.currentTime += seconds;\n }\n };\n\n const formatTime = (time: number) => {\n if (!isFinite(time) || isNaN(time) || time < 0) return '0:00';\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n };\n\n const handleError = () => {\n setError('音频加载失败');\n };\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col items-center justify-center w-full h-full p-8 gap-8\">\n {/* 音频封面 */}\n <div className=\"w-64 h-64 rounded-3xl bg-gradient-to-br from-purple-500 via-pink-500 to-rose-500 flex items-center justify-center shadow-2xl backdrop-blur-xl\">\n <Music className=\"w-32 h-32 text-white\" />\n </div>\n\n {/* 文件名 */}\n <div className=\"text-white text-center max-w-md\">\n <p className=\"text-2xl font-medium mb-1\">{fileName}</p>\n <p className=\"text-sm text-white/60\">音频文件</p>\n </div>\n\n {/* 播放控制器 */}\n <div className=\"w-full max-w-md bg-white/10 backdrop-blur-xl rounded-2xl p-6 border border-white/20\">\n {/* 进度条 */}\n <div className=\"mb-4\">\n <div className=\"relative h-4 flex items-center\">\n {/* 进度条背景轨道 */}\n <div className=\"absolute w-full h-[6px] bg-white/20 rounded-full\" />\n {/* 已播放进度覆盖层 */}\n <div\n className=\"absolute h-[6px] bg-gradient-to-r from-purple-500 to-pink-500 rounded-full transition-all duration-100 ease-linear pointer-events-none\"\n style={{\n width: `${duration > 0 ? (currentTime / duration) * 100 : (currentTime > 100 ? 100 : currentTime)}%`\n }}\n />\n {/* 进度条滑块 */}\n <input\n type=\"range\"\n min=\"0\"\n max={duration > 0 ? duration : 100 + (currentTime > 100 ? currentTime % 100 : 0)}\n value={currentTime}\n onChange={handleSeek}\n className=\"audio-slider absolute w-full\"\n />\n </div>\n <div className=\"flex justify-between text-xs text-white/60 mt-3\">\n <span>{formatTime(currentTime)}</span>\n <span>{formatTime(duration)}</span>\n </div>\n </div>\n\n {/* 控制按钮 */}\n <div className=\"flex items-center justify-center gap-4 mb-4\">\n <button\n onClick={() => skip(-10)}\n className=\"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-all\"\n >\n <SkipBack className=\"w-5 h-5\" />\n </button>\n\n <button\n onClick={togglePlay}\n className=\"w-14 h-14 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 hover:scale-105 flex items-center justify-center text-white transition-all shadow-lg\"\n >\n {isPlaying ? <Pause className=\"w-6 h-6\" /> : <Play className=\"w-6 h-6 ml-1\" />}\n </button>\n\n <button\n onClick={() => skip(10)}\n className=\"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-all\"\n >\n <SkipForward className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* 音量控制 */}\n <div className=\"flex items-center gap-3\">\n <button\n onClick={toggleMute}\n className=\"text-white/80 hover:text-white transition-colors\"\n >\n {isMuted || volume === 0 ? <VolumeX className=\"w-5 h-5\" /> : <Volume2 className=\"w-5 h-5\" />}\n </button>\n <div className=\"flex-1 relative h-3 flex items-center\">\n {/* 音量条背景轨道 */}\n <div className=\"absolute w-full h-[4px] bg-white/20 rounded-full\" />\n {/* 音量覆盖层 */}\n <div\n className=\"absolute h-[4px] bg-purple-500 rounded-full transition-all duration-100 pointer-events-none\"\n style={{\n width: `${(isMuted ? 0 : volume) * 100}%`\n }}\n />\n {/* 音量滑块 */}\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.01\"\n value={isMuted ? 0 : volume}\n onChange={handleVolumeChange}\n className=\"volume-slider absolute w-full\"\n />\n </div>\n </div>\n </div>\n\n {/* 隐藏的 audio 元素 */}\n <audio\n ref={audioRef}\n src={url}\n onError={handleError}\n className=\"hidden\"\n />\n </div>\n );\n};\n\n","export default {\n \"pre[class*=\\\"language-\\\"]\": {\n \"color\": \"#d4d4d4\",\n \"fontSize\": \"13px\",\n \"textShadow\": \"none\",\n \"fontFamily\": \"Menlo, Monaco, Consolas, \\\"Andale Mono\\\", \\\"Ubuntu Mono\\\", \\\"Courier New\\\", monospace\",\n \"direction\": \"ltr\",\n \"textAlign\": \"left\",\n \"whiteSpace\": \"pre\",\n \"wordSpacing\": \"normal\",\n \"wordBreak\": \"normal\",\n \"lineHeight\": \"1.5\",\n \"MozTabSize\": \"4\",\n \"OTabSize\": \"4\",\n \"tabSize\": \"4\",\n \"WebkitHyphens\": \"none\",\n \"MozHyphens\": \"none\",\n \"msHyphens\": \"none\",\n \"hyphens\": \"none\",\n \"padding\": \"1em\",\n \"margin\": \".5em 0\",\n \"overflow\": \"auto\",\n \"background\": \"#1e1e1e\"\n },\n \"code[class*=\\\"language-\\\"]\": {\n \"color\": \"#d4d4d4\",\n \"fontSize\": \"13px\",\n \"textShadow\": \"none\",\n \"fontFamily\": \"Menlo, Monaco, Consolas, \\\"Andale Mono\\\", \\\"Ubuntu Mono\\\", \\\"Courier New\\\", monospace\",\n \"direction\": \"ltr\",\n \"textAlign\": \"left\",\n \"whiteSpace\": \"pre\",\n \"wordSpacing\": \"normal\",\n \"wordBreak\": \"normal\",\n \"lineHeight\": \"1.5\",\n \"MozTabSize\": \"4\",\n \"OTabSize\": \"4\",\n \"tabSize\": \"4\",\n \"WebkitHyphens\": \"none\",\n \"MozHyphens\": \"none\",\n \"msHyphens\": \"none\",\n \"hyphens\": \"none\"\n },\n \"pre[class*=\\\"language-\\\"]::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"code[class*=\\\"language-\\\"]::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"pre[class*=\\\"language-\\\"] *::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"code[class*=\\\"language-\\\"] *::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \":not(pre) > code[class*=\\\"language-\\\"]\": {\n \"padding\": \".1em .3em\",\n \"borderRadius\": \".3em\",\n \"color\": \"#db4c69\",\n \"background\": \"#1e1e1e\"\n },\n \".namespace\": {\n \"Opacity\": \".7\"\n },\n \"doctype.doctype-tag\": {\n \"color\": \"#569CD6\"\n },\n \"doctype.name\": {\n \"color\": \"#9cdcfe\"\n },\n \"comment\": {\n \"color\": \"#6a9955\"\n },\n \"prolog\": {\n \"color\": \"#6a9955\"\n },\n \"punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-html .language-css .token.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-html .language-javascript .token.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \"property\": {\n \"color\": \"#9cdcfe\"\n },\n \"tag\": {\n \"color\": \"#569cd6\"\n },\n \"boolean\": {\n \"color\": \"#569cd6\"\n },\n \"number\": {\n \"color\": \"#b5cea8\"\n },\n \"constant\": {\n \"color\": \"#9cdcfe\"\n },\n \"symbol\": {\n \"color\": \"#b5cea8\"\n },\n \"inserted\": {\n \"color\": \"#b5cea8\"\n },\n \"unit\": {\n \"color\": \"#b5cea8\"\n },\n \"selector\": {\n \"color\": \"#d7ba7d\"\n },\n \"attr-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"string\": {\n \"color\": \"#ce9178\"\n },\n \"char\": {\n \"color\": \"#ce9178\"\n },\n \"builtin\": {\n \"color\": \"#ce9178\"\n },\n \"deleted\": {\n \"color\": \"#ce9178\"\n },\n \".language-css .token.string.url\": {\n \"textDecoration\": \"underline\"\n },\n \"operator\": {\n \"color\": \"#d4d4d4\"\n },\n \"entity\": {\n \"color\": \"#569cd6\"\n },\n \"operator.arrow\": {\n \"color\": \"#569CD6\"\n },\n \"atrule\": {\n \"color\": \"#ce9178\"\n },\n \"atrule.rule\": {\n \"color\": \"#c586c0\"\n },\n \"atrule.url\": {\n \"color\": \"#9cdcfe\"\n },\n \"atrule.url.function\": {\n \"color\": \"#dcdcaa\"\n },\n \"atrule.url.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \"keyword\": {\n \"color\": \"#569CD6\"\n },\n \"keyword.module\": {\n \"color\": \"#c586c0\"\n },\n \"keyword.control-flow\": {\n \"color\": \"#c586c0\"\n },\n \"function\": {\n \"color\": \"#dcdcaa\"\n },\n \"function.maybe-class-name\": {\n \"color\": \"#dcdcaa\"\n },\n \"regex\": {\n \"color\": \"#d16969\"\n },\n \"important\": {\n \"color\": \"#569cd6\"\n },\n \"italic\": {\n \"fontStyle\": \"italic\"\n },\n \"class-name\": {\n \"color\": \"#4ec9b0\"\n },\n \"maybe-class-name\": {\n \"color\": \"#4ec9b0\"\n },\n \"console\": {\n \"color\": \"#9cdcfe\"\n },\n \"parameter\": {\n \"color\": \"#9cdcfe\"\n },\n \"interpolation\": {\n \"color\": \"#9cdcfe\"\n },\n \"punctuation.interpolation-punctuation\": {\n \"color\": \"#569cd6\"\n },\n \"variable\": {\n \"color\": \"#9cdcfe\"\n },\n \"imports.maybe-class-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"exports.maybe-class-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"escape\": {\n \"color\": \"#d7ba7d\"\n },\n \"tag.punctuation\": {\n \"color\": \"#808080\"\n },\n \"cdata\": {\n \"color\": \"#808080\"\n },\n \"attr-value\": {\n \"color\": \"#ce9178\"\n },\n \"attr-value.punctuation\": {\n \"color\": \"#ce9178\"\n },\n \"attr-value.punctuation.attr-equals\": {\n \"color\": \"#d4d4d4\"\n },\n \"namespace\": {\n \"color\": \"#4ec9b0\"\n },\n \"pre[class*=\\\"language-javascript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-javascript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-jsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-jsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-typescript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-typescript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-tsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-tsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-css\\\"]\": {\n \"color\": \"#ce9178\"\n },\n \"code[class*=\\\"language-css\\\"]\": {\n \"color\": \"#ce9178\"\n },\n \"pre[class*=\\\"language-html\\\"]\": {\n \"color\": \"#d4d4d4\"\n },\n \"code[class*=\\\"language-html\\\"]\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-regex .token.anchor\": {\n \"color\": \"#dcdcaa\"\n },\n \".language-html .token.punctuation\": {\n \"color\": \"#808080\"\n },\n \"pre[class*=\\\"language-\\\"] > code[class*=\\\"language-\\\"]\": {\n \"position\": \"relative\",\n \"zIndex\": \"1\"\n },\n \".line-highlight.line-highlight\": {\n \"background\": \"#f7ebc6\",\n \"boxShadow\": \"inset 5px 0 0 #f7d87c\",\n \"zIndex\": \"0\"\n }\n};","import { useState, useEffect } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';\n\ninterface MarkdownRendererProps {\n url: string;\n}\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url }) => {\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('加载失败');\n }\n const text = await response.text();\n setContent(text);\n } catch (err) {\n setError('Markdown 文件加载失败');\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div className=\"max-w-4xl mx-auto bg-white/5 backdrop-blur-sm rounded-2xl p-8 border border-white/10\">\n <div className=\"prose prose-invert prose-lg max-w-none\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n return !inline && match ? (\n <SyntaxHighlighter\n style={vscDarkPlus}\n language={match[1]}\n PreTag=\"div\"\n className=\"rounded-lg\"\n {...props}\n >\n {String(children).replace(/\\n$/, '')}\n </SyntaxHighlighter>\n ) : (\n <code className=\"bg-white/10 px-1.5 py-0.5 rounded text-sm\" {...props}>\n {children}\n </code>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"text-4xl font-bold mb-4 text-white border-b border-white/20 pb-2\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"text-3xl font-bold mb-3 text-white mt-8\">{children}</h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"text-2xl font-bold mb-2 text-white mt-6\">{children}</h3>\n ),\n p: ({ children }) => <p className=\"text-white/90 mb-4 leading-relaxed\">{children}</p>,\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"text-blue-400 hover:text-blue-300 underline\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => <ul className=\"list-disc list-inside mb-4 text-white/90\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal list-inside mb-4 text-white/90\">{children}</ol>,\n li: ({ children }) => <li className=\"mb-1\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-4 border-blue-500 pl-4 italic text-white/80 my-4\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"overflow-x-auto my-4\">\n <table className=\"min-w-full border border-white/20\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-white/20 px-4 py-2 bg-white/10 text-white font-semibold\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"border border-white/20 px-4 py-2 text-white/90\">{children}</td>\n ),\n hr: () => <hr className=\"border-white/20 my-6\" />,\n img: ({ src, alt }) => (\n <img src={src} alt={alt} className=\"rounded-lg max-w-full h-auto my-4\" />\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport { FileText } from 'lucide-react';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n}\n\nconst getLanguageFromFileName = (fileName: string): string => {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n const languageMap: Record<string, string> = {\n js: 'javascript',\n jsx: 'jsx',\n ts: 'typescript',\n tsx: 'tsx',\n py: 'python',\n java: 'java',\n cpp: 'cpp',\n c: 'c',\n cs: 'csharp',\n php: 'php',\n rb: 'ruby',\n go: 'go',\n rs: 'rust',\n swift: 'swift',\n kt: 'kotlin',\n scala: 'scala',\n sh: 'bash',\n bash: 'bash',\n zsh: 'bash',\n json: 'json',\n xml: 'xml',\n html: 'html',\n css: 'css',\n scss: 'scss',\n sass: 'sass',\n less: 'less',\n sql: 'sql',\n yaml: 'yaml',\n yml: 'yaml',\n toml: 'toml',\n ini: 'ini',\n conf: 'nginx',\n md: 'markdown',\n txt: 'text',\n };\n return languageMap[ext] || 'text';\n};\n\nexport const TextRenderer: React.FC<TextRendererProps> = ({ url, fileName }) => {\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const language = getLanguageFromFileName(fileName);\n\n useEffect(() => {\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('加载失败');\n }\n const text = await response.text();\n setContent(text);\n } catch (err) {\n setError('文本文件加载失败');\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div className=\"max-w-6xl mx-auto bg-white/5 backdrop-blur-sm rounded-2xl border border-white/10 overflow-hidden\">\n {/* 文件头部 */}\n <div className=\"flex items-center gap-3 px-6 py-4 bg-white/5 border-b border-white/10\">\n <FileText className=\"w-5 h-5 text-white/70\" />\n <span className=\"text-white font-medium\">{fileName}</span>\n <span className=\"ml-auto text-xs text-white/50 uppercase\">{language}</span>\n </div>\n\n {/* 代码内容 */}\n <div className=\"text-sm\">\n {language === 'text' ? (\n <pre className=\"p-6 text-white/90 font-mono whitespace-pre-wrap break-words\">\n {content}\n </pre>\n ) : (\n <SyntaxHighlighter\n language={language}\n style={vscDarkPlus}\n showLineNumbers\n customStyle={{\n margin: 0,\n padding: '1.5rem',\n background: 'transparent',\n fontSize: '0.875rem',\n }}\n lineNumberStyle={{\n minWidth: '3em',\n paddingRight: '1em',\n color: 'rgba(255, 255, 255, 0.3)',\n userSelect: 'none',\n }}\n >\n {content}\n </SyntaxHighlighter>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n","import { FileQuestion, Download } from 'lucide-react';\n\ninterface UnsupportedRendererProps {\n fileName: string;\n fileType: string;\n onDownload: () => void;\n}\n\nexport const UnsupportedRenderer: React.FC<UnsupportedRendererProps> = ({\n fileName,\n fileType,\n onDownload,\n}) => {\n return (\n <div className=\"flex flex-col items-center justify-center w-full h-full p-8 gap-6\">\n <div className=\"w-32 h-32 rounded-full bg-white/10 flex items-center justify-center\">\n <FileQuestion className=\"w-16 h-16 text-white/70\" />\n </div>\n\n <div className=\"text-white text-center\">\n <p className=\"text-xl font-medium mb-2\">{fileName}</p>\n <p className=\"text-white/70\">不支持预览此文件类型 ({fileType})</p>\n </div>\n\n <button\n onClick={onDownload}\n className=\"flex items-center gap-2 px-6 py-3 bg-white/10 hover:bg-white/20 backdrop-blur-sm rounded-lg text-white font-medium transition-all\"\n >\n <Download className=\"w-5 h-5\" />\n 下载文件查看\n </button>\n </div>\n );\n};\n\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n X,\n ZoomIn,\n ZoomOut,\n RotateCw,\n RotateCcw,\n Download,\n ChevronLeft,\n ChevronRight,\n Maximize2,\n Minimize2,\n RefreshCw,\n} from 'lucide-react';\nimport { PreviewFile, PreviewFileInput, FileType } from './types';\nimport { normalizeFiles } from './utils/fileNormalizer';\nimport { ImageRenderer } from './renderers/ImageRenderer';\nimport { PdfRenderer } from './renderers/PdfRenderer';\nimport { DocxRenderer } from './renderers/DocxRenderer';\nimport { XlsxRenderer } from './renderers/XlsxRenderer';\nimport { PptxRenderer } from './renderers/PptxRenderer';\nimport { VideoRenderer } from './renderers/VideoRenderer';\nimport { AudioRenderer } from './renderers/AudioRenderer';\nimport { MarkdownRenderer } from './renderers/MarkdownRenderer';\nimport { TextRenderer } from './renderers/TextRenderer';\nimport { UnsupportedRenderer } from './renderers/UnsupportedRenderer';\n\ninterface FilePreviewModalProps {\n files: PreviewFileInput[];\n currentIndex: number;\n isOpen: boolean;\n onClose: () => void;\n onNavigate?: (index: number) => void;\n}\n\nconst getFileType = (file: PreviewFile): FileType => {\n const ext = file.name.split('.').pop()?.toLowerCase() || '';\n const mimeType = file.type.toLowerCase();\n\n if (mimeType.startsWith('image/') || ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(ext)) {\n return 'image';\n }\n if (mimeType.includes('pdf') || ext === 'pdf') {\n return 'pdf';\n }\n if (mimeType.includes('wordprocessingml') || ext === 'docx') {\n return 'docx';\n }\n if (mimeType.includes('spreadsheetml') || ext === 'xlsx') {\n return 'xlsx';\n }\n if (mimeType.includes('presentationml') || ext === 'pptx' || ext === 'ppt') {\n return 'pptx';\n }\n if (mimeType.startsWith('video/') || ['mp4', 'webm', 'ogg', 'ogv', 'mov', 'avi', 'mkv', 'm4v', '3gp', 'flv'].includes(ext)) {\n return 'video';\n }\n if (mimeType.startsWith('audio/') || ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac'].includes(ext)) {\n return 'audio';\n }\n if (ext === 'md' || ext === 'markdown') {\n return 'markdown';\n }\n // 文本文件和代码文件\n const textExtensions = [\n 'txt', 'log', 'csv',\n 'js', 'jsx', 'ts', 'tsx', 'json',\n 'py', 'java', 'cpp', 'c', 'h', 'cs', 'php', 'rb', 'go', 'rs', 'swift', 'kt',\n 'html', 'css', 'scss', 'sass', 'less',\n 'xml', 'yaml', 'yml', 'toml', 'ini', 'conf',\n 'sh', 'bash', 'zsh', 'sql',\n ];\n if (mimeType.startsWith('text/') || textExtensions.includes(ext)) {\n return 'text';\n }\n return 'unsupported';\n};\n\nexport const FilePreviewModal: React.FC<FilePreviewModalProps> = ({\n files,\n currentIndex,\n isOpen,\n onClose,\n onNavigate,\n}) => {\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n const [, setTotalPages] = useState(1); // PDF 总页数,由 PdfRenderer 更新\n\n // 标准化文件输入\n const normalizedFiles = useMemo(() => normalizeFiles(files), [files]);\n\n const currentFile = normalizedFiles[currentIndex];\n const fileType = currentFile ? getFileType(currentFile) : 'unsupported';\n\n // 重置状态当文件改变时\n useEffect(() => {\n setZoom(1);\n setRotation(0);\n setCurrentPage(1);\n setTotalPages(1);\n }, [currentIndex]);\n\n // 键盘导航\n // 锁定 body 滚动\n useEffect(() => {\n if (isOpen) {\n // 保存原始的 overflow 值\n const originalOverflow = document.body.style.overflow;\n const originalPaddingRight = document.body.style.paddingRight;\n\n // 获取滚动条宽度\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n // 锁定滚动并补偿滚动条宽度\n document.body.style.overflow = 'hidden';\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n\n return () => {\n // 恢复原始值\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n };\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n } else if (e.key === 'ArrowLeft' && currentIndex > 0) {\n onNavigate?.(currentIndex - 1);\n } else if (e.key === 'ArrowRight' && currentIndex < normalizedFiles.length - 1) {\n onNavigate?.(currentIndex + 1);\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, currentIndex, normalizedFiles.length, onClose, onNavigate]);\n\n const handleZoomIn = useCallback(() => {\n setZoom((prev) => Math.min(prev + 0.25, 5));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom((prev) => Math.max(prev - 0.25, 0.5));\n }, []);\n\n const handleRotate = useCallback(() => {\n setRotation((prev) => prev + 90);\n }, []);\n\n const handleRotateLeft = useCallback(() => {\n setRotation((prev) => prev - 90);\n }, []);\n\n const handleFitToWidth = useCallback(() => {\n setZoom(1);\n setRotation(0);\n }, []);\n\n const handleOriginalSize = useCallback(() => {\n setZoom(1);\n }, []);\n\n const handleZoomChange = useCallback((newZoom: number) => {\n setZoom(newZoom);\n }, []);\n\n const handleReset = useCallback(() => {\n setZoom(1);\n setRotation(0);\n }, []);\n\n const handleDownload = useCallback(() => {\n if (!currentFile) return;\n const link = document.createElement('a');\n link.href = currentFile.url;\n link.download = currentFile.name;\n link.click();\n }, [currentFile]);\n\n if (!isOpen || !currentFile) return null;\n\n const showZoomControls = fileType === 'image' || fileType === 'pdf';\n const showRotateControl = fileType === 'image';\n\n return (\n <AnimatePresence>\n {isOpen && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-md overflow-hidden\"\n onClick={onClose}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* 主内容区域 */}\n <div\n className=\"relative w-full h-full flex flex-col overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* 顶部工具栏 */}\n <motion.div\n initial={{ y: -100 }}\n animate={{ y: 0 }}\n exit={{ y: -100 }}\n className=\"absolute top-0 left-0 right-0 z-10 p-4\"\n >\n <div className=\"max-w-7xl mx-auto flex items-center justify-between bg-black/40 backdrop-blur-xl rounded-2xl px-6 py-4 shadow-2xl border border-white/10\">\n {/* 文件名 */}\n <div className=\"flex-1 min-w-0\">\n <h2 className=\"text-white font-medium text-lg truncate\">\n {currentFile.name}\n </h2>\n <p className=\"text-white/60 text-sm\">\n {currentIndex + 1} / {normalizedFiles.length}\n </p>\n </div>\n\n {/* 工具按钮 */}\n <div className=\"flex items-center gap-2 ml-4\">\n {showZoomControls && (\n <>\n <ToolbarButton\n icon={<ZoomOut className=\"w-5 h-5\" />}\n label=\"缩小\"\n onClick={handleZoomOut}\n disabled={zoom <= 0.5}\n />\n <span className=\"text-white/70 text-sm min-w-[4rem] text-center font-medium\">\n {Math.round(zoom * 100)}%\n </span>\n <ToolbarButton\n icon={<ZoomIn className=\"w-5 h-5\" />}\n label=\"放大\"\n onClick={handleZoomIn}\n disabled={zoom >= 5}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n <ToolbarButton\n icon={<Minimize2 className=\"w-5 h-5\" />}\n label=\"适应窗口\"\n onClick={handleFitToWidth}\n />\n <ToolbarButton\n icon={<Maximize2 className=\"w-5 h-5\" />}\n label=\"原始尺寸\"\n onClick={handleOriginalSize}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n {showRotateControl && (\n <>\n <ToolbarButton\n icon={<RotateCcw className=\"w-5 h-5\" />}\n label=\"向左旋转\"\n onClick={handleRotateLeft}\n />\n <ToolbarButton\n icon={<RotateCw className=\"w-5 h-5\" />}\n label=\"向右旋转\"\n onClick={handleRotate}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n {(showZoomControls || showRotateControl) && (\n <>\n <ToolbarButton\n icon={<RefreshCw className=\"w-5 h-5\" />}\n label=\"复原\"\n onClick={handleReset}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n <ToolbarButton\n icon={<Download className=\"w-5 h-5\" />}\n label=\"下载\"\n onClick={handleDownload}\n />\n\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n\n <ToolbarButton\n icon={<X className=\"w-5 h-5\" />}\n label=\"关闭\"\n onClick={onClose}\n />\n </div>\n </div>\n </motion.div>\n\n {/* 内容区域 */}\n <div className=\"flex-1 flex items-center justify-center pt-24 pb-8 overflow-auto\">\n {fileType === 'image' && (\n <ImageRenderer\n url={currentFile.url}\n zoom={zoom}\n rotation={rotation}\n onZoomChange={handleZoomChange}\n />\n )}\n {fileType === 'pdf' && (\n <PdfRenderer\n url={currentFile.url}\n zoom={zoom}\n currentPage={currentPage}\n onPageChange={setCurrentPage}\n onTotalPagesChange={setTotalPages}\n />\n )}\n {fileType === 'docx' && <DocxRenderer url={currentFile.url} />}\n {fileType === 'xlsx' && <XlsxRenderer url={currentFile.url} />}\n {fileType === 'pptx' && <PptxRenderer url={currentFile.url} />}\n {fileType === 'video' && <VideoRenderer url={currentFile.url} />}\n {fileType === 'audio' && (\n <AudioRenderer url={currentFile.url} fileName={currentFile.name} />\n )}\n {fileType === 'markdown' && <MarkdownRenderer url={currentFile.url} />}\n {fileType === 'text' && (\n <TextRenderer url={currentFile.url} fileName={currentFile.name} />\n )}\n {fileType === 'unsupported' && (\n <UnsupportedRenderer\n fileName={currentFile.name}\n fileType={currentFile.type}\n onDownload={handleDownload}\n />\n )}\n </div>\n\n {/* 左右导航箭头 */}\n {normalizedFiles.length > 1 && (\n <>\n {currentIndex > 0 && (\n <motion.button\n initial={{ x: -100, opacity: 0 }}\n animate={{ x: 0, opacity: 1 }}\n exit={{ x: -100, opacity: 0 }}\n onClick={() => onNavigate?.(currentIndex - 1)}\n className=\"absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/40 backdrop-blur-xl border border-white/10 flex items-center justify-center text-white hover:bg-black/60 transition-all shadow-2xl\"\n >\n <ChevronLeft className=\"w-6 h-6\" />\n </motion.button>\n )}\n\n {currentIndex < normalizedFiles.length - 1 && (\n <motion.button\n initial={{ x: 100, opacity: 0 }}\n animate={{ x: 0, opacity: 1 }}\n exit={{ x: 100, opacity: 0 }}\n onClick={() => onNavigate?.(currentIndex + 1)}\n className=\"absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/40 backdrop-blur-xl border border-white/10 flex items-center justify-center text-white hover:bg-black/60 transition-all shadow-2xl\"\n >\n <ChevronRight className=\"w-6 h-6\" />\n </motion.button>\n )}\n </>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n};\n\n// 工具栏按钮组件\ninterface ToolbarButtonProps {\n icon: React.ReactNode;\n label: string;\n onClick: () => void;\n disabled?: boolean;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({ icon, label, onClick, disabled }) => {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n title={label}\n className={`p-2 rounded-lg transition-all ${disabled\n ? 'text-white/30 cursor-not-allowed'\n : 'text-white hover:bg-white/10 active:bg-white/20'\n }`}\n >\n {icon}\n </button>\n );\n};\n\n"],"names":["getFileNameFromUrl","url","fileName","inferMimeType","ext","_a","normalizeFile","input","index","normalizeFiles","inputs","ImageRenderer","zoom","rotation","onZoomChange","loaded","setLoaded","useState","error","setError","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","containerRef","useRef","useEffect","handleLoad","handleError","handleDoubleClick","handleWheel","useCallback","e","delta","prev","newZoom","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","motion","pdfjsVersion","pdfjs","workerSrc","originalWorkerSrc","cdnWorkerSrc","event","PdfRenderer","currentPage","onPageChange","onTotalPagesChange","numPages","setNumPages","pageRefs","onDocumentLoadSuccess","onDocumentLoadError","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","pageElement","pageNumber","rect","containerRect","pageCenter","distance","setPageRef","element","Document","_","el","Page","DocxRenderer","html","setHtml","loading","setLoading","response","arrayBuffer","result","mammoth","err","XlsxRenderer","sheets","setSheets","activeSheet","setActiveSheet","workbook","XLSX","parsedSheets","name","worksheet","data","currentSheet","sheet","row","rowIndex","cell","cellIndex","PptxRenderer","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","isInitialRender","updateDimensions","initialDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadPptx","previewErr","timer","Presentation","getVideoType","VideoRenderer","isLoading","setIsLoading","videoRef","playerRef","videoElement","videoType","player","videojs","AudioRenderer","isPlaying","setIsPlaying","currentTime","setCurrentTime","duration","setDuration","volume","setVolume","isMuted","setIsMuted","audioRef","audio","updateTime","updateDuration","handleEnded","handleCanPlay","togglePlay","handleSeek","time","handleVolumeChange","vol","toggleMute","skip","seconds","formatTime","minutes","Music","SkipBack","Pause","Play","SkipForward","VolumeX","Volume2","vscDarkPlus","MarkdownRenderer","content","setContent","text","ReactMarkdown","remarkGfm","node","inline","className","children","props","match","SyntaxHighlighter","href","src","alt","getLanguageFromFileName","TextRenderer","language","FileText","UnsupportedRenderer","fileType","onDownload","FileQuestion","Download","getFileType","file","mimeType","textExtensions","FilePreviewModal","files","currentIndex","isOpen","onClose","onNavigate","setZoom","setRotation","setCurrentPage","setTotalPages","normalizedFiles","useMemo","currentFile","originalOverflow","originalPaddingRight","scrollbarWidth","handleKeyDown","handleZoomIn","handleZoomOut","handleRotate","handleRotateLeft","handleFitToWidth","handleOriginalSize","handleZoomChange","handleReset","handleDownload","link","showZoomControls","showRotateControl","AnimatePresence","Fragment","ToolbarButton","ZoomOut","ZoomIn","Minimize2","Maximize2","RotateCcw","RotateCw","RefreshCw","X","ChevronLeft","ChevronRight","icon","label","onClick","disabled"],"mappings":"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A,CACC,IAAK6G,EACL,IAAKxJ,EACL,QAAS+B,EACT,UAAU,QAAA,CAAA,CACZ,EACF,CAEJ,EClOAgJ,EAAe,CACb,0BAA6B,CAC3B,MAAS,UACT,SAAY,OACZ,WAAc,OACd,WAAc,kFACd,UAAa,MACb,UAAa,OACb,WAAc,MACd,YAAe,SACf,UAAa,SACb,WAAc,MACd,WAAc,IACd,SAAY,IACZ,QAAW,IACX,cAAiB,OACjB,WAAc,OACd,UAAa,OACb,QAAW,OACX,QAAW,MACX,OAAU,SACV,SAAY,OACZ,WAAc,SAClB,EACE,2BAA8B,CAC5B,MAAS,UACT,SAAY,OACZ,WAAc,OACd,WAAc,kFACd,UAAa,MACb,UAAa,OACb,WAAc,MACd,YAAe,SACf,UAAa,SACb,WAAc,MACd,WAAc,IACd,SAAY,IACZ,QAAW,IACX,cAAiB,OACjB,WAAc,OACd,UAAa,OACb,QAAW,MACf,EACE,qCAAwC,CACtC,WAAc,OACd,WAAc,SAClB,EACE,sCAAyC,CACvC,WAAc,OACd,WAAc,SAClB,EACE,uCAA0C,CACxC,WAAc,OACd,WAAc,SAClB,EACE,wCAA2C,CACzC,WAAc,OACd,WAAc,SAClB,EACE,uCAA0C,CACxC,QAAW,YACX,aAAgB,OAChB,MAAS,UACT,WAAc,SAClB,EACE,aAAc,CACZ,QAAW,IACf,EACE,sBAAuB,CACrB,MAAS,SACb,EACE,eAAgB,CACd,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,YAAe,CACb,MAAS,SACb,EACE,kDAAmD,CACjD,MAAS,SACb,EACE,yDAA0D,CACxD,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,IAAO,CACL,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,KAAQ,CACN,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,YAAa,CACX,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,KAAQ,CACN,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,kCAAmC,CACjC,eAAkB,WACtB,EACE,SAAY,CACV,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,iBAAkB,CAChB,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,cAAe,CACb,MAAS,SACb,EACE,aAAc,CACZ,MAAS,SACb,EACE,sBAAuB,CACrB,MAAS,SACb,EACE,yBAA0B,CACxB,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,iBAAkB,CAChB,MAAS,SACb,EACE,uBAAwB,CACtB,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,4BAA6B,CAC3B,MAAS,SACb,EACE,MAAS,CACP,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,OAAU,CACR,UAAa,QACjB,EACE,aAAc,CACZ,MAAS,SACb,EACE,mBAAoB,CAClB,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,cAAiB,CACf,MAAS,SACb,EACE,wCAAyC,CACvC,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,2BAA4B,CAC1B,MAAS,SACb,EACE,2BAA4B,CAC1B,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,kBAAmB,CACjB,MAAS,SACb,EACE,MAAS,CACP,MAAS,SACb,EACE,aAAc,CACZ,MAAS,SACb,EACE,yBAA0B,CACxB,MAAS,SACb,EACE,qCAAsC,CACpC,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,oCAAuC,CACrC,MAAS,SACb,EACE,qCAAwC,CACtC,MAAS,SACb,EACE,6BAAgC,CAC9B,MAAS,SACb,EACE,8BAAiC,CAC/B,MAAS,SACb,EACE,oCAAuC,CACrC,MAAS,SACb,EACE,qCAAwC,CACtC,MAAS,SACb,EACE,6BAAgC,CAC9B,MAAS,SACb,EACE,8BAAiC,CAC/B,MAAS,SACb,EACE,6BAAgC,CAC9B,M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","x_google_ignoreList":[9]}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/fileNormalizer.ts","../src/renderers/ImageRenderer.tsx","../src/utils/pdfConfig.ts","../src/renderers/PdfRenderer.tsx","../src/renderers/DocxRenderer.tsx","../src/renderers/XlsxRenderer.tsx","../src/renderers/PptxRenderer.tsx","../src/renderers/VideoRenderer.tsx","../src/renderers/AudioRenderer.tsx","../../../node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@18.3.1/node_modules/react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js","../src/renderers/MarkdownRenderer.tsx","../src/renderers/TextRenderer.tsx","../src/renderers/UnsupportedRenderer.tsx","../src/FilePreviewModal.tsx"],"sourcesContent":["import { PreviewFile, PreviewFileInput } from '../types';\n\n/**\n * 从 URL 字符串中提取文件名\n */\nfunction getFileNameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const fileName = pathname.split('/').pop() || 'file';\n return decodeURIComponent(fileName);\n } catch {\n // 如果不是有效的 URL,尝试从路径中提取\n const fileName = url.split('/').pop() || 'file';\n return decodeURIComponent(fileName);\n }\n}\n\n/**\n * 从文件名中推断 MIME 类型\n */\nfunction inferMimeType(fileName: string): string {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n \n const mimeTypes: Record<string, string> = {\n // 图片\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n \n // 视频\n mp4: 'video/mp4',\n webm: 'video/webm',\n ogg: 'video/ogg',\n ogv: 'video/ogg',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n m4v: 'video/x-m4v',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n \n // 音频\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n m4a: 'audio/mp4',\n aac: 'audio/aac',\n flac: 'audio/flac',\n \n // 文档\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n ppt: 'application/vnd.ms-powerpoint',\n \n // 文本\n txt: 'text/plain',\n md: 'text/markdown',\n markdown: 'text/markdown',\n json: 'application/json',\n xml: 'application/xml',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n jsx: 'text/javascript',\n tsx: 'text/typescript',\n py: 'text/x-python',\n java: 'text/x-java',\n cpp: 'text/x-c++src',\n c: 'text/x-csrc',\n cs: 'text/x-csharp',\n php: 'text/x-php',\n rb: 'text/x-ruby',\n go: 'text/x-go',\n rs: 'text/x-rust',\n yaml: 'text/yaml',\n yml: 'text/yaml',\n };\n \n return mimeTypes[ext] || 'application/octet-stream';\n}\n\n/**\n * 标准化文件输入为 PreviewFile 格式\n * 支持三种输入类型:\n * 1. File 对象(原生浏览器 File)\n * 2. PreviewFileLink 对象(包含 name, url, type 等属性)\n * 3. string(HTTP URL)\n */\nexport function normalizeFile(input: PreviewFileInput, index: number = 0): PreviewFile {\n // 情况 1: 原生 File 对象\n if (input instanceof File) {\n return {\n id: `file-${Date.now()}-${index}`,\n name: input.name,\n url: URL.createObjectURL(input),\n type: input.type || inferMimeType(input.name),\n size: input.size,\n };\n }\n \n // 情况 2: 字符串 URL\n if (typeof input === 'string') {\n const fileName = getFileNameFromUrl(input);\n return {\n id: `url-${Date.now()}-${index}`,\n name: fileName,\n url: input,\n type: inferMimeType(fileName),\n };\n }\n \n // 情况 3: PreviewFileLink 对象\n return {\n id: input.id || `link-${Date.now()}-${index}`,\n name: input.name,\n url: input.url,\n type: input.type || inferMimeType(input.name),\n size: input.size,\n };\n}\n\n/**\n * 批量标准化文件输入\n */\nexport function normalizeFiles(inputs: PreviewFileInput[]): PreviewFile[] {\n return inputs.map((input, index) => normalizeFile(input, index));\n}\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n onZoomChange?: (zoom: number) => void;\n}\n\nexport const ImageRenderer: React.FC<ImageRendererProps> = ({\n url,\n zoom,\n rotation,\n onZoomChange\n}) => {\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [internalZoom, setInternalZoom] = useState(1); // 内部缩放状态\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLoaded(false);\n setError(null);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n }, [url]);\n\n // 当外部 zoom 改变时,同步内部 zoom\n useEffect(() => {\n setInternalZoom(zoom);\n }, [zoom]);\n\n // 重置位置当缩放或旋转改变时\n useEffect(() => {\n setPosition({ x: 0, y: 0 });\n }, [zoom, rotation]);\n\n const handleLoad = () => {\n setLoaded(true);\n };\n\n const handleError = () => {\n setError('图片加载失败');\n setLoaded(true);\n };\n\n const handleDoubleClick = () => {\n // 双击重置位置\n setPosition({ x: 0, y: 0 });\n };\n\n // 鼠标滚轮缩放\n const handleWheel = useCallback((e: React.WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\n setInternalZoom(prev => {\n const newZoom = Math.max(0.5, Math.min(5, prev + delta)); // 限制缩放范围 0.5-5\n // 同步缩放比例到父组件\n if (onZoomChange) {\n onZoomChange(newZoom);\n }\n return newZoom;\n });\n }, [onZoomChange]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return; // 只响应左键\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n }, [isDragging, dragStart]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"flex items-center justify-center w-full h-full overflow-hidden\"\n onWheel={handleWheel}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {!loaded && !error && (\n <div className=\"flex items-center justify-center\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n )}\n\n {error && (\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n )}\n\n <motion.img\n src={url}\n alt=\"Preview\"\n className={`max-w-none select-none ${!loaded ? 'hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${internalZoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n </div>\n );\n};\n\n","import { pdfjs } from 'react-pdf';\n\n/**\n * PDF.js Worker 配置\n *\n * 配置策略:\n * 1. 优先尝试使用本地 public 目录中的 worker 文件\n * 2. 如果本地文件不存在,降级使用 CDN\n * 3. 使用 HTTPS CDN 确保安全性\n */\n\nconst pdfjsVersion = pdfjs.version;\n\n// 配置 worker 路径\n// 优先使用本地 worker,如果不存在则使用 CDN\nconst workerSrc = `/pdf.worker.min.mjs`;\n\n// 尝试使用本地 worker\npdfjs.GlobalWorkerOptions.workerSrc = workerSrc;\n\n// 添加错误处理,如果本地 worker 加载失败,自动降级到 CDN\nconst originalWorkerSrc = pdfjs.GlobalWorkerOptions.workerSrc;\nconst cdnWorkerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`;\n\n// 监听 worker 加载错误\nif (typeof window !== 'undefined') {\n window.addEventListener('error', (event) => {\n if (event.message?.includes('pdf.worker') && pdfjs.GlobalWorkerOptions.workerSrc === originalWorkerSrc) {\n console.warn('本地 PDF worker 加载失败,切换到 CDN:', cdnWorkerSrc);\n pdfjs.GlobalWorkerOptions.workerSrc = cdnWorkerSrc;\n }\n });\n}\n\nexport { pdfjs };\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Document, Page } from 'react-pdf';\nimport 'react-pdf/dist/esm/Page/AnnotationLayer.css';\nimport 'react-pdf/dist/esm/Page/TextLayer.css';\n\n// 导入 PDF.js 配置\nimport '../utils/pdfConfig';\n\ninterface PdfRendererProps {\n url: string;\n zoom: number;\n currentPage: number;\n onPageChange: (page: number) => void;\n onTotalPagesChange: (total: number) => void;\n}\n\nexport const PdfRenderer: React.FC<PdfRendererProps> = ({\n url,\n zoom,\n currentPage,\n onPageChange,\n onTotalPagesChange,\n}) => {\n const [numPages, setNumPages] = useState<number>(0);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n useEffect(() => {\n setError(null);\n }, [url]);\n\n const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {\n setNumPages(numPages);\n onTotalPagesChange(numPages);\n onPageChange(1);\n };\n\n const onDocumentLoadError = (error: Error) => {\n console.error('PDF 加载错误:', error);\n setError('PDF 文件加载失败');\n };\n\n // 滚动时更新当前页码\n const handleScroll = useCallback(() => {\n if (!containerRef.current) return;\n\n const container = containerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n // 找到当前可见的页面\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageRefs.current.forEach((pageElement, pageNumber) => {\n const rect = pageElement.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n onPageChange(currentVisiblePage);\n }\n }, [currentPage, onPageChange]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 设置页面引用\n const setPageRef = useCallback((pageNumber: number, element: HTMLDivElement | null) => {\n if (element) {\n pageRefs.current.set(pageNumber, element);\n } else {\n pageRefs.current.delete(pageNumber);\n }\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col items-center w-full h-full overflow-auto py-8 px-4\"\n >\n {error && (\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n )}\n\n {!error && (\n <Document\n file={url}\n onLoadSuccess={onDocumentLoadSuccess}\n onLoadError={onDocumentLoadError}\n loading={\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n }\n >\n <div className=\"flex flex-col gap-4\">\n {Array.from(new Array(numPages), (_, index) => {\n const pageNumber = index + 1;\n return (\n <div\n key={`page_${pageNumber}`}\n ref={(el) => setPageRef(pageNumber, el)}\n className=\"relative\"\n >\n <Page\n pageNumber={pageNumber}\n scale={zoom}\n loading={\n <div className=\"flex items-center justify-center p-8 bg-white/5 rounded-lg min-h-[600px]\">\n <div className=\"w-8 h-8 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n }\n renderTextLayer={true}\n renderAnnotationLayer={true}\n className=\"shadow-2xl\"\n />\n {/* 页码标签 */}\n <div className=\"absolute top-2 right-2 bg-black/60 backdrop-blur-sm text-white text-xs px-3 py-1 rounded-full\">\n {pageNumber}\n </div>\n </div>\n );\n })}\n </div>\n </Document>\n )}\n\n {/* 底部页码指示器 */}\n {numPages > 0 && (\n <div className=\"sticky bottom-4 mt-8 bg-black/60 backdrop-blur-xl text-white px-6 py-3 rounded-full text-sm font-medium shadow-2xl border border-white/10\">\n 第 {currentPage} 页 / 共 {numPages} 页\n </div>\n )}\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport mammoth from 'mammoth';\n\ninterface DocxRendererProps {\n url: string;\n}\n\nexport const DocxRenderer: React.FC<DocxRendererProps> = ({ url }) => {\n const [html, setHtml] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadDocx = async () => {\n setLoading(true);\n setError(null);\n setHtml('');\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer });\n setHtml(result.value);\n } catch (err) {\n console.error('Docx 解析错误:', err);\n setError('Word 文档解析失败');\n } finally {\n setLoading(false);\n }\n };\n\n loadDocx();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div\n className=\"max-w-4xl mx-auto bg-white rounded-lg shadow-2xl p-12\"\n dangerouslySetInnerHTML={{ __html: html }}\n style={{\n fontFamily: 'system-ui, -apple-system, sans-serif',\n lineHeight: '1.6',\n color: '#333',\n }}\n />\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport * as XLSX from 'xlsx';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const [sheets, setSheets] = useState<{ name: string; data: unknown[] }[]>([]);\n const [activeSheet, setActiveSheet] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadXlsx = async () => {\n setLoading(true);\n setError(null);\n setSheets([]);\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const workbook = XLSX.read(arrayBuffer, { type: 'array' });\n\n const parsedSheets = workbook.SheetNames.map((name) => {\n const worksheet = workbook.Sheets[name];\n const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });\n return { name, data };\n });\n\n setSheets(parsedSheets);\n setActiveSheet(0);\n } catch (err) {\n console.error('Excel 解析错误:', err);\n setError('Excel 文件解析失败');\n } finally {\n setLoading(false);\n }\n };\n\n loadXlsx();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n const currentSheet = sheets[activeSheet];\n\n return (\n <div className=\"w-full h-full flex flex-col overflow-hidden\">\n {/* Sheet Tabs */}\n {sheets.length > 1 && (\n <div className=\"flex gap-2 p-4 bg-black/20 backdrop-blur-sm overflow-x-auto border-b border-white/10\">\n {sheets.map((sheet, index) => (\n <button\n key={index}\n onClick={() => setActiveSheet(index)}\n className={`px-4 py-2 rounded-lg text-sm font-medium transition-all ${activeSheet === index\n ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-lg'\n : 'bg-white/10 text-white hover:bg-white/20'\n }`}\n >\n {sheet.name}\n </button>\n ))}\n </div>\n )}\n\n {/* Table */}\n <div className=\"flex-1 overflow-auto p-8\">\n <div className=\"inline-block min-w-full bg-gradient-to-br from-gray-800/90 to-gray-900/90 backdrop-blur-xl rounded-2xl shadow-2xl overflow-hidden border border-white/10\">\n <table className=\"min-w-full divide-y divide-white/10\">\n <tbody className=\"divide-y divide-white/10\">\n {currentSheet?.data.map((row, rowIndex) => (\n <tr\n key={rowIndex}\n className={`transition-colors ${rowIndex === 0\n ? 'bg-gradient-to-r from-purple-500/20 to-pink-500/20 font-semibold'\n : 'hover:bg-white/5'\n }`}\n >\n {(row as unknown[]).map((cell, cellIndex) => (\n <td\n key={cellIndex}\n className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-200 border-r border-white/10\"\n >\n {String(cell ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n );\n};\n\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Presentation } from 'lucide-react';\nimport { init } from 'pptx-preview';\n\ninterface PptxRendererProps {\n url: string;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url }) => {\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n\n const containerWidth = containerRef.current.clientWidth;\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n\n console.log('计算尺寸:', { width: containerWidth, height });\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current) return;\n\n console.log('重新初始化预览器...');\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch (e) {\n console.error('销毁预览器失败:', e);\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n console.log('重新初始化使用尺寸:', currentDimensions);\n\n // 初始化新的预览器\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: currentDimensions.height,\n });\n\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n console.log('重新初始化成功');\n } catch (e) {\n console.error('重新初始化失败:', e);\n }\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n const initialDimensions = calculateDimensions();\n lastDimensionsRef.current = initialDimensions;\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n console.log('尺寸变化太小,忽略');\n return; // 尺寸变化太小,不做任何操作\n }\n\n console.log('检测到尺寸变化:', {\n old: lastDimensions,\n new: newDimensions,\n diff: { width: widthDiff, height: heightDiff }\n });\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n console.log('尺寸变化,准备重新初始化');\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n let isMounted = true;\n\n const loadPptx = async () => {\n if (!containerRef.current) {\n console.log('Container ref not ready');\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n console.log('开始加载 PPTX:', url);\n\n // 获取文件\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n arrayBufferRef.current = arrayBuffer; // 保存到 ref\n console.log('文件加载成功,大小:', arrayBuffer.byteLength);\n\n if (!isMounted) return;\n\n // 清空容器\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n console.log('使用尺寸:', currentDimensions);\n\n // 初始化 pptx 预览器\n console.log('初始化预览器...');\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: currentDimensions.height,\n });\n\n previewerRef.current = previewer;\n\n // 预览 PPTX\n console.log('开始预览...');\n previewer.preview(arrayBuffer)\n .then(() => {\n console.log('预览成功');\n if (isMounted) {\n setLoading(false);\n }\n })\n .catch((previewErr) => {\n console.error('预览失败:', previewErr);\n if (isMounted) {\n setError('PPT 文件预览失败');\n setLoading(false);\n }\n });\n } catch (err) {\n console.error('PPTX 解析错误:', err);\n if (isMounted) {\n setError(err instanceof Error ? err.message : 'PPT 文件解析失败');\n setLoading(false);\n }\n }\n };\n\n // 延迟执行以确保 DOM 已准备好\n const timer = setTimeout(() => {\n loadPptx();\n }, 100);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n arrayBufferRef.current = null;\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch (e) {\n console.error('销毁预览器失败:', e);\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions]);\n\n return (\n <div className=\"relative flex flex-col items-center w-full h-full pt-[8px]\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm z-10 rounded-2xl\">\n <div className=\"text-center\">\n <div className=\"w-12 h-12 mx-auto mb-3 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n <p className=\"text-sm text-white/70 font-medium\">加载 PPT 中...</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm z-10 rounded-2xl\">\n <div className=\"text-center max-w-md\">\n <div className=\"w-32 h-32 mx-auto mb-6 rounded-3xl bg-gradient-to-br from-orange-500 via-red-500 to-pink-500 flex items-center justify-center shadow-2xl\">\n <Presentation className=\"w-16 h-16 text-white\" />\n </div>\n <p className=\"text-xl text-white/90 mb-3 font-medium\">PPT 预览</p>\n <p className=\"text-sm text-white/60 mb-6\">\n {error || '浏览器暂不支持直接预览 PPT 文件'}\n </p>\n <a\n href={url}\n download\n className=\"inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-xl hover:scale-105 transition-all shadow-lg\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n 下载文件\n </a>\n <p className=\"text-xs text-white/40 mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n )}\n\n {/* PPT 容器 - 始终渲染 */}\n <div\n ref={containerRef}\n className=\"pptx-wrapper w-full max-w-6xl\"\n />\n </div>\n );\n};\n\n","import { useRef, useEffect, useState } from 'react';\nimport videojs from 'video.js';\nimport 'video.js/dist/video-js.css';\n\ntype VideoJsPlayer = ReturnType<typeof videojs>;\n\ninterface VideoRendererProps {\n url: string;\n}\n\n// 根据 URL 获取视频 MIME 类型\nconst getVideoType = (url: string): string => {\n const ext = url.split('.').pop()?.toLowerCase().split('?')[0] || '';\n const typeMap: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n ogg: 'video/ogg',\n ogv: 'video/ogg',\n mov: 'video/quicktime', // MOV 使用 QuickTime MIME 类型\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n m4v: 'video/mp4',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n };\n return typeMap[ext] || 'video/mp4';\n};\n\nexport const VideoRenderer: React.FC<VideoRendererProps> = ({ url }) => {\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const videoRef = useRef<HTMLDivElement>(null);\n const playerRef = useRef<VideoJsPlayer | null>(null);\n\n useEffect(() => {\n // 确保 Video.js 播放器只初始化一次\n if (!playerRef.current && videoRef.current) {\n const videoElement = document.createElement('video-js');\n videoElement.classList.add('vjs-big-play-centered', 'vjs-theme-apple');\n videoRef.current.appendChild(videoElement);\n\n const videoType = getVideoType(url);\n\n // 为 MOV 格式提供多个 MIME 类型作为备用\n const sources = videoType === 'video/quicktime'\n ? [\n { src: url, type: 'video/quicktime' },\n { src: url, type: 'video/mp4' } // 备用方案\n ]\n : [{ src: url, type: videoType }];\n\n const player = videojs(videoElement, {\n controls: true,\n responsive: true,\n fluid: true,\n preload: 'auto',\n controlBar: {\n children: [\n 'playToggle',\n 'volumePanel',\n 'currentTimeDisplay',\n 'timeDivider',\n 'durationDisplay',\n 'progressControl',\n 'remainingTimeDisplay',\n 'fullscreenToggle'\n ],\n volumePanel: {\n inline: false\n }\n },\n html5: {\n vhs: {\n overrideNative: true\n },\n nativeVideoTracks: false,\n nativeAudioTracks: false,\n nativeTextTracks: false\n },\n sources\n });\n\n // 监听加载完成\n player.on('loadeddata', () => {\n setIsLoading(false);\n });\n\n player.on('error', () => {\n const error = player.error();\n console.error('Video.js error:', error);\n setError(`视频加载失败: ${error?.message || '未知错误'}`);\n setIsLoading(false);\n });\n\n playerRef.current = player;\n }\n }, [url]);\n\n // 清理函数\n useEffect(() => {\n const player = playerRef.current;\n\n return () => {\n if (player && !player.isDisposed()) {\n player.dispose();\n playerRef.current = null;\n }\n };\n }, []);\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-center\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-red-500/10 flex items-center justify-center\">\n <svg className=\"w-8 h-8 text-red-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n </div>\n <p className=\"text-lg font-medium text-white/90 mb-2\">视频加载失败</p>\n <p className=\"text-sm text-white/60\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center w-full h-full p-8\">\n <div className=\"w-full max-w-5xl relative\">\n {/* 加载状态 */}\n {isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/20 backdrop-blur-sm rounded-2xl z-10\">\n <div className=\"text-center\">\n <div className=\"w-12 h-12 mx-auto mb-3 border-3 border-white/20 border-t-white rounded-full animate-spin\" />\n <p className=\"text-sm text-white/70 font-medium\">加载视频中...</p>\n </div>\n </div>\n )}\n\n {/* 视频播放器容器 */}\n <div\n ref={videoRef}\n className=\"overflow-hidden\"\n style={{\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05)'\n }}\n />\n </div>\n </div>\n );\n};\n\n","import { useState, useRef, useEffect } from 'react';\nimport { Music, Play, Pause, Volume2, VolumeX, SkipBack, SkipForward } from 'lucide-react';\n\ninterface AudioRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const AudioRenderer: React.FC<AudioRendererProps> = ({ url, fileName }) => {\n const [error, setError] = useState<string | null>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [volume, setVolume] = useState(1);\n const [isMuted, setIsMuted] = useState(false);\n const audioRef = useRef<HTMLAudioElement>(null);\n\n useEffect(() => {\n const audio = audioRef.current;\n if (!audio) return;\n\n const updateTime = () => {\n if (!isNaN(audio.currentTime)) {\n setCurrentTime(audio.currentTime);\n }\n };\n\n const updateDuration = () => {\n if (!isNaN(audio.duration) && isFinite(audio.duration)) {\n setDuration(audio.duration);\n }\n };\n\n const handleEnded = () => setIsPlaying(false);\n const handleCanPlay = () => updateDuration();\n\n audio.addEventListener('timeupdate', updateTime);\n audio.addEventListener('loadedmetadata', updateDuration);\n audio.addEventListener('durationchange', updateDuration);\n audio.addEventListener('canplay', handleCanPlay);\n audio.addEventListener('ended', handleEnded);\n\n // 立即尝试获取时长\n if (audio.readyState >= 1) {\n updateDuration();\n }\n\n return () => {\n audio.removeEventListener('timeupdate', updateTime);\n audio.removeEventListener('loadedmetadata', updateDuration);\n audio.removeEventListener('durationchange', updateDuration);\n audio.removeEventListener('canplay', handleCanPlay);\n audio.removeEventListener('ended', handleEnded);\n };\n }, []);\n\n const togglePlay = () => {\n if (audioRef.current) {\n if (isPlaying) {\n audioRef.current.pause();\n } else {\n audioRef.current.play();\n }\n setIsPlaying(!isPlaying);\n }\n };\n\n const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {\n const time = parseFloat(e.target.value);\n setCurrentTime(time);\n if (audioRef.current) {\n audioRef.current.currentTime = time;\n }\n };\n\n const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const vol = parseFloat(e.target.value);\n setVolume(vol);\n if (audioRef.current) {\n audioRef.current.volume = vol;\n }\n if (vol > 0) setIsMuted(false);\n };\n\n const toggleMute = () => {\n if (audioRef.current) {\n audioRef.current.muted = !isMuted;\n setIsMuted(!isMuted);\n }\n };\n\n const skip = (seconds: number) => {\n if (audioRef.current) {\n audioRef.current.currentTime += seconds;\n }\n };\n\n const formatTime = (time: number) => {\n if (!isFinite(time) || isNaN(time) || time < 0) return '0:00';\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n };\n\n const handleError = () => {\n setError('音频加载失败');\n };\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col items-center justify-center w-full h-full p-8 gap-8\">\n {/* 音频封面 */}\n <div className=\"w-64 h-64 rounded-3xl bg-gradient-to-br from-purple-500 via-pink-500 to-rose-500 flex items-center justify-center shadow-2xl backdrop-blur-xl\">\n <Music className=\"w-32 h-32 text-white\" />\n </div>\n\n {/* 文件名 */}\n <div className=\"text-white text-center max-w-md\">\n <p className=\"text-2xl font-medium mb-1\">{fileName}</p>\n <p className=\"text-sm text-white/60\">音频文件</p>\n </div>\n\n {/* 播放控制器 */}\n <div className=\"w-full max-w-md bg-white/10 backdrop-blur-xl rounded-2xl p-6 border border-white/20\">\n {/* 进度条 */}\n <div className=\"mb-4\">\n <div className=\"relative h-4 flex items-center\">\n {/* 进度条背景轨道 */}\n <div className=\"absolute w-full h-[6px] bg-white/20 rounded-full\" />\n {/* 已播放进度覆盖层 */}\n <div\n className=\"absolute h-[6px] bg-gradient-to-r from-purple-500 to-pink-500 rounded-full transition-all duration-100 ease-linear pointer-events-none\"\n style={{\n width: `${duration > 0 ? (currentTime / duration) * 100 : (currentTime > 100 ? 100 : currentTime)}%`\n }}\n />\n {/* 进度条滑块 */}\n <input\n type=\"range\"\n min=\"0\"\n max={duration > 0 ? duration : 100 + (currentTime > 100 ? currentTime % 100 : 0)}\n value={currentTime}\n onChange={handleSeek}\n className=\"audio-slider absolute w-full\"\n />\n </div>\n <div className=\"flex justify-between text-xs text-white/60 mt-3\">\n <span>{formatTime(currentTime)}</span>\n <span>{formatTime(duration)}</span>\n </div>\n </div>\n\n {/* 控制按钮 */}\n <div className=\"flex items-center justify-center gap-4 mb-4\">\n <button\n onClick={() => skip(-10)}\n className=\"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-all\"\n >\n <SkipBack className=\"w-5 h-5\" />\n </button>\n\n <button\n onClick={togglePlay}\n className=\"w-14 h-14 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 hover:scale-105 flex items-center justify-center text-white transition-all shadow-lg\"\n >\n {isPlaying ? <Pause className=\"w-6 h-6\" /> : <Play className=\"w-6 h-6 ml-1\" />}\n </button>\n\n <button\n onClick={() => skip(10)}\n className=\"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-all\"\n >\n <SkipForward className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* 音量控制 */}\n <div className=\"flex items-center gap-3\">\n <button\n onClick={toggleMute}\n className=\"text-white/80 hover:text-white transition-colors\"\n >\n {isMuted || volume === 0 ? <VolumeX className=\"w-5 h-5\" /> : <Volume2 className=\"w-5 h-5\" />}\n </button>\n <div className=\"flex-1 relative h-3 flex items-center\">\n {/* 音量条背景轨道 */}\n <div className=\"absolute w-full h-[4px] bg-white/20 rounded-full\" />\n {/* 音量覆盖层 */}\n <div\n className=\"absolute h-[4px] bg-purple-500 rounded-full transition-all duration-100 pointer-events-none\"\n style={{\n width: `${(isMuted ? 0 : volume) * 100}%`\n }}\n />\n {/* 音量滑块 */}\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.01\"\n value={isMuted ? 0 : volume}\n onChange={handleVolumeChange}\n className=\"volume-slider absolute w-full\"\n />\n </div>\n </div>\n </div>\n\n {/* 隐藏的 audio 元素 */}\n <audio\n ref={audioRef}\n src={url}\n onError={handleError}\n className=\"hidden\"\n />\n </div>\n );\n};\n\n","export default {\n \"pre[class*=\\\"language-\\\"]\": {\n \"color\": \"#d4d4d4\",\n \"fontSize\": \"13px\",\n \"textShadow\": \"none\",\n \"fontFamily\": \"Menlo, Monaco, Consolas, \\\"Andale Mono\\\", \\\"Ubuntu Mono\\\", \\\"Courier New\\\", monospace\",\n \"direction\": \"ltr\",\n \"textAlign\": \"left\",\n \"whiteSpace\": \"pre\",\n \"wordSpacing\": \"normal\",\n \"wordBreak\": \"normal\",\n \"lineHeight\": \"1.5\",\n \"MozTabSize\": \"4\",\n \"OTabSize\": \"4\",\n \"tabSize\": \"4\",\n \"WebkitHyphens\": \"none\",\n \"MozHyphens\": \"none\",\n \"msHyphens\": \"none\",\n \"hyphens\": \"none\",\n \"padding\": \"1em\",\n \"margin\": \".5em 0\",\n \"overflow\": \"auto\",\n \"background\": \"#1e1e1e\"\n },\n \"code[class*=\\\"language-\\\"]\": {\n \"color\": \"#d4d4d4\",\n \"fontSize\": \"13px\",\n \"textShadow\": \"none\",\n \"fontFamily\": \"Menlo, Monaco, Consolas, \\\"Andale Mono\\\", \\\"Ubuntu Mono\\\", \\\"Courier New\\\", monospace\",\n \"direction\": \"ltr\",\n \"textAlign\": \"left\",\n \"whiteSpace\": \"pre\",\n \"wordSpacing\": \"normal\",\n \"wordBreak\": \"normal\",\n \"lineHeight\": \"1.5\",\n \"MozTabSize\": \"4\",\n \"OTabSize\": \"4\",\n \"tabSize\": \"4\",\n \"WebkitHyphens\": \"none\",\n \"MozHyphens\": \"none\",\n \"msHyphens\": \"none\",\n \"hyphens\": \"none\"\n },\n \"pre[class*=\\\"language-\\\"]::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"code[class*=\\\"language-\\\"]::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"pre[class*=\\\"language-\\\"] *::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \"code[class*=\\\"language-\\\"] *::selection\": {\n \"textShadow\": \"none\",\n \"background\": \"#264F78\"\n },\n \":not(pre) > code[class*=\\\"language-\\\"]\": {\n \"padding\": \".1em .3em\",\n \"borderRadius\": \".3em\",\n \"color\": \"#db4c69\",\n \"background\": \"#1e1e1e\"\n },\n \".namespace\": {\n \"Opacity\": \".7\"\n },\n \"doctype.doctype-tag\": {\n \"color\": \"#569CD6\"\n },\n \"doctype.name\": {\n \"color\": \"#9cdcfe\"\n },\n \"comment\": {\n \"color\": \"#6a9955\"\n },\n \"prolog\": {\n \"color\": \"#6a9955\"\n },\n \"punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-html .language-css .token.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-html .language-javascript .token.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \"property\": {\n \"color\": \"#9cdcfe\"\n },\n \"tag\": {\n \"color\": \"#569cd6\"\n },\n \"boolean\": {\n \"color\": \"#569cd6\"\n },\n \"number\": {\n \"color\": \"#b5cea8\"\n },\n \"constant\": {\n \"color\": \"#9cdcfe\"\n },\n \"symbol\": {\n \"color\": \"#b5cea8\"\n },\n \"inserted\": {\n \"color\": \"#b5cea8\"\n },\n \"unit\": {\n \"color\": \"#b5cea8\"\n },\n \"selector\": {\n \"color\": \"#d7ba7d\"\n },\n \"attr-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"string\": {\n \"color\": \"#ce9178\"\n },\n \"char\": {\n \"color\": \"#ce9178\"\n },\n \"builtin\": {\n \"color\": \"#ce9178\"\n },\n \"deleted\": {\n \"color\": \"#ce9178\"\n },\n \".language-css .token.string.url\": {\n \"textDecoration\": \"underline\"\n },\n \"operator\": {\n \"color\": \"#d4d4d4\"\n },\n \"entity\": {\n \"color\": \"#569cd6\"\n },\n \"operator.arrow\": {\n \"color\": \"#569CD6\"\n },\n \"atrule\": {\n \"color\": \"#ce9178\"\n },\n \"atrule.rule\": {\n \"color\": \"#c586c0\"\n },\n \"atrule.url\": {\n \"color\": \"#9cdcfe\"\n },\n \"atrule.url.function\": {\n \"color\": \"#dcdcaa\"\n },\n \"atrule.url.punctuation\": {\n \"color\": \"#d4d4d4\"\n },\n \"keyword\": {\n \"color\": \"#569CD6\"\n },\n \"keyword.module\": {\n \"color\": \"#c586c0\"\n },\n \"keyword.control-flow\": {\n \"color\": \"#c586c0\"\n },\n \"function\": {\n \"color\": \"#dcdcaa\"\n },\n \"function.maybe-class-name\": {\n \"color\": \"#dcdcaa\"\n },\n \"regex\": {\n \"color\": \"#d16969\"\n },\n \"important\": {\n \"color\": \"#569cd6\"\n },\n \"italic\": {\n \"fontStyle\": \"italic\"\n },\n \"class-name\": {\n \"color\": \"#4ec9b0\"\n },\n \"maybe-class-name\": {\n \"color\": \"#4ec9b0\"\n },\n \"console\": {\n \"color\": \"#9cdcfe\"\n },\n \"parameter\": {\n \"color\": \"#9cdcfe\"\n },\n \"interpolation\": {\n \"color\": \"#9cdcfe\"\n },\n \"punctuation.interpolation-punctuation\": {\n \"color\": \"#569cd6\"\n },\n \"variable\": {\n \"color\": \"#9cdcfe\"\n },\n \"imports.maybe-class-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"exports.maybe-class-name\": {\n \"color\": \"#9cdcfe\"\n },\n \"escape\": {\n \"color\": \"#d7ba7d\"\n },\n \"tag.punctuation\": {\n \"color\": \"#808080\"\n },\n \"cdata\": {\n \"color\": \"#808080\"\n },\n \"attr-value\": {\n \"color\": \"#ce9178\"\n },\n \"attr-value.punctuation\": {\n \"color\": \"#ce9178\"\n },\n \"attr-value.punctuation.attr-equals\": {\n \"color\": \"#d4d4d4\"\n },\n \"namespace\": {\n \"color\": \"#4ec9b0\"\n },\n \"pre[class*=\\\"language-javascript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-javascript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-jsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-jsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-typescript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-typescript\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-tsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"code[class*=\\\"language-tsx\\\"]\": {\n \"color\": \"#9cdcfe\"\n },\n \"pre[class*=\\\"language-css\\\"]\": {\n \"color\": \"#ce9178\"\n },\n \"code[class*=\\\"language-css\\\"]\": {\n \"color\": \"#ce9178\"\n },\n \"pre[class*=\\\"language-html\\\"]\": {\n \"color\": \"#d4d4d4\"\n },\n \"code[class*=\\\"language-html\\\"]\": {\n \"color\": \"#d4d4d4\"\n },\n \".language-regex .token.anchor\": {\n \"color\": \"#dcdcaa\"\n },\n \".language-html .token.punctuation\": {\n \"color\": \"#808080\"\n },\n \"pre[class*=\\\"language-\\\"] > code[class*=\\\"language-\\\"]\": {\n \"position\": \"relative\",\n \"zIndex\": \"1\"\n },\n \".line-highlight.line-highlight\": {\n \"background\": \"#f7ebc6\",\n \"boxShadow\": \"inset 5px 0 0 #f7d87c\",\n \"zIndex\": \"0\"\n }\n};","import { useState, useEffect } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';\n\ninterface MarkdownRendererProps {\n url: string;\n}\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url }) => {\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('加载失败');\n }\n const text = await response.text();\n setContent(text);\n } catch (err) {\n setError('Markdown 文件加载失败');\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div className=\"max-w-4xl mx-auto bg-white/5 backdrop-blur-sm rounded-2xl p-8 border border-white/10\">\n <div className=\"prose prose-invert prose-lg max-w-none\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n return !inline && match ? (\n <SyntaxHighlighter\n style={vscDarkPlus}\n language={match[1]}\n PreTag=\"div\"\n className=\"rounded-lg\"\n {...props}\n >\n {String(children).replace(/\\n$/, '')}\n </SyntaxHighlighter>\n ) : (\n <code className=\"bg-white/10 px-1.5 py-0.5 rounded text-sm\" {...props}>\n {children}\n </code>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"text-4xl font-bold mb-4 text-white border-b border-white/20 pb-2\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"text-3xl font-bold mb-3 text-white mt-8\">{children}</h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"text-2xl font-bold mb-2 text-white mt-6\">{children}</h3>\n ),\n p: ({ children }) => <p className=\"text-white/90 mb-4 leading-relaxed\">{children}</p>,\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"text-blue-400 hover:text-blue-300 underline\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => <ul className=\"list-disc list-inside mb-4 text-white/90\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal list-inside mb-4 text-white/90\">{children}</ol>,\n li: ({ children }) => <li className=\"mb-1\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-4 border-blue-500 pl-4 italic text-white/80 my-4\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"overflow-x-auto my-4\">\n <table className=\"min-w-full border border-white/20\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-white/20 px-4 py-2 bg-white/10 text-white font-semibold\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"border border-white/20 px-4 py-2 text-white/90\">{children}</td>\n ),\n hr: () => <hr className=\"border-white/20 my-6\" />,\n img: ({ src, alt }) => (\n <img src={src} alt={alt} className=\"rounded-lg max-w-full h-auto my-4\" />\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n </div>\n );\n};\n\n","import { useState, useEffect } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport { FileText } from 'lucide-react';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n}\n\nconst getLanguageFromFileName = (fileName: string): string => {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n const languageMap: Record<string, string> = {\n js: 'javascript',\n jsx: 'jsx',\n ts: 'typescript',\n tsx: 'tsx',\n py: 'python',\n java: 'java',\n cpp: 'cpp',\n c: 'c',\n cs: 'csharp',\n php: 'php',\n rb: 'ruby',\n go: 'go',\n rs: 'rust',\n swift: 'swift',\n kt: 'kotlin',\n scala: 'scala',\n sh: 'bash',\n bash: 'bash',\n zsh: 'bash',\n json: 'json',\n xml: 'xml',\n html: 'html',\n css: 'css',\n scss: 'scss',\n sass: 'sass',\n less: 'less',\n sql: 'sql',\n yaml: 'yaml',\n yml: 'yaml',\n toml: 'toml',\n ini: 'ini',\n conf: 'nginx',\n md: 'markdown',\n txt: 'text',\n };\n return languageMap[ext] || 'text';\n};\n\nexport const TextRenderer: React.FC<TextRendererProps> = ({ url, fileName }) => {\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const language = getLanguageFromFileName(fileName);\n\n useEffect(() => {\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error('加载失败');\n }\n const text = await response.text();\n setContent(text);\n } catch (err) {\n setError('文本文件加载失败');\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"w-12 h-12 border-4 border-white/20 border-t-white rounded-full animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center w-full h-full\">\n <div className=\"text-white/70 text-center\">\n <p className=\"text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"w-full h-full overflow-auto p-8\">\n <div className=\"max-w-6xl mx-auto bg-white/5 backdrop-blur-sm rounded-2xl border border-white/10 overflow-hidden\">\n {/* 文件头部 */}\n <div className=\"flex items-center gap-3 px-6 py-4 bg-white/5 border-b border-white/10\">\n <FileText className=\"w-5 h-5 text-white/70\" />\n <span className=\"text-white font-medium\">{fileName}</span>\n <span className=\"ml-auto text-xs text-white/50 uppercase\">{language}</span>\n </div>\n\n {/* 代码内容 */}\n <div className=\"text-sm\">\n {language === 'text' ? (\n <pre className=\"p-6 text-white/90 font-mono whitespace-pre-wrap break-words\">\n {content}\n </pre>\n ) : (\n <SyntaxHighlighter\n language={language}\n style={vscDarkPlus}\n showLineNumbers\n customStyle={{\n margin: 0,\n padding: '1.5rem',\n background: 'transparent',\n fontSize: '0.875rem',\n }}\n lineNumberStyle={{\n minWidth: '3em',\n paddingRight: '1em',\n color: 'rgba(255, 255, 255, 0.3)',\n userSelect: 'none',\n }}\n >\n {content}\n </SyntaxHighlighter>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n","import { FileQuestion, Download } from 'lucide-react';\n\ninterface UnsupportedRendererProps {\n fileName: string;\n fileType: string;\n onDownload: () => void;\n}\n\nexport const UnsupportedRenderer: React.FC<UnsupportedRendererProps> = ({\n fileName,\n fileType,\n onDownload,\n}) => {\n return (\n <div className=\"flex flex-col items-center justify-center w-full h-full p-8 gap-6\">\n <div className=\"w-32 h-32 rounded-full bg-white/10 flex items-center justify-center\">\n <FileQuestion className=\"w-16 h-16 text-white/70\" />\n </div>\n\n <div className=\"text-white text-center\">\n <p className=\"text-xl font-medium mb-2\">{fileName}</p>\n <p className=\"text-white/70\">不支持预览此文件类型 ({fileType})</p>\n </div>\n\n <button\n onClick={onDownload}\n className=\"flex items-center gap-2 px-6 py-3 bg-white/10 hover:bg-white/20 backdrop-blur-sm rounded-lg text-white font-medium transition-all\"\n >\n <Download className=\"w-5 h-5\" />\n 下载文件查看\n </button>\n </div>\n );\n};\n\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n X,\n ZoomIn,\n ZoomOut,\n RotateCw,\n RotateCcw,\n Download,\n ChevronLeft,\n ChevronRight,\n Maximize2,\n Minimize2,\n RefreshCw,\n} from 'lucide-react';\nimport { PreviewFile, PreviewFileInput, FileType, CustomRenderer } from './types';\nimport { normalizeFiles } from './utils/fileNormalizer';\nimport { ImageRenderer } from './renderers/ImageRenderer';\nimport { PdfRenderer } from './renderers/PdfRenderer';\nimport { DocxRenderer } from './renderers/DocxRenderer';\nimport { XlsxRenderer } from './renderers/XlsxRenderer';\nimport { PptxRenderer } from './renderers/PptxRenderer';\nimport { VideoRenderer } from './renderers/VideoRenderer';\nimport { AudioRenderer } from './renderers/AudioRenderer';\nimport { MarkdownRenderer } from './renderers/MarkdownRenderer';\nimport { TextRenderer } from './renderers/TextRenderer';\nimport { UnsupportedRenderer } from './renderers/UnsupportedRenderer';\n\ninterface FilePreviewModalProps {\n files: PreviewFileInput[];\n currentIndex: number;\n isOpen: boolean;\n onClose: () => void;\n onNavigate?: (index: number) => void;\n customRenderers?: CustomRenderer[];\n}\n\nconst getFileType = (file: PreviewFile): FileType => {\n const ext = file.name.split('.').pop()?.toLowerCase() || '';\n const mimeType = file.type.toLowerCase();\n\n if (mimeType.startsWith('image/') || ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(ext)) {\n return 'image';\n }\n if (mimeType.includes('pdf') || ext === 'pdf') {\n return 'pdf';\n }\n if (mimeType.includes('wordprocessingml') || ext === 'docx') {\n return 'docx';\n }\n if (mimeType.includes('spreadsheetml') || ext === 'xlsx') {\n return 'xlsx';\n }\n if (mimeType.includes('presentationml') || ext === 'pptx' || ext === 'ppt') {\n return 'pptx';\n }\n if (mimeType.startsWith('video/') || ['mp4', 'webm', 'ogg', 'ogv', 'mov', 'avi', 'mkv', 'm4v', '3gp', 'flv'].includes(ext)) {\n return 'video';\n }\n if (mimeType.startsWith('audio/') || ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac'].includes(ext)) {\n return 'audio';\n }\n if (ext === 'md' || ext === 'markdown') {\n return 'markdown';\n }\n // 文本文件和代码文件\n const textExtensions = [\n 'txt', 'log', 'csv',\n 'js', 'jsx', 'ts', 'tsx', 'json',\n 'py', 'java', 'cpp', 'c', 'h', 'cs', 'php', 'rb', 'go', 'rs', 'swift', 'kt',\n 'html', 'css', 'scss', 'sass', 'less',\n 'xml', 'yaml', 'yml', 'toml', 'ini', 'conf',\n 'sh', 'bash', 'zsh', 'sql',\n ];\n if (mimeType.startsWith('text/') || textExtensions.includes(ext)) {\n return 'text';\n }\n return 'unsupported';\n};\n\nexport const FilePreviewModal: React.FC<FilePreviewModalProps> = ({\n files,\n currentIndex,\n isOpen,\n onClose,\n onNavigate,\n customRenderers = [],\n}) => {\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n const [, setTotalPages] = useState(1); // PDF 总页数,由 PdfRenderer 更新\n\n // 标准化文件输入\n const normalizedFiles = useMemo(() => normalizeFiles(files), [files]);\n\n const currentFile = normalizedFiles[currentIndex];\n\n // 检查是否有自定义渲染器匹配当前文件\n const customRenderer = useMemo(() => {\n if (!currentFile) return null;\n return customRenderers.find(renderer => renderer.test(currentFile));\n }, [currentFile, customRenderers]);\n\n const fileType = currentFile ? getFileType(currentFile) : 'unsupported';\n\n // 重置状态当文件改变时\n useEffect(() => {\n setZoom(1);\n setRotation(0);\n setCurrentPage(1);\n setTotalPages(1);\n }, [currentIndex]);\n\n // 键盘导航\n // 锁定 body 滚动\n useEffect(() => {\n if (isOpen) {\n // 保存原始的 overflow 值\n const originalOverflow = document.body.style.overflow;\n const originalPaddingRight = document.body.style.paddingRight;\n\n // 获取滚动条宽度\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n // 锁定滚动并补偿滚动条宽度\n document.body.style.overflow = 'hidden';\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n\n return () => {\n // 恢复原始值\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n };\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n } else if (e.key === 'ArrowLeft' && currentIndex > 0) {\n onNavigate?.(currentIndex - 1);\n } else if (e.key === 'ArrowRight' && currentIndex < normalizedFiles.length - 1) {\n onNavigate?.(currentIndex + 1);\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, currentIndex, normalizedFiles.length, onClose, onNavigate]);\n\n const handleZoomIn = useCallback(() => {\n setZoom((prev) => Math.min(prev + 0.25, 5));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom((prev) => Math.max(prev - 0.25, 0.5));\n }, []);\n\n const handleRotate = useCallback(() => {\n setRotation((prev) => prev + 90);\n }, []);\n\n const handleRotateLeft = useCallback(() => {\n setRotation((prev) => prev - 90);\n }, []);\n\n const handleFitToWidth = useCallback(() => {\n setZoom(1);\n setRotation(0);\n }, []);\n\n const handleOriginalSize = useCallback(() => {\n setZoom(1);\n }, []);\n\n const handleZoomChange = useCallback((newZoom: number) => {\n setZoom(newZoom);\n }, []);\n\n const handleReset = useCallback(() => {\n setZoom(1);\n setRotation(0);\n }, []);\n\n const handleDownload = useCallback(() => {\n if (!currentFile) return;\n const link = document.createElement('a');\n link.href = currentFile.url;\n link.download = currentFile.name;\n link.click();\n }, [currentFile]);\n\n if (!isOpen || !currentFile) return null;\n\n const showZoomControls = fileType === 'image' || fileType === 'pdf';\n const showRotateControl = fileType === 'image';\n\n const modalContent = (\n <AnimatePresence>\n {isOpen && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"fixed inset-0 z-[9999] flex items-center justify-center bg-black/80 backdrop-blur-md overflow-hidden\"\n onClick={onClose}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* 主内容区域 */}\n <div\n className=\"relative w-full h-full flex flex-col overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* 顶部工具栏 */}\n <motion.div\n initial={{ y: -100 }}\n animate={{ y: 0 }}\n exit={{ y: -100 }}\n className=\"absolute top-0 left-0 right-0 z-10 p-4\"\n >\n <div className=\"max-w-7xl mx-auto flex items-center justify-between bg-black/40 backdrop-blur-xl rounded-2xl px-6 py-4 shadow-2xl border border-white/10\">\n {/* 文件名 */}\n <div className=\"flex-1 min-w-0\">\n <h2 className=\"text-white font-medium text-lg truncate\">\n {currentFile.name}\n </h2>\n <p className=\"text-white/60 text-sm\">\n {currentIndex + 1} / {normalizedFiles.length}\n </p>\n </div>\n\n {/* 工具按钮 */}\n <div className=\"flex items-center gap-2 ml-4\">\n {showZoomControls && (\n <>\n <ToolbarButton\n icon={<ZoomOut className=\"w-5 h-5\" />}\n label=\"缩小\"\n onClick={handleZoomOut}\n disabled={zoom <= 0.5}\n />\n <span className=\"text-white/70 text-sm min-w-[4rem] text-center font-medium\">\n {Math.round(zoom * 100)}%\n </span>\n <ToolbarButton\n icon={<ZoomIn className=\"w-5 h-5\" />}\n label=\"放大\"\n onClick={handleZoomIn}\n disabled={zoom >= 5}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n <ToolbarButton\n icon={<Minimize2 className=\"w-5 h-5\" />}\n label=\"适应窗口\"\n onClick={handleFitToWidth}\n />\n <ToolbarButton\n icon={<Maximize2 className=\"w-5 h-5\" />}\n label=\"原始尺寸\"\n onClick={handleOriginalSize}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n {showRotateControl && (\n <>\n <ToolbarButton\n icon={<RotateCcw className=\"w-5 h-5\" />}\n label=\"向左旋转\"\n onClick={handleRotateLeft}\n />\n <ToolbarButton\n icon={<RotateCw className=\"w-5 h-5\" />}\n label=\"向右旋转\"\n onClick={handleRotate}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n {(showZoomControls || showRotateControl) && (\n <>\n <ToolbarButton\n icon={<RefreshCw className=\"w-5 h-5\" />}\n label=\"复原\"\n onClick={handleReset}\n />\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n </>\n )}\n\n <ToolbarButton\n icon={<Download className=\"w-5 h-5\" />}\n label=\"下载\"\n onClick={handleDownload}\n />\n\n <div className=\"w-px h-6 bg-white/20 mx-2\" />\n\n <ToolbarButton\n icon={<X className=\"w-5 h-5\" />}\n label=\"关闭\"\n onClick={onClose}\n />\n </div>\n </div>\n </motion.div>\n\n {/* 内容区域 */}\n <div className=\"flex-1 flex items-center justify-center pt-24 pb-8 overflow-auto\">\n {customRenderer ? (\n // 使用自定义渲染器\n customRenderer.render(currentFile)\n ) : (\n <>\n {fileType === 'image' && (\n <ImageRenderer\n url={currentFile.url}\n zoom={zoom}\n rotation={rotation}\n onZoomChange={handleZoomChange}\n />\n )}\n {fileType === 'pdf' && (\n <PdfRenderer\n url={currentFile.url}\n zoom={zoom}\n currentPage={currentPage}\n onPageChange={setCurrentPage}\n onTotalPagesChange={setTotalPages}\n />\n )}\n {fileType === 'docx' && <DocxRenderer url={currentFile.url} />}\n {fileType === 'xlsx' && <XlsxRenderer url={currentFile.url} />}\n {fileType === 'pptx' && <PptxRenderer url={currentFile.url} />}\n {fileType === 'video' && <VideoRenderer url={currentFile.url} />}\n {fileType === 'audio' && (\n <AudioRenderer url={currentFile.url} fileName={currentFile.name} />\n )}\n {fileType === 'markdown' && <MarkdownRenderer url={currentFile.url} />}\n {fileType === 'text' && (\n <TextRenderer url={currentFile.url} fileName={currentFile.name} />\n )}\n {fileType === 'unsupported' && (\n <UnsupportedRenderer\n fileName={currentFile.name}\n fileType={currentFile.type}\n onDownload={handleDownload}\n />\n )}\n </>\n )}\n </div>\n\n {/* 左右导航箭头 */}\n {normalizedFiles.length > 1 && (\n <>\n {currentIndex > 0 && (\n <motion.button\n initial={{ x: -100, opacity: 0 }}\n animate={{ x: 0, opacity: 1 }}\n exit={{ x: -100, opacity: 0 }}\n onClick={() => onNavigate?.(currentIndex - 1)}\n className=\"absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/40 backdrop-blur-xl border border-white/10 flex items-center justify-center text-white hover:bg-black/60 transition-all shadow-2xl\"\n >\n <ChevronLeft className=\"w-6 h-6\" />\n </motion.button>\n )}\n\n {currentIndex < normalizedFiles.length - 1 && (\n <motion.button\n initial={{ x: 100, opacity: 0 }}\n animate={{ x: 0, opacity: 1 }}\n exit={{ x: 100, opacity: 0 }}\n onClick={() => onNavigate?.(currentIndex + 1)}\n className=\"absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/40 backdrop-blur-xl border border-white/10 flex items-center justify-center text-white hover:bg-black/60 transition-all shadow-2xl\"\n >\n <ChevronRight className=\"w-6 h-6\" />\n </motion.button>\n )}\n </>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n\n // 使用 Portal 将模态框渲染到 document.body\n return createPortal(modalContent, document.body);\n};\n\n// 工具栏按钮组件\ninterface ToolbarButtonProps {\n icon: React.ReactNode;\n label: string;\n onClick: () => void;\n disabled?: boolean;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({ icon, label, onClick, disabled }) => {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n title={label}\n className={`p-2 rounded-lg transition-all ${disabled\n ? 'text-white/30 cursor-not-allowed'\n : 'text-white hover:bg-white/10 active:bg-white/20'\n }`}\n >\n {icon}\n </button>\n );\n};\n\n"],"names":["getFileNameFromUrl","url","fileName","inferMimeType","ext","_a","normalizeFile","input","index","normalizeFiles","inputs","ImageRenderer","zoom","rotation","onZoomChange","loaded","setLoaded","useState","error","setError","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","containerRef","useRef","useEffect","handleLoad","handleError","handleDoubleClick","handleWheel","useCallback","e","delta","prev","newZoom","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","motion","pdfjsVersion","pdfjs","workerSrc","originalWorkerSrc","cdnWorkerSrc","event","PdfRenderer","currentPage","onPageChange","onTotalPagesChange","numPages","setNumPages","pageRefs","onDocumentLoadSuccess","onDocumentLoadError","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","pageElement","pageNumber","rect","containerRect","pageCenter","distance","setPageRef","element","Document","_","el","Page","DocxRenderer","html","setHtml","loading","setLoading","response","arrayBuffer","result","mammoth","err","XlsxRenderer","sheets","setSheets","activeSheet","setActiveSheet","workbook","XLSX","parsedSheets","name","worksheet","data","currentSheet","sheet","row","rowIndex","cell","cellIndex","PptxRenderer","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","isInitialRender","updateDimensions","initialDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadPptx","previewErr","timer","Presentation","getVideoType","VideoRenderer","isLoading","setIsLoading","videoRef","playerRef","videoElement","videoType","player","videojs","AudioRenderer","isPlaying","setIsPlaying","currentTime","setCurrentTime","duration","setDuration","volume","setVolume","isMuted","setIsMuted","audioRef","audio","updateTime","updateDuration","handleEnded","handleCanPlay","togglePlay","handleSeek","time","handleVolumeChange","vol","toggleMute","skip","seconds","formatTime","minutes","Music","SkipBack","Pause","Play","SkipForward","VolumeX","Volume2","vscDarkPlus","MarkdownRenderer","content","setContent","text","ReactMarkdown","remarkGfm","node","inline","className","children","props","match","SyntaxHighlighter","href","src","alt","getLanguageFromFileName","TextRenderer","language","FileText","UnsupportedRenderer","fileType","onDownload","FileQuestion","Download","getFileType","file","mimeType","textExtensions","FilePreviewModal","files","currentIndex","isOpen","onClose","onNavigate","customRenderers","setZoom","setRotation","setCurrentPage","setTotalPages","normalizedFiles","useMemo","currentFile","customRenderer","renderer","originalOverflow","originalPaddingRight","scrollbarWidth","handleKeyDown","handleZoomIn","handleZoomOut","handleRotate","handleRotateLeft","handleFitToWidth","handleOriginalSize","handleZoomChange","handleReset","handleDownload","link","showZoomControls","showRotateControl","modalContent","AnimatePresence","Fragment","ToolbarButton","ZoomOut","ZoomIn","Minimize2","Maximize2","RotateCcw","RotateCw","RefreshCw","X","ChevronLeft","ChevronRight","createPortal","icon","label","onClick","disabled"],"mappings":"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A,CACC,IAAK6G,EACL,IAAKxJ,EACL,QAAS+B,EACT,UAAU,QAAA,CAAA,CACZ,EACF,CAEJ,EClOAgJ,EAAe,CACb,0BAA6B,CAC3B,MAAS,UACT,SAAY,OACZ,WAAc,OACd,WAAc,kFACd,UAAa,MACb,UAAa,OACb,WAAc,MACd,YAAe,SACf,UAAa,SACb,WAAc,MACd,WAAc,IACd,SAAY,IACZ,QAAW,IACX,cAAiB,OACjB,WAAc,OACd,UAAa,OACb,QAAW,OACX,QAAW,MACX,OAAU,SACV,SAAY,OACZ,WAAc,SAClB,EACE,2BAA8B,CAC5B,MAAS,UACT,SAAY,OACZ,WAAc,OACd,WAAc,kFACd,UAAa,MACb,UAAa,OACb,WAAc,MACd,YAAe,SACf,UAAa,SACb,WAAc,MACd,WAAc,IACd,SAAY,IACZ,QAAW,IACX,cAAiB,OACjB,WAAc,OACd,UAAa,OACb,QAAW,MACf,EACE,qCAAwC,CACtC,WAAc,OACd,WAAc,SAClB,EACE,sCAAyC,CACvC,WAAc,OACd,WAAc,SAClB,EACE,uCAA0C,CACxC,WAAc,OACd,WAAc,SAClB,EACE,wCAA2C,CACzC,WAAc,OACd,WAAc,SAClB,EACE,uCAA0C,CACxC,QAAW,YACX,aAAgB,OAChB,MAAS,UACT,WAAc,SAClB,EACE,aAAc,CACZ,QAAW,IACf,EACE,sBAAuB,CACrB,MAAS,SACb,EACE,eAAgB,CACd,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,YAAe,CACb,MAAS,SACb,EACE,kDAAmD,CACjD,MAAS,SACb,EACE,yDAA0D,CACxD,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,IAAO,CACL,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,KAAQ,CACN,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,YAAa,CACX,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,KAAQ,CACN,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,kCAAmC,CACjC,eAAkB,WACtB,EACE,SAAY,CACV,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,iBAAkB,CAChB,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,cAAe,CACb,MAAS,SACb,EACE,aAAc,CACZ,MAAS,SACb,EACE,sBAAuB,CACrB,MAAS,SACb,EACE,yBAA0B,CACxB,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,iBAAkB,CAChB,MAAS,SACb,EACE,uBAAwB,CACtB,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,4BAA6B,CAC3B,MAAS,SACb,EACE,MAAS,CACP,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,OAAU,CACR,UAAa,QACjB,EACE,aAAc,CACZ,MAAS,SACb,EACE,mBAAoB,CAClB,MAAS,SACb,EACE,QAAW,CACT,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,cAAiB,CACf,MAAS,SACb,EACE,wCAAyC,CACvC,MAAS,SACb,EACE,SAAY,CACV,MAAS,SACb,EACE,2BAA4B,CAC1B,MAAS,SACb,EACE,2BAA4B,CAC1B,MAAS,SACb,EACE,OAAU,CACR,MAAS,SACb,EACE,kBAAmB,CACjB,MAAS,SACb,EACE,MAAS,CACP,MAAS,SACb,EACE,aAAc,CACZ,MAAS,SACb,EACE,yBAA0B,CACxB,MAAS,SACb,EACE,qCAAsC,CACpC,MAAS,SACb,EACE,UAAa,CACX,MAAS,SACb,EACE,oCAAuC,CACrC,MAAS,SACb,EACE,qCAAwC,CACtC,MAAS,SACb,EACE,6BAAgC,CAC9B,MAAS,SACb,EACE,8BAAiC,CAC/B,MAAS,SACb,EACE,oCAAuC,CACrC,MAAS,SACb,EACE,qCAAwC,CACtC,MAAS,SACb,EACE,6BAAgC,CAC9B,MAAS,SACb,EACE,8BAAiC,CAC/B,MAAS,SACb,EACE,6BAAgC,CAC9B,M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","x_google_ignoreList":[9]}