@eternalheart/react-file-preview 1.3.5 → 1.3.7

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.
Files changed (70) hide show
  1. package/lib/FilePreviewContent.d.ts +3 -0
  2. package/lib/FilePreviewContent.d.ts.map +1 -1
  3. package/lib/FilePreviewEmbed.d.ts +3 -1
  4. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  5. package/lib/FilePreviewModal.d.ts +3 -1
  6. package/lib/FilePreviewModal.d.ts.map +1 -1
  7. package/lib/ThemeContext.d.ts +18 -0
  8. package/lib/ThemeContext.d.ts.map +1 -0
  9. package/lib/chunks/index--zZy1XpK.mjs +299 -0
  10. package/lib/chunks/index--zZy1XpK.mjs.map +1 -0
  11. package/lib/chunks/index-B5tBeF0g.mjs +51 -0
  12. package/lib/chunks/index-B5tBeF0g.mjs.map +1 -0
  13. package/lib/chunks/index-BEolw_uv.mjs +528 -0
  14. package/lib/chunks/index-BEolw_uv.mjs.map +1 -0
  15. package/lib/chunks/index-BIg3vHQf.mjs +110 -0
  16. package/lib/chunks/index-BIg3vHQf.mjs.map +1 -0
  17. package/lib/chunks/index-BOEtlHD3.mjs +257 -0
  18. package/lib/chunks/index-BOEtlHD3.mjs.map +1 -0
  19. package/lib/chunks/index-BWbuffRN.mjs +152 -0
  20. package/lib/chunks/index-BWbuffRN.mjs.map +1 -0
  21. package/lib/chunks/index-BsSx9pGx.mjs +128 -0
  22. package/lib/chunks/index-BsSx9pGx.mjs.map +1 -0
  23. package/lib/chunks/index-CQABwGVP.mjs +99 -0
  24. package/lib/chunks/index-CQABwGVP.mjs.map +1 -0
  25. package/lib/chunks/index-DOMMMe9f.mjs +96 -0
  26. package/lib/chunks/index-DOMMMe9f.mjs.map +1 -0
  27. package/lib/chunks/index-DTH1IvOG.mjs +239 -0
  28. package/lib/chunks/index-DTH1IvOG.mjs.map +1 -0
  29. package/lib/chunks/index-D_8IHm6o.mjs +98 -0
  30. package/lib/chunks/index-D_8IHm6o.mjs.map +1 -0
  31. package/lib/chunks/index-DinKO2op.mjs +116 -0
  32. package/lib/chunks/index-DinKO2op.mjs.map +1 -0
  33. package/lib/chunks/index-LNXbKjrI.mjs +1900 -0
  34. package/lib/chunks/index-LNXbKjrI.mjs.map +1 -0
  35. package/lib/chunks/index-Yp36heK8.mjs +193 -0
  36. package/lib/chunks/index-Yp36heK8.mjs.map +1 -0
  37. package/lib/chunks/index-qxvk-6P6.mjs +172 -0
  38. package/lib/chunks/index-qxvk-6P6.mjs.map +1 -0
  39. package/lib/chunks/index-w0tt7Myw.mjs +96 -0
  40. package/lib/chunks/index-w0tt7Myw.mjs.map +1 -0
  41. package/lib/chunks/index-xTq9b3vw.mjs +52 -0
  42. package/lib/chunks/index-xTq9b3vw.mjs.map +1 -0
  43. package/lib/chunks/index-zDEwNk3h.mjs +103 -0
  44. package/lib/chunks/index-zDEwNk3h.mjs.map +1 -0
  45. package/lib/chunks/useShikiHighlight-DtWg9b8y.mjs +23 -0
  46. package/lib/chunks/useShikiHighlight-DtWg9b8y.mjs.map +1 -0
  47. package/lib/chunks/xspreadsheet-CyBXARuf.mjs +5215 -0
  48. package/lib/chunks/xspreadsheet-CyBXARuf.mjs.map +1 -0
  49. package/lib/hooks/useShikiHighlight.d.ts +18 -0
  50. package/lib/hooks/useShikiHighlight.d.ts.map +1 -0
  51. package/lib/index.cjs +28 -508
  52. package/lib/index.cjs.map +1 -1
  53. package/lib/index.css +1 -1
  54. package/lib/index.d.ts +1 -1
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.mjs +13 -59140
  57. package/lib/index.mjs.map +1 -1
  58. package/lib/renderers/Audio/index.d.ts.map +1 -1
  59. package/lib/renderers/Json/index.d.ts.map +1 -1
  60. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  61. package/lib/renderers/RendererLoading.d.ts +3 -0
  62. package/lib/renderers/RendererLoading.d.ts.map +1 -0
  63. package/lib/renderers/Text/index.d.ts.map +1 -1
  64. package/lib/renderers/Xml/index.d.ts.map +1 -1
  65. package/lib/renderers/lazy.d.ts +38 -0
  66. package/lib/renderers/lazy.d.ts.map +1 -0
  67. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  68. package/lib/types.d.ts +27 -3
  69. package/lib/types.d.ts.map +1 -1
  70. package/package.json +4 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BWbuffRN.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Presentation } from 'lucide-react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url, tiled = true }) => {\n const t = useTranslator();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\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 const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\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 lastDimensionsRef.current = calculateDimensions();\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 return;\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 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 let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetch(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <div className=\"rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-orange-500 rfp-via-red-500 rfp-to-pink-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl\">\n <Presentation className=\"rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary\" />\n </div>\n <p className=\"rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium\">{t('pptx.load_failed')}</p>\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6\">\n {error}\n </p>\n <a\n href={url}\n download\n className=\"rfp-inline-flex rfp-items-center rfp-gap-2 rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-bg-gradient-to-r rfp-from-purple-500 rfp-to-pink-500 rfp-text-fg-primary rfp-text-sm md:rfp-text-base rfp-rounded-lg md:rfp-rounded-xl hover:rfp-scale-105 rfp-transition-all rfp-shadow-lg\"\n >\n <svg className=\"rfp-w-4 rfp-h-4 md:rfp-w-5 md:rfp-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 {t('common.download')}\n </a>\n <p className=\"rfp-text-xs rfp-text-fg-muted rfp-mt-3 md:rfp-mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["PptxRenderer","url","tiled","t","useTranslator","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","jsxs","jsx","Presentation"],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ import { jsxs as h, jsx as n } from "react/jsx-runtime";
2
+ import { useState as k, useRef as i, useCallback as E, useEffect as D } from "react";
3
+ import { FileSpreadsheet as T } from "lucide-react";
4
+ import M from "exceljs";
5
+ import { S } from "./xspreadsheet-CyBXARuf.mjs";
6
+ import { u as W, C as j } from "./index-LNXbKjrI.mjs";
7
+ const F = ({ url: x }) => {
8
+ const l = W(), [w, g] = k(!0), [b, N] = k(null), e = i(null), v = i(null), a = i(null), d = i(null), p = i(null), y = i({ width: 0, height: 0 }), c = E(() => {
9
+ if (!e.current) return { width: 800, height: 600 };
10
+ const t = e.current.clientWidth, s = e.current.clientHeight, f = t > 100 ? t : 800, r = s > 100 ? s : 600;
11
+ return { width: f, height: r };
12
+ }, []), m = E(() => {
13
+ if (!e.current || !a.current) return;
14
+ e.current.innerHTML = "", v.current = null;
15
+ const { width: t, height: s } = c(), f = t < 640, r = new S(e.current, {
16
+ mode: "read",
17
+ showToolbar: !1,
18
+ showContextmenu: !1,
19
+ showGrid: !0,
20
+ row: {
21
+ len: 100,
22
+ height: 25
23
+ },
24
+ col: {
25
+ len: 26,
26
+ width: f ? 80 : 100,
27
+ indexWidth: f ? 40 : 60,
28
+ minWidth: f ? 40 : 60
29
+ },
30
+ view: {
31
+ height: () => s,
32
+ width: () => t
33
+ }
34
+ });
35
+ r.loadData(a.current), v.current = r;
36
+ }, [c]);
37
+ return D(() => {
38
+ if (!e.current) return;
39
+ let t = !0;
40
+ const s = () => {
41
+ if (t) {
42
+ t = !1, y.current = c();
43
+ return;
44
+ }
45
+ const f = c(), r = y.current, o = Math.abs(r.width - f.width), u = Math.abs(r.height - f.height);
46
+ o < 10 && u < 10 || (y.current = f, p.current && clearTimeout(p.current), p.current = window.setTimeout(() => {
47
+ a.current && m();
48
+ }, 500));
49
+ };
50
+ return d.current = new ResizeObserver(() => {
51
+ s();
52
+ }), d.current.observe(e.current), () => {
53
+ d.current && d.current.disconnect(), p.current && clearTimeout(p.current);
54
+ };
55
+ }, [c, m]), D(() => {
56
+ let t = !0;
57
+ const s = async () => {
58
+ if (e.current) {
59
+ g(!0), N(null);
60
+ try {
61
+ const r = await fetch(x, {
62
+ mode: "cors",
63
+ credentials: "omit",
64
+ redirect: "follow"
65
+ });
66
+ if (!r.ok)
67
+ throw r.status === 404 ? new Error(l("xlsx.not_found")) : r.status === 403 ? new Error("无权限访问此文件") : new Error(`文件加载失败 (${r.status})`);
68
+ const o = await r.arrayBuffer();
69
+ if (o.byteLength === 0)
70
+ throw new Error("文件为空");
71
+ const u = new M.Workbook();
72
+ await u.xlsx.load(o);
73
+ const R = j(u);
74
+ if (!t) return;
75
+ a.current = R, m(), g(!1);
76
+ } catch (r) {
77
+ if (t) {
78
+ console.error("Excel 解析错误:", r);
79
+ let o = l("xlsx.parse_failed");
80
+ r instanceof Error && (o = r.message), N(o), g(!1);
81
+ }
82
+ }
83
+ }
84
+ }, f = setTimeout(() => {
85
+ requestAnimationFrame(() => {
86
+ s();
87
+ });
88
+ }, 100);
89
+ return () => {
90
+ t = !1, clearTimeout(f), a.current = null, e.current && (e.current.innerHTML = ""), v.current = null;
91
+ };
92
+ }, [x, m]), /* @__PURE__ */ h("div", { className: "rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full", children: [
93
+ w && /* @__PURE__ */ n("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ h("div", { className: "rfp-text-center", children: [
94
+ /* @__PURE__ */ n("div", { className: "rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }),
95
+ /* @__PURE__ */ n("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: l("xlsx.loading") })
96
+ ] }) }),
97
+ b && !w && /* @__PURE__ */ n("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ h("div", { className: "rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4", children: [
98
+ /* @__PURE__ */ n("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ n(T, { className: "rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary" }) }),
99
+ /* @__PURE__ */ n("p", { className: "rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium", children: l("xlsx.load_failed") }),
100
+ /* @__PURE__ */ n("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6", children: b }),
101
+ /* @__PURE__ */ h(
102
+ "a",
103
+ {
104
+ href: x,
105
+ download: !0,
106
+ className: "rfp-inline-flex rfp-items-center rfp-gap-2 rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-bg-gradient-to-r rfp-from-purple-500 rfp-to-pink-500 rfp-text-fg-primary rfp-text-sm md:rfp-text-base rfp-rounded-lg md:rfp-rounded-xl hover:rfp-scale-105 rfp-transition-all rfp-shadow-lg",
107
+ children: [
108
+ /* @__PURE__ */ n("svg", { className: "rfp-w-4 rfp-h-4 md:rfp-w-5 md:rfp-h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) }),
109
+ l("common.download")
110
+ ]
111
+ }
112
+ ),
113
+ /* @__PURE__ */ n("p", { className: "rfp-text-xs rfp-text-fg-muted rfp-mt-3 md:rfp-mt-4", children: "提示:可以使用 Microsoft Excel 或 WPS 打开" })
114
+ ] }) }),
115
+ !b && /* @__PURE__ */ n(
116
+ "div",
117
+ {
118
+ ref: e,
119
+ className: "xlsx-spreadsheet-container rfp-w-full rfp-h-full",
120
+ style: { opacity: w ? 0 : 1 }
121
+ }
122
+ )
123
+ ] });
124
+ };
125
+ export {
126
+ F as XlsxRenderer
127
+ };
128
+ //# sourceMappingURL=index-BsSx9pGx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BsSx9pGx.mjs","sources":["../../src/renderers/Xlsx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { FileSpreadsheet } from 'lucide-react';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '../../utils/excelDataConverter';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n // 清空容器\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\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) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\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, mountSpreadsheet]);\n\n useEffect(() => {\n let isMounted = true;\n\n const loadExcel = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await fetch(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('xlsx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n // 使用 exceljs 解析\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n\n // 转换为 x-data-spreadsheet 数据格式\n const sheetData = convertWorkbookToSpreadsheetData(workbook);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n\n // 挂载 x-data-spreadsheet\n mountSpreadsheet();\n\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t('xlsx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadExcel();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, mountSpreadsheet]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('xlsx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <div className=\"rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl\">\n <FileSpreadsheet className=\"rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary\" />\n </div>\n <p className=\"rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium\">{t('xlsx.load_failed')}</p>\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6\">\n {error}\n </p>\n <a\n href={url}\n download\n className=\"rfp-inline-flex rfp-items-center rfp-gap-2 rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-bg-gradient-to-r rfp-from-purple-500 rfp-to-pink-500 rfp-text-fg-primary rfp-text-sm md:rfp-text-base rfp-rounded-lg md:rfp-rounded-xl hover:rfp-scale-105 rfp-transition-all rfp-shadow-lg\"\n >\n <svg className=\"rfp-w-4 rfp-h-4 md:rfp-w-5 md:rfp-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 {t('common.download')}\n </a>\n <p className=\"rfp-text-xs rfp-text-fg-muted rfp-mt-3 md:rfp-mt-4\">\n 提示:可以使用 Microsoft Excel 或 WPS 打开\n </p>\n </div>\n </div>\n )}\n\n {/* Spreadsheet 容器 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["XlsxRenderer","url","t","useTranslator","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadExcel","response","arrayBuffer","workbook","ExcelJS","sheetData","convertWorkbookToSpreadsheetData","err","errorMsg","timer","jsxs","jsx","FileSpreadsheet"],"mappings":";;;;;;AAYO,MAAMA,IAA4C,CAAC,EAAE,KAAAC,QAAU;AACpE,QAAMC,IAAIC,EAAA,GACJ,CAACC,GAASC,CAAU,IAAIC,EAAS,EAAI,GACrC,CAACC,GAAOC,CAAQ,IAAIF,EAAwB,IAAI,GAChDG,IAAeC,EAAuB,IAAI,GAC1CC,IAAiBD,EAA2B,IAAI,GAChDE,IAAeF,EAAyC,IAAI,GAC5DG,IAAoBH,EAA8B,IAAI,GACtDI,IAAmBJ,EAAsB,IAAI,GAC7CK,IAAoBL,EAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,GAElDM,IAAsBC,EAAY,MAAM;AAC5C,QAAI,CAACR,EAAa,QAAS,QAAO,EAAE,OAAO,KAAK,QAAQ,IAAA;AACxD,UAAMS,IAAWT,EAAa,QAAQ,aAChCU,IAAYV,EAAa,QAAQ,cACjCW,IAAQF,IAAW,MAAMA,IAAW,KACpCG,IAASF,IAAY,MAAMA,IAAY;AAC7C,WAAO,EAAE,OAAAC,GAAO,QAAAC,EAAA;AAAA,EAClB,GAAG,CAAA,CAAE,GAECC,IAAmBL,EAAY,MAAM;AACzC,QAAI,CAACR,EAAa,WAAW,CAACG,EAAa,QAAS;AAGpD,IAAAH,EAAa,QAAQ,YAAY,IACjCE,EAAe,UAAU;AAEzB,UAAM,EAAE,OAAAS,GAAO,QAAAC,EAAA,IAAWL,EAAA,GACpBO,IAAWH,IAAQ,KAEnBI,IAAI,IAAIC,EAAYhB,EAAa,SAAS;AAAA,MAC9C,MAAM;AAAA,MACN,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,KAAK;AAAA,QACH,KAAK;AAAA,QACL,QAAQ;AAAA,MAAA;AAAA,MAEV,KAAK;AAAA,QACH,KAAK;AAAA,QACL,OAAOc,IAAW,KAAK;AAAA,QACvB,YAAYA,IAAW,KAAK;AAAA,QAC5B,UAAUA,IAAW,KAAK;AAAA,MAAA;AAAA,MAE5B,MAAM;AAAA,QACJ,QAAQ,MAAMF;AAAA,QACd,OAAO,MAAMD;AAAA,MAAA;AAAA,IACf,CACD;AAED,IAAAI,EAAE,SAASZ,EAAa,OAA6C,GACrED,EAAe,UAAUa;AAAA,EAC3B,GAAG,CAACR,CAAmB,CAAC;AAGxB,SAAAU,EAAU,MAAM;AACd,QAAI,CAACjB,EAAa,QAAS;AAE3B,QAAIkB,IAAkB;AAEtB,UAAMC,IAAmB,MAAM;AAC7B,UAAID,GAAiB;AACnB,QAAAA,IAAkB,IAClBZ,EAAkB,UAAUC,EAAA;AAC5B;AAAA,MACF;AAEA,YAAMa,IAAgBb,EAAA,GAChBc,IAAiBf,EAAkB,SACnCgB,IAAY,KAAK,IAAID,EAAe,QAAQD,EAAc,KAAK,GAC/DG,IAAa,KAAK,IAAIF,EAAe,SAASD,EAAc,MAAM;AAExE,MAAIE,IAAY,MAAMC,IAAa,OAEnCjB,EAAkB,UAAUc,GAExBf,EAAiB,WACnB,aAAaA,EAAiB,OAAO,GAGvCA,EAAiB,UAAU,OAAO,WAAW,MAAM;AACjD,QAAIF,EAAa,WACfU,EAAA;AAAA,MAEJ,GAAG,GAAG;AAAA,IACR;AAEA,WAAAT,EAAkB,UAAU,IAAI,eAAe,MAAM;AACnD,MAAAe,EAAA;AAAA,IACF,CAAC,GAEDf,EAAkB,QAAQ,QAAQJ,EAAa,OAAO,GAE/C,MAAM;AACX,MAAII,EAAkB,WACpBA,EAAkB,QAAQ,WAAA,GAExBC,EAAiB,WACnB,aAAaA,EAAiB,OAAO;AAAA,IAEzC;AAAA,EACF,GAAG,CAACE,GAAqBM,CAAgB,CAAC,GAE1CI,EAAU,MAAM;AACd,QAAIO,IAAY;AAEhB,UAAMC,IAAY,YAAY;AAC5B,UAAKzB,EAAa,SAElB;AAAA,QAAAJ,EAAW,EAAI,GACfG,EAAS,IAAI;AAEb,YAAI;AACF,gBAAM2B,IAAW,MAAM,MAAMlC,GAAK;AAAA,YAChC,MAAM;AAAA,YACN,aAAa;AAAA,YACb,UAAU;AAAA,UAAA,CACX;AAED,cAAI,CAACkC,EAAS;AACZ,kBAAIA,EAAS,WAAW,MAChB,IAAI,MAAMjC,EAAE,gBAAgB,CAAC,IAC1BiC,EAAS,WAAW,MACvB,IAAI,MAAM,UAAU,IAEpB,IAAI,MAAM,WAAWA,EAAS,MAAM,GAAG;AAIjD,gBAAMC,IAAc,MAAMD,EAAS,YAAA;AAEnC,cAAIC,EAAY,eAAe;AAC7B,kBAAM,IAAI,MAAM,MAAM;AAIxB,gBAAMC,IAAW,IAAIC,EAAQ,SAAA;AAC7B,gBAAMD,EAAS,KAAK,KAAKD,CAAW;AAGpC,gBAAMG,IAAYC,EAAiCH,CAAQ;AAE3D,cAAI,CAACJ,EAAW;AAEhB,UAAArB,EAAa,UAAU2B,GAGvBjB,EAAA,GAEAjB,EAAW,EAAK;AAAA,QAClB,SAASoC,GAAK;AACZ,cAAIR,GAAW;AACb,oBAAQ,MAAM,eAAeQ,CAAG;AAChC,gBAAIC,IAAWxC,EAAE,mBAAmB;AACpC,YAAIuC,aAAe,UACjBC,IAAWD,EAAI,UAEjBjC,EAASkC,CAAQ,GACjBrC,EAAW,EAAK;AAAA,UAClB;AAAA,QACF;AAAA;AAAA,IACF,GAEMsC,IAAQ,WAAW,MAAM;AAC7B,4BAAsB,MAAM;AAC1B,QAAAT,EAAA;AAAA,MACF,CAAC;AAAA,IACH,GAAG,GAAG;AAEN,WAAO,MAAM;AACX,MAAAD,IAAY,IACZ,aAAaU,CAAK,GAClB/B,EAAa,UAAU,MACnBH,EAAa,YACfA,EAAa,QAAQ,YAAY,KAEnCE,EAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAACV,GAAKqB,CAAgB,CAAC,GAGxB,gBAAAsB,EAAC,OAAA,EAAI,WAAU,6EAEZ,UAAA;AAAA,IAAAxC,uBACE,OAAA,EAAI,WAAU,8HACb,UAAA,gBAAAwC,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,MAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,iKAAA,CAAiK;AAAA,wBAC/K,KAAA,EAAE,WAAU,oEAAoE,UAAA3C,EAAE,cAAc,EAAA,CAAE;AAAA,IAAA,EAAA,CACrG,EAAA,CACF;AAAA,IAIDK,KAAS,CAACH,KACT,gBAAAyC,EAAC,OAAA,EAAI,WAAU,8HACb,UAAA,gBAAAD,EAAC,OAAA,EAAI,WAAU,yDACb,UAAA;AAAA,MAAA,gBAAAC,EAAC,SAAI,WAAU,0PACb,4BAACC,GAAA,EAAgB,WAAU,iEAAgE,EAAA,CAC7F;AAAA,wBACC,KAAA,EAAE,WAAU,uFAAuF,UAAA5C,EAAE,kBAAkB,GAAE;AAAA,MAC1H,gBAAA2C,EAAC,KAAA,EAAE,WAAU,wEACV,UAAAtC,GACH;AAAA,MACA,gBAAAqC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAM3C;AAAA,UACN,UAAQ;AAAA,UACR,WAAU;AAAA,UAEV,UAAA;AAAA,YAAA,gBAAA4C,EAAC,SAAI,WAAU,yCAAwC,MAAK,QAAO,QAAO,gBAAe,SAAQ,aAC/F,4BAAC,QAAA,EAAK,eAAc,SAAQ,gBAAe,SAAQ,aAAa,GAAG,GAAE,kEAAiE,EAAA,CACxI;AAAA,YACC3C,EAAE,iBAAiB;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEtB,gBAAA2C,EAAC,KAAA,EAAE,WAAU,sDAAqD,UAAA,mCAAA,CAElE;AAAA,IAAA,EAAA,CACF,EAAA,CACF;AAAA,IAID,CAACtC,KACA,gBAAAsC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKpC;AAAA,QACL,WAAU;AAAA,QACV,OAAO,EAAE,SAASL,IAAU,IAAI,EAAA;AAAA,MAAE;AAAA,IAAA;AAAA,EACpC,GAEJ;AAEJ;"}
@@ -0,0 +1,99 @@
1
+ import { jsx as r, jsxs as t, Fragment as y } from "react/jsx-runtime";
2
+ import { useState as c, useEffect as w, useMemo as k } from "react";
3
+ import { u as j, b as T, x as n, h as _ } from "./index-LNXbKjrI.mjs";
4
+ const $ = {
5
+ srt: "srt",
6
+ vtt: "vtt",
7
+ lrc: "lrc",
8
+ elrc: "elrc",
9
+ ass: "ass",
10
+ ssa: "ssa",
11
+ ttml: "ttml",
12
+ dfxp: "ttml"
13
+ }, E = (s) => {
14
+ var p;
15
+ const a = ((p = s.split(".").pop()) == null ? void 0 : p.toLowerCase()) || "";
16
+ return $[a];
17
+ }, R = ({ url: s, fileName: a }) => {
18
+ const p = j(), [o, b] = c(""), [h, m] = c(!0), [x, u] = c(null);
19
+ w(() => {
20
+ (async () => {
21
+ try {
22
+ m(!0), u(null), b(await _(s));
23
+ } catch (l) {
24
+ console.error(l), u(p("subtitle.load_failed"));
25
+ } finally {
26
+ m(!1);
27
+ }
28
+ })();
29
+ }, [s]);
30
+ const f = k(() => {
31
+ if (!o) return null;
32
+ try {
33
+ return T(o, E(a));
34
+ } catch (e) {
35
+ return console.error(e), null;
36
+ }
37
+ }, [o, a]);
38
+ if (h)
39
+ return /* @__PURE__ */ r("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-bg-[#0f0f12]", children: /* @__PURE__ */ r("div", { className: "rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) });
40
+ if (x || !f)
41
+ return /* @__PURE__ */ r("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-bg-[#0f0f12]", children: /* @__PURE__ */ r("div", { className: "rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ r("p", { className: "rfp-text-lg", children: x || p("subtitle.parse_failed") }) }) });
42
+ const i = f.format === "lrc" || f.format === "elrc", g = f.metadata ?? {}, v = i ? "group-hover:rfp-bg-violet-400" : "group-hover:rfp-bg-sky-400";
43
+ return /* @__PURE__ */ t("div", { className: "rfp-relative rfp-w-full rfp-h-full rfp-bg-[#0f0f12]", children: [
44
+ /* @__PURE__ */ r("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-px-6 md:rfp-px-10 rfp-pt-6 rfp-pb-16 md:rfp-pb-20", children: /* @__PURE__ */ t("div", { className: "rfp-relative rfp-max-w-5xl rfp-mx-auto", children: [
45
+ /* @__PURE__ */ r("div", { className: "rfp-absolute rfp-left-[5px] md:rfp-left-[7px] rfp-top-2 rfp-bottom-2 rfp-w-px rfp-bg-surface-1" }),
46
+ /* @__PURE__ */ r("ol", { className: "rfp-space-y-5 md:rfp-space-y-6", children: f.cues.map((e, l) => /* @__PURE__ */ t("li", { className: "rfp-relative rfp-pl-6 md:rfp-pl-8 rfp-group", children: [
47
+ /* @__PURE__ */ r(
48
+ "div",
49
+ {
50
+ className: `rfp-absolute rfp-left-0 rfp-top-2 rfp-w-3 rfp-h-3 rfp-rounded-full rfp-bg-surface-3 rfp-border-2 rfp-border-[#0f0f12] rfp-transition-colors ${v}`
51
+ }
52
+ ),
53
+ /* @__PURE__ */ t("div", { className: "rfp-flex rfp-flex-wrap rfp-items-baseline rfp-gap-x-3 rfp-gap-y-1 rfp-mb-1.5", children: [
54
+ /* @__PURE__ */ r("span", { className: "rfp-text-[11px] rfp-font-mono rfp-text-fg-muted rfp-tabular-nums", children: n(e.start) }),
55
+ /* @__PURE__ */ r("span", { className: "rfp-text-[11px] rfp-text-fg-disabled", children: "→" }),
56
+ /* @__PURE__ */ r("span", { className: "rfp-text-[11px] rfp-font-mono rfp-text-fg-muted rfp-tabular-nums", children: n(e.end) }),
57
+ /* @__PURE__ */ t("span", { className: "rfp-text-[10px] rfp-font-mono rfp-text-fg-disabled rfp-tabular-nums", children: [
58
+ "#",
59
+ e.id ?? l + 1
60
+ ] }),
61
+ e.style && /* @__PURE__ */ r("span", { className: "rfp-text-[9px] rfp-uppercase rfp-tracking-widest rfp-text-fg-tertiary rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-bg-surface-1 rfp-border rfp-border-line-weak", children: e.style })
62
+ ] }),
63
+ e.words && e.words.length > 0 ? /* @__PURE__ */ r("div", { className: "rfp-flex rfp-flex-wrap rfp-gap-x-1.5 rfp-gap-y-1 rfp-text-base md:rfp-text-lg rfp-text-fg-primary rfp-leading-relaxed group-hover:rfp-text-fg-primary rfp-transition-colors", children: e.words.map((d, N) => /* @__PURE__ */ t(
64
+ "span",
65
+ {
66
+ className: "rfp-inline-flex rfp-flex-col rfp-items-start",
67
+ title: n(d.start),
68
+ children: [
69
+ /* @__PURE__ */ r("span", { className: "rfp-text-[9px] rfp-text-fg-disabled rfp-font-mono rfp-leading-none rfp-tabular-nums", children: n(d.start).slice(3, 8) }),
70
+ /* @__PURE__ */ r("span", { className: "rfp-leading-snug", children: d.text })
71
+ ]
72
+ },
73
+ `w-${N}`
74
+ )) }) : /* @__PURE__ */ r(
75
+ "p",
76
+ {
77
+ className: `rfp-whitespace-pre-wrap rfp-break-words rfp-leading-relaxed group-hover:rfp-text-fg-primary rfp-transition-colors rfp-text-fg-primary ${i ? "rfp-text-base md:rfp-text-xl rfp-font-medium" : "rfp-text-sm md:rfp-text-base"}`,
78
+ children: e.text
79
+ }
80
+ )
81
+ ] }, `cue-${l}`)) })
82
+ ] }) }),
83
+ /* @__PURE__ */ t("div", { className: "rfp-pointer-events-none rfp-absolute rfp-bottom-3 rfp-right-3 md:rfp-bottom-4 md:rfp-right-4 rfp-flex rfp-items-center rfp-gap-2 rfp-px-2.5 rfp-py-1 rfp-rounded-full rfp-bg-surface-nav rfp-backdrop-blur rfp-border rfp-border-line-weak rfp-text-[10px] rfp-text-fg-tertiary rfp-font-mono rfp-tabular-nums", children: [
84
+ /* @__PURE__ */ t("span", { children: [
85
+ f.cues.length,
86
+ " ",
87
+ p(i ? "subtitle.lines" : "subtitle.cues")
88
+ ] }),
89
+ g.length && /* @__PURE__ */ t(y, { children: [
90
+ /* @__PURE__ */ r("span", { className: "rfp-text-fg-disabled", children: "·" }),
91
+ /* @__PURE__ */ r("span", { children: g.length })
92
+ ] })
93
+ ] })
94
+ ] });
95
+ };
96
+ export {
97
+ R as SubtitleRenderer
98
+ };
99
+ //# sourceMappingURL=index-CQABwGVP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CQABwGVP.mjs","sources":["../../src/renderers/Subtitle/index.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport {\n parseSubtitle,\n formatSubtitleTime,\n fetchTextUtf8,\n type SubtitleParseResult,\n type SubtitleFormat,\n} from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface SubtitleRendererProps {\n url: string;\n fileName: string;\n}\n\nconst FORMAT_BY_EXT: Record<string, SubtitleFormat> = {\n srt: 'srt',\n vtt: 'vtt',\n lrc: 'lrc',\n elrc: 'elrc',\n ass: 'ass',\n ssa: 'ssa',\n ttml: 'ttml',\n dfxp: 'ttml',\n};\n\nconst getFormat = (fileName: string): SubtitleFormat | undefined => {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n return FORMAT_BY_EXT[ext];\n};\n\nexport const SubtitleRenderer: React.FC<SubtitleRendererProps> = ({ url, fileName }) => {\n const t = useTranslator();\n const [text, setText] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const load = async () => {\n try {\n setLoading(true);\n setError(null);\n setText(await fetchTextUtf8(url));\n } catch (err) {\n console.error(err);\n setError(t('subtitle.load_failed'));\n } finally {\n setLoading(false);\n }\n };\n load();\n }, [url]);\n\n const parsed: SubtitleParseResult | null = useMemo(() => {\n if (!text) return null;\n try {\n return parseSubtitle(text, getFormat(fileName));\n } catch (err) {\n console.error(err);\n return null;\n }\n }, [text, fileName]);\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-bg-[#0f0f12]\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n );\n }\n\n if (error || !parsed) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-bg-[#0f0f12]\">\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error || t('subtitle.parse_failed')}</p>\n </div>\n </div>\n );\n }\n\n const isLyric = parsed.format === 'lrc' || parsed.format === 'elrc';\n const meta = parsed.metadata ?? {};\n const dotHover = isLyric ? 'group-hover:rfp-bg-violet-400' : 'group-hover:rfp-bg-sky-400';\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-bg-[#0f0f12]\">\n {/* 内容滚动区 */}\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-px-6 md:rfp-px-10 rfp-pt-6 rfp-pb-16 md:rfp-pb-20\">\n <div className=\"rfp-relative rfp-max-w-5xl rfp-mx-auto\">\n {/* vertical line */}\n <div className=\"rfp-absolute rfp-left-[5px] md:rfp-left-[7px] rfp-top-2 rfp-bottom-2 rfp-w-px rfp-bg-surface-1\" />\n\n <ol className=\"rfp-space-y-5 md:rfp-space-y-6\">\n {parsed.cues.map((cue, i) => (\n <li key={`cue-${i}`} className=\"rfp-relative rfp-pl-6 md:rfp-pl-8 rfp-group\">\n {/* dot */}\n <div\n className={`rfp-absolute rfp-left-0 rfp-top-2 rfp-w-3 rfp-h-3 rfp-rounded-full rfp-bg-surface-3 rfp-border-2 rfp-border-[#0f0f12] rfp-transition-colors ${dotHover}`}\n />\n\n <div className=\"rfp-flex rfp-flex-wrap rfp-items-baseline rfp-gap-x-3 rfp-gap-y-1 rfp-mb-1.5\">\n <span className=\"rfp-text-[11px] rfp-font-mono rfp-text-fg-muted rfp-tabular-nums\">\n {formatSubtitleTime(cue.start)}\n </span>\n <span className=\"rfp-text-[11px] rfp-text-fg-disabled\">→</span>\n <span className=\"rfp-text-[11px] rfp-font-mono rfp-text-fg-muted rfp-tabular-nums\">\n {formatSubtitleTime(cue.end)}\n </span>\n <span className=\"rfp-text-[10px] rfp-font-mono rfp-text-fg-disabled rfp-tabular-nums\">\n #{cue.id ?? i + 1}\n </span>\n {cue.style && (\n <span className=\"rfp-text-[9px] rfp-uppercase rfp-tracking-widest rfp-text-fg-tertiary rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-bg-surface-1 rfp-border rfp-border-line-weak\">\n {cue.style}\n </span>\n )}\n </div>\n\n {cue.words && cue.words.length > 0 ? (\n <div className=\"rfp-flex rfp-flex-wrap rfp-gap-x-1.5 rfp-gap-y-1 rfp-text-base md:rfp-text-lg rfp-text-fg-primary rfp-leading-relaxed group-hover:rfp-text-fg-primary rfp-transition-colors\">\n {cue.words.map((word, wi) => (\n <span\n key={`w-${wi}`}\n className=\"rfp-inline-flex rfp-flex-col rfp-items-start\"\n title={formatSubtitleTime(word.start)}\n >\n <span className=\"rfp-text-[9px] rfp-text-fg-disabled rfp-font-mono rfp-leading-none rfp-tabular-nums\">\n {formatSubtitleTime(word.start).slice(3, 8)}\n </span>\n <span className=\"rfp-leading-snug\">{word.text}</span>\n </span>\n ))}\n </div>\n ) : (\n <p\n className={`rfp-whitespace-pre-wrap rfp-break-words rfp-leading-relaxed group-hover:rfp-text-fg-primary rfp-transition-colors rfp-text-fg-primary ${\n isLyric ? 'rfp-text-base md:rfp-text-xl rfp-font-medium' : 'rfp-text-sm md:rfp-text-base'\n }`}\n >\n {cue.text}\n </p>\n )}\n </li>\n ))}\n </ol>\n </div>\n </div>\n\n {/* 底部状态栏 */}\n <div className=\"rfp-pointer-events-none rfp-absolute rfp-bottom-3 rfp-right-3 md:rfp-bottom-4 md:rfp-right-4 rfp-flex rfp-items-center rfp-gap-2 rfp-px-2.5 rfp-py-1 rfp-rounded-full rfp-bg-surface-nav rfp-backdrop-blur rfp-border rfp-border-line-weak rfp-text-[10px] rfp-text-fg-tertiary rfp-font-mono rfp-tabular-nums\">\n <span>{parsed.cues.length} {isLyric ? t('subtitle.lines') : t('subtitle.cues')}</span>\n {meta.length && (\n <>\n <span className=\"rfp-text-fg-disabled\">·</span>\n <span>{meta.length}</span>\n </>\n )}\n </div>\n </div>\n );\n};\n"],"names":["FORMAT_BY_EXT","getFormat","fileName","ext","_a","SubtitleRenderer","url","t","useTranslator","text","setText","useState","loading","setLoading","error","setError","useEffect","fetchTextUtf8","err","parsed","useMemo","parseSubtitle","jsx","isLyric","meta","dotHover","jsxs","cue","i","formatSubtitleTime","word","wi","Fragment"],"mappings":";;;AAeA,MAAMA,IAAgD;AAAA,EACpD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AACR,GAEMC,IAAY,CAACC,MAAiD;;AAClE,QAAMC,MAAMC,IAAAF,EAAS,MAAM,GAAG,EAAE,IAAA,MAApB,gBAAAE,EAA2B,kBAAiB;AACxD,SAAOJ,EAAcG,CAAG;AAC1B,GAEaE,IAAoD,CAAC,EAAE,KAAAC,GAAK,UAAAJ,QAAe;AACtF,QAAMK,IAAIC,EAAA,GACJ,CAACC,GAAMC,CAAO,IAAIC,EAAiB,EAAE,GACrC,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAI,GACrC,CAACG,GAAOC,CAAQ,IAAIJ,EAAwB,IAAI;AAEtD,EAAAK,EAAU,MAAM;AAad,KAZa,YAAY;AACvB,UAAI;AACF,QAAAH,EAAW,EAAI,GACfE,EAAS,IAAI,GACbL,EAAQ,MAAMO,EAAcX,CAAG,CAAC;AAAA,MAClC,SAASY,GAAK;AACZ,gBAAQ,MAAMA,CAAG,GACjBH,EAASR,EAAE,sBAAsB,CAAC;AAAA,MACpC,UAAA;AACE,QAAAM,EAAW,EAAK;AAAA,MAClB;AAAA,IACF,GACA;AAAA,EACF,GAAG,CAACP,CAAG,CAAC;AAER,QAAMa,IAAqCC,EAAQ,MAAM;AACvD,QAAI,CAACX,EAAM,QAAO;AAClB,QAAI;AACF,aAAOY,EAAcZ,GAAMR,EAAUC,CAAQ,CAAC;AAAA,IAChD,SAASgB,GAAK;AACZ,qBAAQ,MAAMA,CAAG,GACV;AAAA,IACT;AAAA,EACF,GAAG,CAACT,GAAMP,CAAQ,CAAC;AAEnB,MAAIU;AACF,WACE,gBAAAU,EAAC,SAAI,WAAU,uFACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI;AAIJ,MAAIR,KAAS,CAACK;AACZ,6BACG,OAAA,EAAI,WAAU,uFACb,UAAA,gBAAAG,EAAC,SAAI,WAAU,yCACb,UAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,eAAe,UAAAR,KAASP,EAAE,uBAAuB,GAAE,GAClE,EAAA,CACF;AAIJ,QAAMgB,IAAUJ,EAAO,WAAW,SAASA,EAAO,WAAW,QACvDK,IAAOL,EAAO,YAAY,CAAA,GAC1BM,IAAWF,IAAU,kCAAkC;AAE7D,SACE,gBAAAG,EAAC,OAAA,EAAI,WAAU,uDAEb,UAAA;AAAA,IAAA,gBAAAJ,EAAC,SAAI,WAAU,iGACb,UAAA,gBAAAI,EAAC,OAAA,EAAI,WAAU,0CAEb,UAAA;AAAA,MAAA,gBAAAJ,EAAC,OAAA,EAAI,WAAU,iGAAA,CAAiG;AAAA,MAEhH,gBAAAA,EAAC,MAAA,EAAG,WAAU,kCACX,UAAAH,EAAO,KAAK,IAAI,CAACQ,GAAKC,MACrB,gBAAAF,EAAC,MAAA,EAAoB,WAAU,+CAE7B,UAAA;AAAA,QAAA,gBAAAJ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,+IAA+IG,CAAQ;AAAA,UAAA;AAAA,QAAA;AAAA,QAGpK,gBAAAC,EAAC,OAAA,EAAI,WAAU,gFACb,UAAA;AAAA,UAAA,gBAAAJ,EAAC,UAAK,WAAU,oEACb,UAAAO,EAAmBF,EAAI,KAAK,GAC/B;AAAA,UACA,gBAAAL,EAAC,QAAA,EAAK,WAAU,wCAAuC,UAAA,KAAC;AAAA,4BACvD,QAAA,EAAK,WAAU,oEACb,UAAAO,EAAmBF,EAAI,GAAG,GAC7B;AAAA,UACA,gBAAAD,EAAC,QAAA,EAAK,WAAU,uEAAsE,UAAA;AAAA,YAAA;AAAA,YAClFC,EAAI,MAAMC,IAAI;AAAA,UAAA,GAClB;AAAA,UACCD,EAAI,SACH,gBAAAL,EAAC,UAAK,WAAU,4JACb,YAAI,MAAA,CACP;AAAA,QAAA,GAEJ;AAAA,QAECK,EAAI,SAASA,EAAI,MAAM,SAAS,IAC/B,gBAAAL,EAAC,OAAA,EAAI,WAAU,+KACZ,UAAAK,EAAI,MAAM,IAAI,CAACG,GAAMC,MACpB,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAOG,EAAmBC,EAAK,KAAK;AAAA,YAEpC,UAAA;AAAA,cAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,uFACb,UAAAO,EAAmBC,EAAK,KAAK,EAAE,MAAM,GAAG,CAAC,EAAA,CAC5C;AAAA,cACA,gBAAAR,EAAC,QAAA,EAAK,WAAU,oBAAoB,YAAK,KAAA,CAAK;AAAA,YAAA;AAAA,UAAA;AAAA,UAPzC,KAAKS,CAAE;AAAA,QAAA,CASf,GACH,IAEA,gBAAAT;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,yIACTC,IAAU,iDAAiD,8BAC7D;AAAA,YAEC,UAAAI,EAAI;AAAA,UAAA;AAAA,QAAA;AAAA,MACP,EAAA,GA9CK,OAAOC,CAAC,EAgDjB,CACD,EAAA,CACH;AAAA,IAAA,EAAA,CACF,EAAA,CACF;AAAA,IAGA,gBAAAF,EAAC,OAAA,EAAI,WAAU,kTACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,QAAA,EAAM,UAAA;AAAA,QAAAP,EAAO,KAAK;AAAA,QAAO;AAAA,QAAYZ,EAAVgB,IAAY,mBAAsB,eAAN;AAAA,MAAqB,GAAE;AAAA,MAC9EC,EAAK,UACJ,gBAAAE,EAAAM,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAV,EAAC,QAAA,EAAK,WAAU,wBAAuB,UAAA,KAAC;AAAA,QACxC,gBAAAA,EAAC,QAAA,EAAM,UAAAE,EAAK,OAAA,CAAO;AAAA,MAAA,EAAA,CACrB;AAAA,IAAA,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ;"}
@@ -0,0 +1,96 @@
1
+ import { jsx as e, jsxs as a } from "react/jsx-runtime";
2
+ import { useState as u, useRef as v, useEffect as g } from "react";
3
+ import x from "video.js";
4
+ import { u as y } from "./index-LNXbKjrI.mjs";
5
+ const b = (r) => {
6
+ var s;
7
+ const o = ((s = r.split(".").pop()) == null ? void 0 : s.toLowerCase().split("?")[0]) || "";
8
+ return {
9
+ mp4: "video/mp4",
10
+ webm: "video/webm",
11
+ ogg: "video/ogg",
12
+ ogv: "video/ogg",
13
+ mov: "video/quicktime",
14
+ // MOV 使用 QuickTime MIME 类型
15
+ avi: "video/x-msvideo",
16
+ mkv: "video/x-matroska",
17
+ m4v: "video/mp4",
18
+ "3gp": "video/3gpp",
19
+ flv: "video/x-flv"
20
+ }[o] || "video/mp4";
21
+ }, L = ({ url: r }) => {
22
+ const o = y(), [f, s] = u(null), [h, d] = u(!0), n = v(null), l = v(null);
23
+ return g(() => {
24
+ if (!l.current && n.current) {
25
+ const t = document.createElement("video-js");
26
+ t.classList.add("vjs-big-play-centered", "vjs-theme-apple"), n.current.appendChild(t);
27
+ const c = b(r), i = x(t, {
28
+ controls: !0,
29
+ fill: !0,
30
+ preload: "auto",
31
+ controlBar: {
32
+ children: [
33
+ "playToggle",
34
+ "volumePanel",
35
+ "currentTimeDisplay",
36
+ "timeDivider",
37
+ "durationDisplay",
38
+ "progressControl",
39
+ "remainingTimeDisplay",
40
+ "fullscreenToggle"
41
+ ],
42
+ volumePanel: {
43
+ inline: !1
44
+ }
45
+ },
46
+ html5: {
47
+ vhs: {
48
+ overrideNative: !0
49
+ },
50
+ nativeVideoTracks: !1,
51
+ nativeAudioTracks: !1,
52
+ nativeTextTracks: !1
53
+ },
54
+ sources: c === "video/quicktime" ? [
55
+ { src: r, type: "video/quicktime" },
56
+ { src: r, type: "video/mp4" }
57
+ // 备用方案
58
+ ] : [{ src: r, type: c }]
59
+ }), m = i.el().querySelector("video");
60
+ m && (m.style.objectFit = "contain"), i.on("loadeddata", () => {
61
+ d(!1);
62
+ }), i.on("error", () => {
63
+ const p = i.error();
64
+ console.error("Video.js error:", p), s(o("video.load_failed_with_error", { error: (p == null ? void 0 : p.message) || o("common.unknown_error") })), d(!1);
65
+ }), l.current = i;
66
+ }
67
+ }, [r]), g(() => {
68
+ const t = l.current;
69
+ return () => {
70
+ t && !t.isDisposed() && (t.dispose(), l.current = null);
71
+ };
72
+ }, []), f ? /* @__PURE__ */ e("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ a("div", { className: "rfp-text-center", children: [
73
+ /* @__PURE__ */ e("div", { className: "rfp-w-16 rfp-h-16 rfp-mx-auto rfp-mb-4 rfp-rounded-full rfp-bg-red-500/10 rfp-flex rfp-items-center rfp-justify-center", children: /* @__PURE__ */ e("svg", { className: "rfp-w-8 rfp-h-8 rfp-text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ e("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" }) }) }),
74
+ /* @__PURE__ */ e("p", { className: "rfp-text-lg rfp-font-medium rfp-text-fg-primary rfp-mb-2", children: o("video.load_failed") }),
75
+ /* @__PURE__ */ e("p", { className: "rfp-text-sm rfp-text-fg-tertiary", children: f })
76
+ ] }) }) : /* @__PURE__ */ e("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ a("div", { className: "rfp-w-full rfp-h-full rfp-relative", children: [
77
+ h && /* @__PURE__ */ e("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-3 rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ a("div", { className: "rfp-text-center", children: [
78
+ /* @__PURE__ */ e("div", { className: "rfp-w-12 rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-3 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }),
79
+ /* @__PURE__ */ e("p", { className: "rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: o("video.loading") })
80
+ ] }) }),
81
+ /* @__PURE__ */ e(
82
+ "div",
83
+ {
84
+ ref: n,
85
+ className: "rfp-overflow-hidden rfp-w-full rfp-h-full [&_video]:rfp-object-contain",
86
+ style: {
87
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05)"
88
+ }
89
+ }
90
+ )
91
+ ] }) });
92
+ };
93
+ export {
94
+ L as VideoRenderer
95
+ };
96
+ //# sourceMappingURL=index-DOMMMe9f.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DOMMMe9f.mjs","sources":["../../src/renderers/Video/index.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport videojs from 'video.js';\nimport 'video.js/dist/video-js.css';\nimport { useTranslator } from '../../i18n/LocaleContext';\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 t = useTranslator();\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 fill: 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 const videoEl = player.el().querySelector('video');\n if (videoEl) {\n (videoEl as HTMLVideoElement).style.objectFit = 'contain';\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(t('video.load_failed_with_error', { error: error?.message || t('common.unknown_error') }));\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=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-16 rfp-h-16 rfp-mx-auto rfp-mb-4 rfp-rounded-full rfp-bg-red-500/10 rfp-flex rfp-items-center rfp-justify-center\">\n <svg className=\"rfp-w-8 rfp-h-8 rfp-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=\"rfp-text-lg rfp-font-medium rfp-text-fg-primary rfp-mb-2\">{t('video.load_failed')}</p>\n <p className=\"rfp-text-sm rfp-text-fg-tertiary\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-w-full rfp-h-full rfp-relative\">\n {/* 加载状态 */}\n {isLoading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-3 rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-3 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('video.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 视频播放器容器 */}\n <div\n ref={videoRef}\n className=\"rfp-overflow-hidden rfp-w-full rfp-h-full [&_video]:rfp-object-contain\"\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"],"names":["getVideoType","url","ext","_a","VideoRenderer","t","useTranslator","error","setError","useState","isLoading","setIsLoading","videoRef","useRef","playerRef","useEffect","videoElement","videoType","player","videojs","videoEl","jsxs","jsx"],"mappings":"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"}