@eternalheart/react-file-preview 1.3.9 → 1.3.11

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 (124) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/lib/FilePreviewContent.d.ts.map +1 -1
  4. package/lib/RequestContext.d.ts +1 -1
  5. package/lib/RequestContext.d.ts.map +1 -1
  6. package/lib/chunks/RendererError-BH6fzLrN.mjs +15 -0
  7. package/lib/chunks/RendererError-BH6fzLrN.mjs.map +1 -0
  8. package/lib/chunks/avifLoader-BP3fgcMm-BnpxLhxp.mjs +56 -0
  9. package/lib/chunks/avifLoader-BP3fgcMm-BnpxLhxp.mjs.map +1 -0
  10. package/lib/chunks/heicLoader-CH_raQNn-1fBLaICM.mjs +37 -0
  11. package/lib/chunks/heicLoader-CH_raQNn-1fBLaICM.mjs.map +1 -0
  12. package/lib/chunks/index-B57rEPin.mjs +54 -0
  13. package/lib/chunks/index-B57rEPin.mjs.map +1 -0
  14. package/lib/chunks/index-BCuRRLYt.mjs +222 -0
  15. package/lib/chunks/index-BCuRRLYt.mjs.map +1 -0
  16. package/lib/chunks/{index-BSD3w5eG.mjs → index-BJ6vTNxc.mjs} +76 -75
  17. package/lib/chunks/index-BJ6vTNxc.mjs.map +1 -0
  18. package/lib/chunks/index-BYdqrqnR.mjs +161 -0
  19. package/lib/chunks/index-BYdqrqnR.mjs.map +1 -0
  20. package/lib/chunks/index-BiyghBxu.mjs +136 -0
  21. package/lib/chunks/index-BiyghBxu.mjs.map +1 -0
  22. package/lib/chunks/{index-DdOEWhrk.mjs → index-C8CyS_sj.mjs} +66 -63
  23. package/lib/chunks/index-C8CyS_sj.mjs.map +1 -0
  24. package/lib/chunks/index-C8OrFLd5.mjs +594 -0
  25. package/lib/chunks/index-C8OrFLd5.mjs.map +1 -0
  26. package/lib/chunks/{index-DGuiWJr7.mjs → index-CCkHAeLh.mjs} +40 -37
  27. package/lib/chunks/index-CCkHAeLh.mjs.map +1 -0
  28. package/lib/chunks/index-CdmkF0CO.mjs +105 -0
  29. package/lib/chunks/index-CdmkF0CO.mjs.map +1 -0
  30. package/lib/chunks/index-CuAALtwC.mjs +2299 -0
  31. package/lib/chunks/index-CuAALtwC.mjs.map +1 -0
  32. package/lib/chunks/index-D660ENHx.mjs +114 -0
  33. package/lib/chunks/index-D660ENHx.mjs.map +1 -0
  34. package/lib/chunks/{index-DV5Jd7Qe.mjs → index-DBEG73K1.mjs} +79 -78
  35. package/lib/chunks/index-DBEG73K1.mjs.map +1 -0
  36. package/lib/chunks/index-DaFlk9dd.mjs +13097 -0
  37. package/lib/chunks/index-DaFlk9dd.mjs.map +1 -0
  38. package/lib/chunks/index-_mP0FkqE.mjs +113 -0
  39. package/lib/chunks/index-_mP0FkqE.mjs.map +1 -0
  40. package/lib/chunks/{index-U3w45GW8.mjs → index-nLTQXCV7.mjs} +84 -82
  41. package/lib/chunks/index-nLTQXCV7.mjs.map +1 -0
  42. package/lib/chunks/index-nVblatyi.mjs +55 -0
  43. package/lib/chunks/index-nVblatyi.mjs.map +1 -0
  44. package/lib/chunks/{index-zEVVgWCH.mjs → index-ow-nGpuu.mjs} +99 -98
  45. package/lib/chunks/index-ow-nGpuu.mjs.map +1 -0
  46. package/lib/chunks/index-qOC5xQyK.mjs +96 -0
  47. package/lib/chunks/index-qOC5xQyK.mjs.map +1 -0
  48. package/lib/chunks/index-rUfsiVR8.mjs +12335 -0
  49. package/lib/chunks/index-rUfsiVR8.mjs.map +1 -0
  50. package/lib/chunks/jp2Loader-Bn-qPMbD-Bn-qPMbD.mjs +122 -0
  51. package/lib/chunks/jp2Loader-Bn-qPMbD-Bn-qPMbD.mjs.map +1 -0
  52. package/lib/chunks/psdLoader-Doxw3mWm-DVOGFSlh.mjs +73 -0
  53. package/lib/chunks/psdLoader-Doxw3mWm-DVOGFSlh.mjs.map +1 -0
  54. package/lib/chunks/rawLoader-0mLvxCNp-CJmERiK7.mjs +82 -0
  55. package/lib/chunks/rawLoader-0mLvxCNp-CJmERiK7.mjs.map +1 -0
  56. package/lib/chunks/tiffLoader-CTFKVLqJ-B84NfwhR.mjs +60 -0
  57. package/lib/chunks/tiffLoader-CTFKVLqJ-B84NfwhR.mjs.map +1 -0
  58. package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs → useShikiHighlight-ClbUXJ2p.mjs} +3 -3
  59. package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs.map → useShikiHighlight-ClbUXJ2p.mjs.map} +1 -1
  60. package/lib/index.cjs +33 -20
  61. package/lib/index.cjs.map +1 -1
  62. package/lib/index.css +1 -1
  63. package/lib/index.d.ts +1 -0
  64. package/lib/index.d.ts.map +1 -1
  65. package/lib/index.mjs +14 -13
  66. package/lib/renderers/Audio/index.d.ts.map +1 -1
  67. package/lib/renderers/Csv/index.d.ts.map +1 -1
  68. package/lib/renderers/Docx/index.d.ts.map +1 -1
  69. package/lib/renderers/Epub/index.d.ts.map +1 -1
  70. package/lib/renderers/Font/index.d.ts +6 -0
  71. package/lib/renderers/Font/index.d.ts.map +1 -0
  72. package/lib/renderers/Image/index.d.ts +2 -0
  73. package/lib/renderers/Image/index.d.ts.map +1 -1
  74. package/lib/renderers/Json/index.d.ts.map +1 -1
  75. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  76. package/lib/renderers/Mobi/index.d.ts.map +1 -1
  77. package/lib/renderers/Msg/index.d.ts.map +1 -1
  78. package/lib/renderers/Pdf/index.d.ts +0 -1
  79. package/lib/renderers/Pdf/index.d.ts.map +1 -1
  80. package/lib/renderers/Pptx/index.d.ts.map +1 -1
  81. package/lib/renderers/RendererError.d.ts +8 -0
  82. package/lib/renderers/RendererError.d.ts.map +1 -0
  83. package/lib/renderers/Subtitle/index.d.ts.map +1 -1
  84. package/lib/renderers/Text/index.d.ts.map +1 -1
  85. package/lib/renderers/Video/index.d.ts +1 -0
  86. package/lib/renderers/Video/index.d.ts.map +1 -1
  87. package/lib/renderers/Xlsx/index.d.ts.map +1 -1
  88. package/lib/renderers/Xml/index.d.ts.map +1 -1
  89. package/lib/renderers/Zip/index.d.ts.map +1 -1
  90. package/lib/renderers/lazy.d.ts +2 -0
  91. package/lib/renderers/lazy.d.ts.map +1 -1
  92. package/lib/utils/pdfConfig.d.ts +2 -2
  93. package/lib/utils/pdfConfig.d.ts.map +1 -1
  94. package/package.json +14 -5
  95. package/lib/chunks/index-B-H9HQiI.mjs +0 -110
  96. package/lib/chunks/index-B-H9HQiI.mjs.map +0 -1
  97. package/lib/chunks/index-BGeyzo6u.mjs +0 -96
  98. package/lib/chunks/index-BGeyzo6u.mjs.map +0 -1
  99. package/lib/chunks/index-BNUiNUWa.mjs +0 -103
  100. package/lib/chunks/index-BNUiNUWa.mjs.map +0 -1
  101. package/lib/chunks/index-BSD3w5eG.mjs.map +0 -1
  102. package/lib/chunks/index-BcBe6KW7.mjs +0 -99
  103. package/lib/chunks/index-BcBe6KW7.mjs.map +0 -1
  104. package/lib/chunks/index-BdYkTSTt.mjs +0 -51
  105. package/lib/chunks/index-BdYkTSTt.mjs.map +0 -1
  106. package/lib/chunks/index-BqEuP_8r.mjs +0 -152
  107. package/lib/chunks/index-BqEuP_8r.mjs.map +0 -1
  108. package/lib/chunks/index-Bv93wiEK.mjs +0 -2031
  109. package/lib/chunks/index-Bv93wiEK.mjs.map +0 -1
  110. package/lib/chunks/index-CKirCT35.mjs +0 -52
  111. package/lib/chunks/index-CKirCT35.mjs.map +0 -1
  112. package/lib/chunks/index-CgV8T0G5.mjs +0 -257
  113. package/lib/chunks/index-CgV8T0G5.mjs.map +0 -1
  114. package/lib/chunks/index-D8GtNeDn.mjs +0 -116
  115. package/lib/chunks/index-D8GtNeDn.mjs.map +0 -1
  116. package/lib/chunks/index-DGuiWJr7.mjs.map +0 -1
  117. package/lib/chunks/index-DV5Jd7Qe.mjs.map +0 -1
  118. package/lib/chunks/index-DdOEWhrk.mjs.map +0 -1
  119. package/lib/chunks/index-DmepcY31.mjs +0 -96
  120. package/lib/chunks/index-DmepcY31.mjs.map +0 -1
  121. package/lib/chunks/index-U3w45GW8.mjs.map +0 -1
  122. package/lib/chunks/index-r3q2xCCI.mjs +0 -129
  123. package/lib/chunks/index-r3q2xCCI.mjs.map +0 -1
  124. package/lib/chunks/index-zEVVgWCH.mjs.map +0 -1
@@ -1,96 +0,0 @@
1
- import { jsxs as m, jsx as e } from "react/jsx-runtime";
2
- import { useState as N, useRef as w, useEffect as R, useCallback as L } from "react";
3
- import { Document as H, Page as M } from "react-pdf";
4
- import { u as P } from "./index-Bv93wiEK.mjs";
5
- const q = ({
6
- url: u,
7
- zoom: x,
8
- currentPage: s,
9
- onPageChange: o,
10
- onTotalPagesChange: E,
11
- onPageWidthChange: h
12
- }) => {
13
- const k = P(), [c, D] = N(0), [l, b] = N(null), p = w(null), a = w(/* @__PURE__ */ new Map());
14
- R(() => {
15
- b(null);
16
- }, [u]);
17
- const S = ({ numPages: r }) => {
18
- D(r), E(r), o(1);
19
- }, j = (r) => {
20
- console.error("PDF 加载错误:", r), b(k("pdf.load_failed"));
21
- }, i = L(() => {
22
- if (!p.current) return;
23
- const r = p.current, t = r.scrollTop, f = r.clientHeight, n = t + f / 2;
24
- let d = 1, g = 1 / 0;
25
- a.current.forEach((A, _) => {
26
- const v = A.getBoundingClientRect(), B = r.getBoundingClientRect(), C = v.top - B.top + v.height / 2 + t, y = Math.abs(C - n);
27
- y < g && (g = y, d = _);
28
- }), d !== s && o(d);
29
- }, [s, o]);
30
- R(() => {
31
- const r = p.current;
32
- if (r)
33
- return r.addEventListener("scroll", i), () => r.removeEventListener("scroll", i);
34
- }, [i]);
35
- const T = L((r, t) => {
36
- t ? a.current.set(r, t) : a.current.delete(r);
37
- }, []);
38
- return /* @__PURE__ */ m(
39
- "div",
40
- {
41
- ref: p,
42
- className: "rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-4 md:rfp-py-8 rfp-px-2 md:rfp-px-4",
43
- children: [
44
- l && /* @__PURE__ */ e("div", { className: "rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ e("p", { className: "rfp-text-lg", children: l }) }),
45
- !l && /* @__PURE__ */ e(
46
- H,
47
- {
48
- file: u,
49
- onLoadSuccess: S,
50
- onLoadError: j,
51
- loading: /* @__PURE__ */ e("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen", children: /* @__PURE__ */ e("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" }) }),
52
- children: /* @__PURE__ */ e("div", { className: "rfp-flex rfp-flex-col rfp-gap-4", children: Array.from(new Array(c), (r, t) => {
53
- const f = t + 1;
54
- return /* @__PURE__ */ m(
55
- "div",
56
- {
57
- ref: (n) => T(f, n),
58
- className: "rfp-relative",
59
- children: [
60
- /* @__PURE__ */ e(
61
- M,
62
- {
63
- pageNumber: f,
64
- scale: x,
65
- loading: /* @__PURE__ */ e("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-p-8 rfp-bg-surface-1 rfp-rounded-lg rfp-min-h-[600px]", children: /* @__PURE__ */ e("div", { className: "rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) }),
66
- renderTextLayer: !1,
67
- renderAnnotationLayer: !1,
68
- className: "rfp-shadow-2xl",
69
- onRenderSuccess: (n) => {
70
- f === 1 && h && h(n.originalWidth || n.width / x);
71
- }
72
- }
73
- ),
74
- /* @__PURE__ */ e("div", { className: "rfp-absolute rfp-top-2 rfp-right-2 rfp-bg-surface-nav-hover rfp-backdrop-blur-sm rfp-text-fg-primary rfp-text-xs rfp-px-3 rfp-py-1 rfp-rounded-full", children: f })
75
- ]
76
- },
77
- `page_${f}`
78
- );
79
- }) })
80
- }
81
- ),
82
- c > 0 && /* @__PURE__ */ m("div", { className: "rfp-sticky rfp-bottom-2 md:rfp-bottom-4 rfp-mt-4 md:rfp-mt-8 rfp-bg-surface-nav-hover rfp-backdrop-blur-xl rfp-text-fg-primary rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-rounded-full rfp-text-xs md:rfp-text-sm rfp-font-medium rfp-shadow-2xl rfp-border rfp-border-line-weak", children: [
83
- "第 ",
84
- s,
85
- " 页 / 共 ",
86
- c,
87
- " 页"
88
- ] })
89
- ]
90
- }
91
- );
92
- };
93
- export {
94
- q as PdfRenderer
95
- };
96
- //# sourceMappingURL=index-DmepcY31.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DmepcY31.mjs","sources":["../../src/renderers/Pdf/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Document, Page } from 'react-pdf';\nimport { useTranslator } from '../../i18n/LocaleContext';\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 onPageWidthChange?: (width: number) => void;\n}\n\nexport const PdfRenderer: React.FC<PdfRendererProps> = ({\n url,\n zoom,\n currentPage,\n onPageChange,\n onTotalPagesChange,\n onPageWidthChange,\n}) => {\n const t = useTranslator();\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(t('pdf.load_failed'));\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=\"rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-4 md:rfp-py-8 rfp-px-2 md:rfp-px-4\"\n >\n {error && (\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-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=\"rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen\">\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 <div className=\"rfp-flex rfp-flex-col rfp-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=\"rfp-relative\"\n >\n <Page\n pageNumber={pageNumber}\n scale={zoom}\n loading={\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-p-8 rfp-bg-surface-1 rfp-rounded-lg rfp-min-h-[600px]\">\n <div className=\"rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n }\n renderTextLayer={false}\n renderAnnotationLayer={false}\n className=\"rfp-shadow-2xl\"\n onRenderSuccess={(page) => {\n if (pageNumber === 1 && onPageWidthChange) {\n // 上报 scale=1 时的原始页面宽度\n onPageWidthChange(page.originalWidth || page.width / zoom);\n }\n }}\n />\n {/* 页码标签 */}\n <div className=\"rfp-absolute rfp-top-2 rfp-right-2 rfp-bg-surface-nav-hover rfp-backdrop-blur-sm rfp-text-fg-primary rfp-text-xs rfp-px-3 rfp-py-1 rfp-rounded-full\">\n {pageNumber}\n </div>\n </div>\n );\n })}\n </div>\n </Document>\n )}\n\n {/* 底部页码指示器 */}\n {numPages > 0 && (\n <div className=\"rfp-sticky rfp-bottom-2 md:rfp-bottom-4 rfp-mt-4 md:rfp-mt-8 rfp-bg-surface-nav-hover rfp-backdrop-blur-xl rfp-text-fg-primary rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-rounded-full rfp-text-xs md:rfp-text-sm rfp-font-medium rfp-shadow-2xl rfp-border rfp-border-line-weak\">\n 第 {currentPage} 页 / 共 {numPages} 页\n </div>\n )}\n </div>\n );\n};\n"],"names":["PdfRenderer","url","zoom","currentPage","onPageChange","onTotalPagesChange","onPageWidthChange","t","useTranslator","numPages","setNumPages","useState","error","setError","containerRef","useRef","pageRefs","useEffect","onDocumentLoadSuccess","onDocumentLoadError","handleScroll","useCallback","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","pageElement","pageNumber","rect","containerRect","pageCenter","distance","setPageRef","element","jsxs","jsx","Document","_","index","el","Page","page"],"mappings":";;;;AAgBO,MAAMA,IAA0C,CAAC;AAAA,EACtD,KAAAC;AAAA,EACA,MAAAC;AAAA,EACA,aAAAC;AAAA,EACA,cAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,mBAAAC;AACF,MAAM;AACJ,QAAMC,IAAIC,EAAA,GACJ,CAACC,GAAUC,CAAW,IAAIC,EAAiB,CAAC,GAC5C,CAACC,GAAOC,CAAQ,IAAIF,EAAwB,IAAI,GAChDG,IAAeC,EAAuB,IAAI,GAC1CC,IAAWD,EAAoC,oBAAI,KAAK;AAE9D,EAAAE,EAAU,MAAM;AACd,IAAAJ,EAAS,IAAI;AAAA,EACf,GAAG,CAACZ,CAAG,CAAC;AAER,QAAMiB,IAAwB,CAAC,EAAE,UAAAT,QAAqC;AACpE,IAAAC,EAAYD,CAAQ,GACpBJ,EAAmBI,CAAQ,GAC3BL,EAAa,CAAC;AAAA,EAChB,GAEMe,IAAsB,CAACP,MAAiB;AAC5C,YAAQ,MAAM,aAAaA,CAAK,GAChCC,EAASN,EAAE,iBAAiB,CAAC;AAAA,EAC/B,GAGMa,IAAeC,EAAY,MAAM;AACrC,QAAI,CAACP,EAAa,QAAS;AAE3B,UAAMQ,IAAYR,EAAa,SACzBS,IAAYD,EAAU,WACtBE,IAAkBF,EAAU,cAC5BG,IAAeF,IAAYC,IAAkB;AAGnD,QAAIE,IAAqB,GACrBC,IAAc;AAElB,IAAAX,EAAS,QAAQ,QAAQ,CAACY,GAAaC,MAAe;AACpD,YAAMC,IAAOF,EAAY,sBAAA,GACnBG,IAAgBT,EAAU,sBAAA,GAC1BU,IAAaF,EAAK,MAAMC,EAAc,MAAMD,EAAK,SAAS,IAAIP,GAC9DU,IAAW,KAAK,IAAID,IAAaP,CAAY;AAEnD,MAAIQ,IAAWN,MACbA,IAAcM,GACdP,IAAqBG;AAAA,IAEzB,CAAC,GAEGH,MAAuBvB,KACzBC,EAAasB,CAAkB;AAAA,EAEnC,GAAG,CAACvB,GAAaC,CAAY,CAAC;AAG9B,EAAAa,EAAU,MAAM;AACd,UAAMK,IAAYR,EAAa;AAC/B,QAAKQ;AAEL,aAAAA,EAAU,iBAAiB,UAAUF,CAAY,GAC1C,MAAME,EAAU,oBAAoB,UAAUF,CAAY;AAAA,EACnE,GAAG,CAACA,CAAY,CAAC;AAGjB,QAAMc,IAAab,EAAY,CAACQ,GAAoBM,MAAmC;AACrF,IAAIA,IACFnB,EAAS,QAAQ,IAAIa,GAAYM,CAAO,IAExCnB,EAAS,QAAQ,OAAOa,CAAU;AAAA,EAEtC,GAAG,CAAA,CAAE;AAEL,SACE,gBAAAO;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKtB;AAAA,MACL,WAAU;AAAA,MAET,UAAA;AAAA,QAAAF,KACC,gBAAAyB,EAAC,SAAI,WAAU,yCACb,4BAAC,KAAA,EAAE,WAAU,eAAe,UAAAzB,EAAA,CAAM,EAAA,CACpC;AAAA,QAGD,CAACA,KACA,gBAAAyB;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,MAAMrC;AAAA,YACN,eAAeiB;AAAA,YACf,aAAaC;AAAA,YACb,2BACG,OAAA,EAAI,WAAU,iEACb,UAAA,gBAAAkB,EAAC,OAAA,EAAI,WAAU,oHAAA,CAAoH,EAAA,CACrI;AAAA,YAGF,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,mCACZ,UAAA,MAAM,KAAK,IAAI,MAAM5B,CAAQ,GAAG,CAAC8B,GAAGC,MAAU;AAC7C,oBAAMX,IAAaW,IAAQ;AAC3B,qBACE,gBAAAJ;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,KAAK,CAACK,MAAOP,EAAWL,GAAYY,CAAE;AAAA,kBACtC,WAAU;AAAA,kBAEV,UAAA;AAAA,oBAAA,gBAAAJ;AAAA,sBAACK;AAAA,sBAAA;AAAA,wBACC,YAAAb;AAAA,wBACA,OAAO3B;AAAA,wBACP,2BACG,OAAA,EAAI,WAAU,0GACb,UAAA,gBAAAmC,EAAC,OAAA,EAAI,WAAU,kHAAA,CAAkH,EAAA,CACnI;AAAA,wBAEF,iBAAiB;AAAA,wBACjB,uBAAuB;AAAA,wBACvB,WAAU;AAAA,wBACV,iBAAiB,CAACM,MAAS;AACzB,0BAAId,MAAe,KAAKvB,KAEtBA,EAAkBqC,EAAK,iBAAiBA,EAAK,QAAQzC,CAAI;AAAA,wBAE7D;AAAA,sBAAA;AAAA,oBAAA;AAAA,oBAGF,gBAAAmC,EAAC,OAAA,EAAI,WAAU,uJACZ,UAAAR,EAAA,CACH;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAzBK,QAAQA,CAAU;AAAA,cAAA;AAAA,YA4B7B,CAAC,EAAA,CACH;AAAA,UAAA;AAAA,QAAA;AAAA,QAKHpB,IAAW,KACV,gBAAA2B,EAAC,OAAA,EAAI,WAAU,uRAAsR,UAAA;AAAA,UAAA;AAAA,UAChSjC;AAAA,UAAY;AAAA,UAAQM;AAAA,UAAS;AAAA,QAAA,EAAA,CAClC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-U3w45GW8.mjs","sources":["../../src/components/ResizableSplit.tsx","../../src/renderers/Zip/index.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState, useCallback } from 'react';\n\nexport interface ResizableSplitProps {\n /** 左侧内容 */\n left: React.ReactNode;\n /** 右侧内容 */\n right: React.ReactNode;\n /** 左侧初始宽度(px);传入 storageKey 时会从 localStorage 读取 */\n initialLeftWidth?: number;\n /** 左侧最小宽度(px) */\n minLeftWidth?: number;\n /** 左侧最大宽度(px),同时不超过 `容器宽 - minRightWidth - 分隔线宽` */\n maxLeftWidth?: number;\n /** 右侧至少保留的宽度(px) */\n minRightWidth?: number;\n /** localStorage 持久化 key;不传则不持久化 */\n storageKey?: string;\n /** 启用横向拖动的媒体查询,默认 `(min-width: 768px)` */\n desktopMedia?: string;\n /** 容器额外类名 */\n className?: string;\n}\n\n/**\n * 通用可拖动分隔布局:\n * - 桌面端(由 `desktopMedia` 判定)横向分两栏,中间分隔线可左右拖动调整左栏宽度\n * - 移动端退化为上下堆叠,不显示分隔线\n * - 可选 `storageKey` 将宽度持久化到 localStorage\n */\nexport const ResizableSplit: React.FC<ResizableSplitProps> = ({\n left,\n right,\n initialLeftWidth = 280,\n minLeftWidth = 160,\n maxLeftWidth = 640,\n minRightWidth = 200,\n storageKey,\n desktopMedia = '(min-width: 768px)',\n className = '',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [leftWidth, setLeftWidth] = useState<number>(() => {\n if (storageKey && typeof window !== 'undefined') {\n const saved = Number(window.localStorage.getItem(storageKey));\n if (!isNaN(saved) && saved > 0) return saved;\n }\n return initialLeftWidth;\n });\n const [dragging, setDragging] = useState(false);\n const [isDesktop, setIsDesktop] = useState(false);\n\n // 响应式:监听媒体查询\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const mq = window.matchMedia(desktopMedia);\n const handler = () => setIsDesktop(mq.matches);\n handler();\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n }, [desktopMedia]);\n\n // 拖动\n useEffect(() => {\n if (!dragging) return;\n const handleMove = (e: MouseEvent) => {\n if (!containerRef.current) return;\n const rect = containerRef.current.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const cap = rect.width - minRightWidth - 6;\n const effectiveMax = Math.min(maxLeftWidth, cap);\n const newW = Math.max(minLeftWidth, Math.min(effectiveMax, x));\n setLeftWidth(newW);\n };\n const handleUp = () => setDragging(false);\n window.addEventListener('mousemove', handleMove);\n window.addEventListener('mouseup', handleUp);\n const prevCursor = document.body.style.cursor;\n const prevSelect = document.body.style.userSelect;\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n return () => {\n window.removeEventListener('mousemove', handleMove);\n window.removeEventListener('mouseup', handleUp);\n document.body.style.cursor = prevCursor;\n document.body.style.userSelect = prevSelect;\n };\n }, [dragging, minLeftWidth, maxLeftWidth, minRightWidth]);\n\n // 持久化\n useEffect(() => {\n if (!storageKey || dragging) return;\n try {\n window.localStorage.setItem(storageKey, String(leftWidth));\n } catch {\n // ignore\n }\n }, [leftWidth, storageKey, dragging]);\n\n const handleDividerDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n setDragging(true);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className={`rfp-w-full rfp-h-full rfp-flex rfp-flex-col md:rfp-flex-row rfp-min-h-0 rfp-min-w-0 ${className}`}\n >\n <div\n className=\"rfp-min-h-0 rfp-min-w-0 rfp-flex-shrink-0 rfp-w-full rfp-max-h-60 md:rfp-h-full md:rfp-max-h-none\"\n style={isDesktop ? { width: `${leftWidth}px` } : undefined}\n >\n {left}\n </div>\n {/* 分隔线:仅桌面显示 */}\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n onMouseDown={handleDividerDown}\n className={`rfp-hidden md:rfp-block rfp-relative rfp-w-1.5 rfp-flex-shrink-0 rfp-cursor-col-resize rfp-transition-colors ${\n dragging ? 'rfp-bg-surface-toolbar' : 'rfp-bg-surface-2 hover:rfp-bg-surface-3'\n }`}\n >\n {/* 加宽命中区,改善拖动体验 */}\n <span className=\"rfp-absolute rfp-inset-y-0 -rfp-left-1 -rfp-right-1\" />\n </div>\n <div className=\"rfp-flex-1 rfp-min-w-0 rfp-min-h-0 rfp-overflow-hidden\">{right}</div>\n </div>\n );\n};\n","import { useState, useEffect, useMemo, useCallback, useRef, lazy, Suspense } from 'react';\nimport React from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n Folder,\n FolderOpen,\n FileText,\n FileImage,\n FileCode,\n File as FileIcon,\n ChevronRight,\n} from 'lucide-react';\nimport type JSZip from 'jszip';\nimport {\n loadZip,\n listZipEntries,\n buildZipTree,\n readZipEntryBlob,\n formatFileSize,\n getFileType,\n inferMimeType,\n type ZipTreeNode,\n} from '@eternalheart/file-preview-core';\nimport { ResizableSplit } from '../../components/ResizableSplit';\nimport type { ZipToolbarStats } from './toolbar';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\n// 懒加载 FilePreviewContent 以打破循环依赖\nconst LazyFilePreviewContent = lazy(() =>\n import('../../FilePreviewContent').then(m => ({ default: m.FilePreviewContent }))\n);\n\ninterface ZipRendererProps {\n url: string;\n /** ZIP 嵌套深度(由 FilePreviewContent 传入) */\n nestingDepth?: number;\n /** 解析完成后向外回报统计信息(files / dirs / size),供工具栏展示 */\n onStatsChange?: (stats: ZipToolbarStats | null) => void;\n}\n\ninterface SelectedPreview {\n path: string;\n name: string;\n size: number;\n blobUrl: string;\n}\n\n/** 根据文件类型返回树节点图标 */\nconst resolveIcon = (name: string) => {\n const ft = getFileType({ id: '', name, url: '', type: '' });\n if (ft === 'image') return FileImage;\n if (ft === 'text' || ft === 'markdown' || ft === 'json' || ft === 'csv' || ft === 'xml' || ft === 'subtitle') {\n return name.endsWith('.md') || name.endsWith('.markdown') ? FileText : FileCode;\n }\n return FileIcon;\n};\n\n// ---------- Tooltip via portal ----------\n\ninterface HoverTipState {\n text: string;\n x: number;\n y: number;\n}\n\n// ---------- Tree item ----------\n\ninterface TreeItemProps {\n node: ZipTreeNode;\n depth: number;\n selectedPath: string | null;\n expanded: Set<string>;\n onToggle: (path: string) => void;\n onSelect: (node: ZipTreeNode) => void;\n onHover: (text: string, rect: DOMRect) => void;\n onLeave: () => void;\n}\n\nconst TreeItem: React.FC<TreeItemProps> = ({\n node,\n depth,\n selectedPath,\n expanded,\n onToggle,\n onSelect,\n onHover,\n onLeave,\n}) => {\n const isOpen = expanded.has(node.path);\n const isSelected = selectedPath === node.path;\n const pad = { paddingLeft: `${depth * 14 + 10}px` };\n const handleEnter = (e: React.MouseEvent<HTMLElement>) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n onHover(node.name || '/', rect);\n };\n\n if (node.isDir) {\n return (\n <>\n <button\n type=\"button\"\n onClick={() => onToggle(node.path)}\n onMouseEnter={handleEnter}\n onMouseLeave={onLeave}\n className=\"rfp-w-full rfp-flex rfp-items-center rfp-gap-1.5 rfp-py-1.5 rfp-pr-2 rfp-text-left rfp-text-fg-secondary hover:rfp-bg-surface-1 rfp-text-sm\"\n style={pad}\n >\n <ChevronRight\n className={`rfp-w-3.5 rfp-h-3.5 rfp-flex-shrink-0 rfp-transition-transform ${\n isOpen ? 'rfp-rotate-90' : ''\n }`}\n />\n {isOpen ? (\n <FolderOpen className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-amber-300/80\" />\n ) : (\n <Folder className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-amber-300/80\" />\n )}\n <span className=\"rfp-truncate rfp-flex-1 rfp-min-w-0\">{node.name || '/'}</span>\n </button>\n {isOpen &&\n node.children?.map((child) => (\n <TreeItem\n key={child.path}\n node={child}\n depth={depth + 1}\n selectedPath={selectedPath}\n expanded={expanded}\n onToggle={onToggle}\n onSelect={onSelect}\n onHover={onHover}\n onLeave={onLeave}\n />\n ))}\n </>\n );\n }\n\n const Icon = resolveIcon(node.name);\n\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(node)}\n onMouseEnter={handleEnter}\n onMouseLeave={onLeave}\n className={`rfp-w-full rfp-flex rfp-items-center rfp-gap-1.5 rfp-py-1.5 rfp-pr-2 rfp-text-left rfp-text-sm ${\n isSelected ? 'rfp-bg-surface-2 rfp-text-fg-primary' : 'rfp-text-fg-secondary hover:rfp-bg-surface-1'\n }`}\n style={pad}\n >\n <span className=\"rfp-w-3.5 rfp-h-3.5 rfp-flex-shrink-0\" />\n <Icon className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-fg-tertiary\" />\n <span className=\"rfp-flex-1 rfp-truncate rfp-min-w-0\">{node.name}</span>\n <span className=\"rfp-text-xs rfp-text-fg-disabled rfp-flex-shrink-0 rfp-ml-2\">\n {formatFileSize(node.size)}\n </span>\n </button>\n );\n};\n\n// ---------- Main Zip Renderer ----------\n\nexport const ZipRenderer: React.FC<ZipRendererProps> = ({ url, nestingDepth = 0, onStatsChange }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [zip, setZip] = useState<JSZip | null>(null);\n const [tree, setTree] = useState<ZipTreeNode | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [expanded, setExpanded] = useState<Set<string>>(new Set(['']));\n const [selected, setSelected] = useState<SelectedPreview | null>(null);\n const [previewLoading, setPreviewLoading] = useState(false);\n const [previewError, setPreviewError] = useState<string | null>(null);\n const [hoverTip, setHoverTip] = useState<HoverTipState | null>(null);\n const onStatsChangeRef = useRef(onStatsChange);\n\n useEffect(() => {\n onStatsChangeRef.current = onStatsChange;\n }, [onStatsChange]);\n\n useEffect(() => {\n let cancelled = false;\n const load = async () => {\n try {\n setLoading(true);\n setError(null);\n const res = await fetcher(url);\n if (!res.ok) throw new Error('加载失败');\n const buf = await res.arrayBuffer();\n const z = await loadZip(buf);\n if (cancelled) return;\n const entries = listZipEntries(z);\n const root = buildZipTree(entries);\n setZip(z);\n setTree(root);\n const init = new Set<string>(['']);\n if (root.children) {\n for (const c of root.children) if (c.isDir) init.add(c.path);\n }\n setExpanded(init);\n } catch (err) {\n console.error(err);\n if (!cancelled) setError(t('zip.load_failed'));\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n load();\n return () => {\n cancelled = true;\n };\n }, [url]);\n\n // 切换文件时回收 blob URL\n useEffect(() => {\n return () => {\n if (selected?.blobUrl) URL.revokeObjectURL(selected.blobUrl);\n };\n }, [selected]);\n\n const totalStats = useMemo<ZipToolbarStats | null>(() => {\n if (!tree) return null;\n let files = 0;\n let dirs = 0;\n let size = 0;\n const walk = (n: ZipTreeNode) => {\n if (n.isDir) {\n if (n.path) dirs++;\n n.children?.forEach(walk);\n } else {\n files++;\n size += n.size;\n }\n };\n walk(tree);\n return { files, dirs, size };\n }, [tree]);\n\n // 向外回报 stats\n useEffect(() => {\n onStatsChangeRef.current?.(totalStats);\n return () => {\n onStatsChangeRef.current?.(null);\n };\n }, [totalStats]);\n\n const handleToggle = useCallback((path: string) => {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(path)) next.delete(path);\n else next.add(path);\n return next;\n });\n }, []);\n\n const handleHover = useCallback((text: string, rect: DOMRect) => {\n setHoverTip({\n text,\n x: rect.right + 8,\n y: rect.top + rect.height / 2,\n });\n }, []);\n\n const handleLeave = useCallback(() => {\n setHoverTip(null);\n }, []);\n\n const handleSelect = useCallback(\n async (node: ZipTreeNode) => {\n if (!zip || node.isDir) return;\n if (selected?.blobUrl) URL.revokeObjectURL(selected.blobUrl);\n setPreviewLoading(true);\n setPreviewError(null);\n\n try {\n const mime = inferMimeType(node.name);\n const blob = await readZipEntryBlob(zip, node.path, mime !== 'application/octet-stream' ? mime : undefined);\n const blobUrl = URL.createObjectURL(blob);\n setSelected({ path: node.path, name: node.name, size: node.size, blobUrl });\n } catch (err) {\n console.error(err);\n setPreviewError('条目读取失败');\n } finally {\n setPreviewLoading(false);\n }\n },\n [zip, selected]\n );\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\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 || !tree) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error || t('zip.parse_failed')}</p>\n </div>\n </div>\n );\n }\n\n // 左侧:文件树\n const leftPane = (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto\">\n {tree.children?.map((child) => (\n <TreeItem\n key={child.path}\n node={child}\n depth={0}\n selectedPath={selected?.path ?? null}\n expanded={expanded}\n onToggle={handleToggle}\n onSelect={handleSelect}\n onHover={handleHover}\n onLeave={handleLeave}\n />\n ))}\n </div>\n );\n\n // 右侧:预览区\n const rightPane = (\n <div className=\"rfp-w-full rfp-h-full rfp-flex rfp-flex-col\">\n {!selected && (\n <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-muted rfp-text-sm rfp-p-6\">\n 从左侧选择一个文件以预览\n </div>\n )}\n {selected && previewLoading && (\n <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center\">\n <div className=\"rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n {selected && !previewLoading && previewError && (\n <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary\">\n {previewError}\n </div>\n )}\n {selected && !previewLoading && !previewError && (\n <>\n <div className=\"rfp-flex-1 rfp-min-h-0 rfp-overflow-hidden rfp-flex rfp-relative rfp-z-0\">\n <Suspense\n fallback={\n <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center\">\n <div className=\"rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n }\n >\n <LazyFilePreviewContent\n mode=\"embed\"\n files={[{ name: selected.name, url: selected.blobUrl, type: inferMimeType(selected.name) }]}\n currentIndex={0}\n zipNestingDepth={nestingDepth + 1}\n />\n </Suspense>\n </div>\n </>\n )}\n </div>\n );\n\n return (\n <>\n <ResizableSplit\n left={leftPane}\n right={rightPane}\n initialLeftWidth={280}\n minLeftWidth={180}\n maxLeftWidth={560}\n storageKey=\"rfp-zip-split-left\"\n />\n {/* 文件名 hover tooltip(portal 到 body,避免被滚动区裁剪) */}\n {hoverTip &&\n typeof document !== 'undefined' &&\n createPortal(\n <div\n className=\"rfp-fixed rfp-z-[9999] rfp-pointer-events-none rfp-px-2 rfp-py-1 rfp-bg-[rgba(0,0,0,0.85)] rfp-text-fg-primary rfp-text-xs rfp-rounded rfp-whitespace-nowrap rfp-shadow-lg\"\n style={{\n left: `${hoverTip.x}px`,\n top: `${hoverTip.y}px`,\n transform: 'translateY(-50%)',\n }}\n >\n {hoverTip.text}\n </div>,\n document.body\n )}\n </>\n );\n};\n"],"names":["ResizableSplit","left","right","initialLeftWidth","minLeftWidth","maxLeftWidth","minRightWidth","storageKey","desktopMedia","className","containerRef","useRef","leftWidth","setLeftWidth","useState","saved","dragging","setDragging","isDesktop","setIsDesktop","useEffect","mq","handler","handleMove","e","rect","cap","effectiveMax","newW","handleUp","prevCursor","prevSelect","handleDividerDown","useCallback","jsxs","jsx","LazyFilePreviewContent","lazy","n","m","resolveIcon","name","ft","getFileType","FileImage","FileText","FileCode","FileIcon","TreeItem","node","depth","selectedPath","expanded","onToggle","onSelect","onHover","onLeave","isOpen","isSelected","pad","handleEnter","Fragment","ChevronRight","FolderOpen","Folder","_a","child","Icon","formatFileSize","ZipRenderer","url","nestingDepth","onStatsChange","t","useTranslator","fetcher","useFetcher","zip","setZip","tree","setTree","loading","setLoading","error","setError","setExpanded","selected","setSelected","previewLoading","setPreviewLoading","previewError","setPreviewError","hoverTip","setHoverTip","onStatsChangeRef","cancelled","res","buf","z","loadZip","entries","listZipEntries","root","buildZipTree","init","c","err","totalStats","useMemo","files","dirs","size","walk","handleToggle","path","prev","next","handleHover","text","handleLeave","handleSelect","mime","inferMimeType","blob","readZipEntryBlob","blobUrl","leftPane","rightPane","Suspense","createPortal"],"mappings":"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"}
@@ -1,129 +0,0 @@
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 M } from "lucide-react";
4
- import z from "exceljs";
5
- import W from "x-data-spreadsheet";
6
- /* empty css */
7
- import { u as j, a as L, z as S } from "./index-Bv93wiEK.mjs";
8
- const A = ({ url: x }) => {
9
- const a = j(), R = L(), [w, g] = k(!0), [b, N] = k(null), e = i(null), v = i(null), l = i(null), d = i(null), p = i(null), y = i({ width: 0, height: 0 }), c = E(() => {
10
- if (!e.current) return { width: 800, height: 600 };
11
- const t = e.current.clientWidth, f = e.current.clientHeight, s = t > 100 ? t : 800, r = f > 100 ? f : 600;
12
- return { width: s, height: r };
13
- }, []), m = E(() => {
14
- if (!e.current || !l.current) return;
15
- e.current.innerHTML = "", v.current = null;
16
- const { width: t, height: f } = c(), s = t < 640, r = new W(e.current, {
17
- mode: "read",
18
- showToolbar: !1,
19
- showContextmenu: !1,
20
- showGrid: !0,
21
- row: {
22
- len: 100,
23
- height: 25
24
- },
25
- col: {
26
- len: 26,
27
- width: s ? 80 : 100,
28
- indexWidth: s ? 40 : 60,
29
- minWidth: s ? 40 : 60
30
- },
31
- view: {
32
- height: () => f,
33
- width: () => t
34
- }
35
- });
36
- r.loadData(l.current), v.current = r;
37
- }, [c]);
38
- return D(() => {
39
- if (!e.current) return;
40
- let t = !0;
41
- const f = () => {
42
- if (t) {
43
- t = !1, y.current = c();
44
- return;
45
- }
46
- const s = c(), r = y.current, o = Math.abs(r.width - s.width), u = Math.abs(r.height - s.height);
47
- o < 10 && u < 10 || (y.current = s, p.current && clearTimeout(p.current), p.current = window.setTimeout(() => {
48
- l.current && m();
49
- }, 500));
50
- };
51
- return d.current = new ResizeObserver(() => {
52
- f();
53
- }), d.current.observe(e.current), () => {
54
- d.current && d.current.disconnect(), p.current && clearTimeout(p.current);
55
- };
56
- }, [c, m]), D(() => {
57
- let t = !0;
58
- const f = async () => {
59
- if (e.current) {
60
- g(!0), N(null);
61
- try {
62
- const r = await R(x, {
63
- mode: "cors",
64
- credentials: "omit",
65
- redirect: "follow"
66
- });
67
- if (!r.ok)
68
- throw r.status === 404 ? new Error(a("xlsx.not_found")) : r.status === 403 ? new Error("无权限访问此文件") : new Error(`文件加载失败 (${r.status})`);
69
- const o = await r.arrayBuffer();
70
- if (o.byteLength === 0)
71
- throw new Error("文件为空");
72
- const u = new z.Workbook();
73
- await u.xlsx.load(o);
74
- const T = S(u);
75
- if (!t) return;
76
- l.current = T, m(), g(!1);
77
- } catch (r) {
78
- if (t) {
79
- console.error("Excel 解析错误:", r);
80
- let o = a("xlsx.parse_failed");
81
- r instanceof Error && (o = r.message), N(o), g(!1);
82
- }
83
- }
84
- }
85
- }, s = setTimeout(() => {
86
- requestAnimationFrame(() => {
87
- f();
88
- });
89
- }, 100);
90
- return () => {
91
- t = !1, clearTimeout(s), l.current = null, e.current && (e.current.innerHTML = ""), v.current = null;
92
- };
93
- }, [x, m]), /* @__PURE__ */ h("div", { className: "rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full", children: [
94
- 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: [
95
- /* @__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" }),
96
- /* @__PURE__ */ n("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: a("xlsx.loading") })
97
- ] }) }),
98
- 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: [
99
- /* @__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(M, { className: "rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary" }) }),
100
- /* @__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: a("xlsx.load_failed") }),
101
- /* @__PURE__ */ n("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6", children: b }),
102
- /* @__PURE__ */ h(
103
- "a",
104
- {
105
- href: x,
106
- download: !0,
107
- 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",
108
- children: [
109
- /* @__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" }) }),
110
- a("common.download")
111
- ]
112
- }
113
- ),
114
- /* @__PURE__ */ n("p", { className: "rfp-text-xs rfp-text-fg-muted rfp-mt-3 md:rfp-mt-4", children: "提示:可以使用 Microsoft Excel 或 WPS 打开" })
115
- ] }) }),
116
- !b && /* @__PURE__ */ n(
117
- "div",
118
- {
119
- ref: e,
120
- className: "xlsx-spreadsheet-container rfp-w-full rfp-h-full",
121
- style: { opacity: w ? 0 : 1 }
122
- }
123
- )
124
- ] });
125
- };
126
- export {
127
- A as XlsxRenderer
128
- };
129
- //# sourceMappingURL=index-r3q2xCCI.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-r3q2xCCI.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';\nimport { useFetcher } from '../../RequestContext';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\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 fetcher(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","fetcher","useFetcher","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":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-zEVVgWCH.mjs","sources":["../../src/hooks/useAudioPlayer.ts","../../src/renderers/Audio/index.tsx"],"sourcesContent":["import { useState, useRef, useEffect, useCallback } from 'react';\n\ninterface UseAudioPlayerOptions {\n url: string;\n skipSeconds?: number;\n}\n\ninterface UseAudioPlayerReturn {\n audioRef: React.RefObject<HTMLAudioElement>;\n isPlaying: boolean;\n isLoading: boolean;\n isLoop: boolean;\n currentTime: number;\n duration: number;\n volume: number;\n isMuted: boolean;\n error: string | null;\n togglePlay: () => void;\n seek: (time: number) => void;\n skip: (seconds: number) => void;\n setVolume: (vol: number) => void;\n toggleMute: () => void;\n toggleLoop: () => void;\n formatTime: (time: number) => string;\n}\n\nexport function useAudioPlayer({\n url,\n}: UseAudioPlayerOptions): UseAudioPlayerReturn {\n const audioRef = useRef<HTMLAudioElement>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [volume, setVolumeState] = useState(1);\n const [isMuted, setIsMuted] = useState(false);\n const [isLoop, setIsLoop] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const audio = audioRef.current;\n if (!audio) return;\n\n // 重置加载状态\n setIsLoading(true);\n setError(null);\n\n const onTimeUpdate = () => {\n if (!isNaN(audio.currentTime)) {\n setCurrentTime(audio.currentTime);\n }\n };\n\n const onDurationChange = () => {\n if (!isNaN(audio.duration) && isFinite(audio.duration)) {\n setDuration(audio.duration);\n }\n };\n\n const onCanPlay = () => {\n setIsLoading(false);\n onDurationChange();\n };\n\n const onWaiting = () => setIsLoading(true);\n const onPlaying = () => {\n setIsLoading(false);\n setIsPlaying(true);\n };\n\n // 由 audio 事件驱动播放状态,而非手动设置\n const onPlay = () => setIsPlaying(true);\n const onPause = () => setIsPlaying(false);\n const onEnded = () => setIsPlaying(false);\n\n const onError = () => {\n setError('音频加载失败');\n setIsLoading(false);\n };\n\n audio.addEventListener('timeupdate', onTimeUpdate);\n audio.addEventListener('loadedmetadata', onDurationChange);\n audio.addEventListener('durationchange', onDurationChange);\n audio.addEventListener('canplay', onCanPlay);\n audio.addEventListener('waiting', onWaiting);\n audio.addEventListener('playing', onPlaying);\n audio.addEventListener('play', onPlay);\n audio.addEventListener('pause', onPause);\n audio.addEventListener('ended', onEnded);\n audio.addEventListener('error', onError);\n\n // 如果 audio 已经就绪\n if (audio.readyState >= 3) {\n setIsLoading(false);\n onDurationChange();\n } else if (audio.readyState >= 1) {\n onDurationChange();\n }\n\n return () => {\n audio.removeEventListener('timeupdate', onTimeUpdate);\n audio.removeEventListener('loadedmetadata', onDurationChange);\n audio.removeEventListener('durationchange', onDurationChange);\n audio.removeEventListener('canplay', onCanPlay);\n audio.removeEventListener('waiting', onWaiting);\n audio.removeEventListener('playing', onPlaying);\n audio.removeEventListener('play', onPlay);\n audio.removeEventListener('pause', onPause);\n audio.removeEventListener('ended', onEnded);\n audio.removeEventListener('error', onError);\n };\n }, [url]);\n\n const togglePlay = useCallback(() => {\n const audio = audioRef.current;\n if (!audio) return;\n\n if (audio.paused) {\n audio.play().catch(() => {\n // 浏览器自动播放策略拒绝\n });\n } else {\n audio.pause();\n }\n }, []);\n\n const seek = useCallback((time: number) => {\n const audio = audioRef.current;\n if (!audio) return;\n audio.currentTime = time;\n setCurrentTime(time);\n }, []);\n\n const skip = useCallback(\n (seconds: number) => {\n const audio = audioRef.current;\n if (!audio) return;\n audio.currentTime = Math.max(\n 0,\n Math.min(audio.currentTime + seconds, audio.duration || Infinity)\n );\n },\n []\n );\n\n const setVolume = useCallback((vol: number) => {\n const audio = audioRef.current;\n if (!audio) return;\n const clamped = Math.max(0, Math.min(1, vol));\n audio.volume = clamped;\n setVolumeState(clamped);\n if (clamped > 0) {\n audio.muted = false;\n setIsMuted(false);\n }\n }, []);\n\n const toggleMute = useCallback(() => {\n const audio = audioRef.current;\n if (!audio) return;\n audio.muted = !audio.muted;\n setIsMuted(audio.muted);\n }, []);\n\n const toggleLoop = useCallback(() => {\n const audio = audioRef.current;\n if (!audio) return;\n const next = !audio.loop;\n audio.loop = next;\n setIsLoop(next);\n }, []);\n\n const formatTime = useCallback((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 return {\n audioRef,\n isPlaying,\n isLoading,\n isLoop,\n currentTime,\n duration,\n volume,\n isMuted,\n error,\n togglePlay,\n seek,\n skip,\n setVolume,\n toggleMute,\n toggleLoop,\n formatTime,\n };\n}\n","import { useState, useRef, useEffect } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Play, Pause, Volume2, VolumeX, Volume1, SkipBack, SkipForward, Repeat } from 'lucide-react';\nimport { useAudioPlayer } from '../../hooks/useAudioPlayer';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\n/** 文本溢出时自动横向滚动 */\nconst MarqueeText: React.FC<{\n text: string;\n className?: string;\n style?: React.CSSProperties;\n}> = ({ text, className = '', style }) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n const [overflow, setOverflow] = useState(false);\n const [scrollDist, setScrollDist] = useState(0);\n\n useEffect(() => {\n const check = () => {\n const container = containerRef.current;\n const inner = innerRef.current;\n if (!container || !inner) return;\n const cw = container.clientWidth;\n const tw = inner.scrollWidth;\n setOverflow(tw > cw);\n setScrollDist(tw);\n };\n check();\n const observer = new ResizeObserver(check);\n if (containerRef.current) observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [text]);\n\n const gap = 60;\n const totalScroll = scrollDist + gap;\n const dur = totalScroll / 40;\n\n return (\n <div\n ref={containerRef}\n className={`rfp-overflow-hidden rfp-whitespace-nowrap ${className}`}\n style={style}\n >\n {overflow ? (\n <motion.div\n className=\"rfp-inline-flex rfp-whitespace-nowrap\"\n animate={{ x: [0, -totalScroll] }}\n transition={{ duration: dur, repeat: Infinity, ease: 'linear', repeatDelay: 1.5 }}\n >\n <span>{text}</span>\n <span style={{ width: gap }} className=\"rfp-inline-block\" />\n <span>{text}</span>\n </motion.div>\n ) : null}\n {/* 始终渲染用于测量的隐藏层 */}\n <div\n ref={innerRef}\n className=\"rfp-whitespace-nowrap\"\n style={overflow ? { position: 'absolute', visibility: 'hidden', pointerEvents: 'none' } : undefined}\n >\n {text}\n </div>\n </div>\n );\n};\n\n/** SVG 唱臂组件 */\nconst Tonearm: React.FC<{ isPlaying: boolean }> = ({ isPlaying }) => (\n <motion.div\n className=\"rfp-absolute\"\n style={{\n top: '-6px',\n right: '2px',\n width: '100px',\n height: '120px',\n transformOrigin: '76px 16px',\n zIndex: 5,\n }}\n animate={{ rotate: isPlaying ? 16 : 0 }}\n transition={{ duration: 0.8, ease: [0.4, 0, 0.2, 1] }}\n >\n <svg\n width=\"100\"\n height=\"120\"\n viewBox=\"0 0 100 120\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {/* 底座阴影 */}\n <circle cx=\"76\" cy=\"16\" r=\"13\" fill=\"rgba(0,0,0,0.3)\" />\n {/* 底座外圈 */}\n <circle cx=\"76\" cy=\"16\" r=\"11\" fill=\"url(#baseGrad)\" />\n {/* 底座内圈 */}\n <circle cx=\"76\" cy=\"16\" r=\"6\" fill=\"url(#baseInnerGrad)\" />\n {/* 底座中心轴 */}\n <circle cx=\"76\" cy=\"16\" r=\"2.5\" fill=\"#222\" stroke=\"#555\" strokeWidth=\"0.5\" />\n\n {/* 臂杆 */}\n <path\n d=\"M74 22 L56 88\"\n stroke=\"url(#armGrad)\"\n strokeWidth=\"3.5\"\n strokeLinecap=\"round\"\n />\n {/* 臂杆高光 */}\n <path\n d=\"M74.8 22 L56.8 88\"\n stroke=\"rgba(255,255,255,0.06)\"\n strokeWidth=\"1\"\n strokeLinecap=\"round\"\n />\n\n {/* 唱头座 (Headshell) */}\n <rect x=\"50\" y=\"86\" width=\"12\" height=\"7\" rx=\"1.5\" fill=\"url(#headGrad)\" />\n {/* 唱头 (Cartridge) */}\n <rect x=\"52.5\" y=\"92\" width=\"7\" height=\"9\" rx=\"1\" fill=\"url(#cartridgeGrad)\" />\n {/* 唱针 (Stylus) */}\n <line x1=\"56\" y1=\"101\" x2=\"56\" y2=\"105\" stroke=\"#bbb\" strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"56\" cy=\"105.5\" r=\"0.8\" fill=\"#ddd\" />\n\n {/* 渐变定义 */}\n <defs>\n <radialGradient id=\"baseGrad\" cx=\"40%\" cy=\"35%\">\n <stop offset=\"0%\" stopColor=\"#555\" />\n <stop offset=\"100%\" stopColor=\"#1a1a1a\" />\n </radialGradient>\n <radialGradient id=\"baseInnerGrad\" cx=\"40%\" cy=\"35%\">\n <stop offset=\"0%\" stopColor=\"#666\" />\n <stop offset=\"100%\" stopColor=\"#333\" />\n </radialGradient>\n <linearGradient id=\"armGrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"#555\" />\n <stop offset=\"50%\" stopColor=\"#444\" />\n <stop offset=\"100%\" stopColor=\"#333\" />\n </linearGradient>\n <linearGradient id=\"headGrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"#555\" />\n <stop offset=\"100%\" stopColor=\"#333\" />\n </linearGradient>\n <linearGradient id=\"cartridgeGrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"#444\" />\n <stop offset=\"100%\" stopColor=\"#222\" />\n </linearGradient>\n </defs>\n </svg>\n </motion.div>\n);\n\ninterface AudioRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const AudioRenderer: React.FC<AudioRendererProps> = ({ url, fileName }) => {\n const t = useTranslator();\n const {\n audioRef,\n isPlaying,\n isLoading,\n isLoop,\n currentTime,\n duration,\n volume,\n isMuted,\n error,\n togglePlay,\n seek,\n skip,\n setVolume,\n toggleMute,\n toggleLoop,\n formatTime,\n } = useAudioPlayer({ url });\n\n const [showVolume, setShowVolume] = useState(false);\n const volumeRef = useRef<HTMLDivElement>(null);\n const volumeTimerRef = useRef<ReturnType<typeof setTimeout>>();\n\n const progress = duration > 0 ? currentTime / duration : 0;\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (volumeRef.current && !volumeRef.current.contains(e.target as Node)) {\n setShowVolume(false);\n }\n };\n if (showVolume) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [showVolume]);\n\n const handleVolumeEnter = () => {\n clearTimeout(volumeTimerRef.current);\n setShowVolume(true);\n };\n\n const handleVolumeLeave = () => {\n volumeTimerRef.current = setTimeout(() => setShowVolume(false), 300);\n };\n\n const VolumeIcon = isMuted || volume === 0 ? VolumeX : volume < 0.5 ? Volume1 : Volume2;\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-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"rfp-flex rfp-flex-col rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-p-4 md:rfp-p-8 rfp-gap-5 md:rfp-gap-8 rfp-select-none\">\n {/* 唱片机整体 */}\n <div className=\"rfp-relative\" style={{ width: '260px', height: '240px' }}>\n {/* 外圈光晕 */}\n <motion.div\n className=\"rfp-absolute rfp-rounded-full\"\n style={{\n width: '220px',\n height: '220px',\n top: '18px',\n left: '8px',\n background: 'radial-gradient(circle, rgba(129,140,248,0.12) 0%, transparent 70%)',\n }}\n animate={isPlaying ? { scale: [1, 1.08, 1], opacity: [0.5, 1, 0.5] } : { scale: 1, opacity: 0.2 }}\n transition={isPlaying ? { duration: 3, repeat: Infinity, ease: 'easeInOut' } : { duration: 0.5 }}\n />\n\n {/* 唱片主体 */}\n <div\n className=\"rfp-absolute rfp-rounded-full rfp-overflow-hidden\"\n style={{\n width: '200px',\n height: '200px',\n top: '28px',\n left: '18px',\n background: `\n radial-gradient(circle at center, transparent 95%, rgba(30,30,30,0.8) 95.5%, #111 97%),\n radial-gradient(circle at center, transparent 38%, rgba(50,50,50,0.5) 38.15%, transparent 38.4%),\n radial-gradient(circle at center, transparent 45%, rgba(50,50,50,0.3) 45.15%, transparent 45.4%),\n radial-gradient(circle at center, transparent 52%, rgba(50,50,50,0.5) 52.15%, transparent 52.4%),\n radial-gradient(circle at center, transparent 59%, rgba(50,50,50,0.3) 59.15%, transparent 59.4%),\n radial-gradient(circle at center, transparent 66%, rgba(50,50,50,0.5) 66.15%, transparent 66.4%),\n radial-gradient(circle at center, transparent 73%, rgba(50,50,50,0.3) 73.15%, transparent 73.4%),\n radial-gradient(circle at center, transparent 80%, rgba(50,50,50,0.4) 80.15%, transparent 80.4%),\n radial-gradient(circle at center, transparent 87%, rgba(50,50,50,0.3) 87.15%, transparent 87.4%),\n conic-gradient(from 0deg, #1c1c1c, #232323, #1a1a1a, #262626, #1c1c1c, #212121, #1a1a1a, #252525, #1c1c1c, #232323, #1a1a1a, #262626, #1c1c1c)\n `,\n boxShadow: isPlaying\n ? '0 0 36px rgba(129,140,248,0.1), 0 8px 32px rgba(0,0,0,0.4), inset 0 0 20px rgba(0,0,0,0.4)'\n : '0 8px 32px rgba(0,0,0,0.4), inset 0 0 20px rgba(0,0,0,0.4)',\n animation: 'rfp-vinyl-spin 8s linear infinite',\n animationPlayState: isPlaying ? 'running' : 'paused',\n }}\n >\n {/* 中心标签 */}\n <div\n className=\"rfp-absolute rfp-rounded-full\"\n style={{\n width: '34%',\n height: '34%',\n top: '33%',\n left: '33%',\n background: 'radial-gradient(circle at 40% 38%, #818cf8, #6366f1, #4f46e5, #4338ca)',\n boxShadow: 'inset 0 1px 3px rgba(255,255,255,0.25), inset 0 -1px 3px rgba(0,0,0,0.3), 0 0 8px rgba(0,0,0,0.3)',\n }}\n >\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-rounded-full rfp-opacity-20\"\n style={{\n background: `\n radial-gradient(circle at center, transparent 30%, rgba(0,0,0,0.3) 31%, transparent 32%),\n radial-gradient(circle at center, transparent 50%, rgba(0,0,0,0.2) 51%, transparent 52%),\n radial-gradient(circle at center, transparent 70%, rgba(0,0,0,0.3) 71%, transparent 72%),\n radial-gradient(circle at center, transparent 88%, rgba(0,0,0,0.2) 89%, transparent 90%)\n `,\n }}\n />\n <div\n className=\"rfp-absolute rfp-rounded-full\"\n style={{\n width: '14%',\n height: '14%',\n top: '43%',\n left: '43%',\n background: 'radial-gradient(circle at 40% 40%, #333, #0d0d0d)',\n boxShadow: 'inset 0 1px 3px rgba(0,0,0,0.9), 0 0 2px rgba(0,0,0,0.5)',\n }}\n />\n </div>\n\n {isLoading && (\n <motion.div\n className=\"rfp-absolute rfp-inset-0 rfp-rounded-full\"\n style={{ border: '2px solid rgba(129,140,248,0.3)' }}\n animate={{ scale: [1, 1.02, 1], opacity: [0.3, 0.6, 0.3] }}\n transition={{ duration: 1.5, repeat: Infinity }}\n />\n )}\n </div>\n\n {/* 唱臂 */}\n <Tonearm isPlaying={isPlaying} />\n </div>\n\n {/* 文件名 */}\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <MarqueeText\n text={fileName}\n className=\"rfp-text-lg md:rfp-text-xl rfp-font-medium rfp-mb-1 rfp-text-fg-primary\"\n />\n <p className=\"rfp-text-xs rfp-tracking-widest rfp-uppercase rfp-text-accent\">\n Audio\n </p>\n </div>\n\n {/* 控制面板 */}\n <div\n className=\"rfp-w-full rfp-max-w-sm md:rfp-max-w-md rfp-rounded-2xl rfp-p-4 md:rfp-p-6 rfp-border rfp-bg-surface-1 rfp-border-line-weak\"\n style={{ backdropFilter: 'blur(16px)' }}\n >\n {/* 进度条 */}\n <div className=\"rfp-mb-5\">\n <div className=\"rfp-relative rfp-h-4 rfp-flex rfp-items-center\">\n <div className=\"rfp-absolute rfp-w-full rfp-h-[5px] rfp-rounded-full rfp-bg-surface-2\" />\n <div\n className=\"rfp-absolute rfp-h-[5px] rfp-rounded-full rfp-pointer-events-none\"\n style={{\n width: `${progress * 100}%`,\n background: 'linear-gradient(90deg, var(--fp-accent), var(--fp-accent-hover))',\n boxShadow: isPlaying ? '0 0 8px rgba(129,140,248,0.4)' : 'none',\n transition: 'width 0.1s linear',\n }}\n />\n <input\n type=\"range\"\n min=\"0\"\n max={duration > 0 ? duration : currentTime || 100}\n step=\"any\"\n value={currentTime}\n onChange={(e) => seek(parseFloat(e.target.value))}\n disabled={duration <= 0}\n aria-label={t('audio.aria.progress')}\n className=\"audio-slider rfp-absolute rfp-w-full\"\n />\n </div>\n <div className=\"rfp-flex rfp-justify-between rfp-text-xs rfp-mt-2.5 rfp-text-fg-tertiary\">\n <span style={{ fontVariantNumeric: 'tabular-nums' }}>{formatTime(currentTime)}</span>\n <span style={{ fontVariantNumeric: 'tabular-nums' }}>{duration > 0 ? formatTime(duration) : '--:--'}</span>\n </div>\n </div>\n\n {/* 控制按钮 */}\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-gap-3\">\n {/* 循环 */}\n <motion.button\n onClick={toggleLoop}\n whileHover={{ scale: 1.1 }}\n whileTap={{ scale: 0.92 }}\n aria-label={isLoop ? t('audio.aria.loop_off') : t('audio.aria.loop_on')}\n className={`rfp-w-9 rfp-h-9 rfp-rounded-full rfp-flex rfp-items-center rfp-justify-center rfp-transition-colors ${\n isLoop\n ? 'rfp-bg-accent-soft rfp-text-accent'\n : 'rfp-bg-surface-2 rfp-text-fg-tertiary'\n }`}\n >\n <Repeat className=\"rfp-w-4 rfp-h-4\" />\n </motion.button>\n\n {/* 后退 */}\n <motion.button\n onClick={() => skip(-10)}\n whileHover={{ scale: 1.1 }}\n whileTap={{ scale: 0.92 }}\n aria-label={t('audio.aria.backward_10')}\n className=\"rfp-w-10 rfp-h-10 rfp-rounded-full rfp-flex rfp-items-center rfp-justify-center rfp-transition-colors rfp-bg-surface-2 rfp-text-fg-secondary\"\n >\n <SkipBack className=\"rfp-w-[18px] rfp-h-[18px]\" />\n </motion.button>\n\n {/* 播放/暂停 */}\n <motion.button\n onClick={togglePlay}\n whileHover={{ scale: 1.06 }}\n whileTap={{ scale: 0.94 }}\n aria-label={isPlaying ? t('audio.aria.pause') : t('audio.aria.play')}\n className=\"rfp-w-14 rfp-h-14 rfp-rounded-full rfp-flex rfp-items-center rfp-justify-center\"\n style={{\n background: 'linear-gradient(135deg, var(--fp-accent-hover), var(--fp-accent))',\n color: '#fff',\n boxShadow: '0 4px 20px rgba(99,102,241,0.35)',\n }}\n >\n {isPlaying ? (\n <Pause className=\"rfp-w-6 rfp-h-6\" />\n ) : (\n <Play className=\"rfp-w-6 rfp-h-6 rfp-ml-0.5\" />\n )}\n </motion.button>\n\n {/* 前进 */}\n <motion.button\n onClick={() => skip(10)}\n whileHover={{ scale: 1.1 }}\n whileTap={{ scale: 0.92 }}\n aria-label={t('audio.aria.forward_10')}\n className=\"rfp-w-10 rfp-h-10 rfp-rounded-full rfp-flex rfp-items-center rfp-justify-center rfp-transition-colors rfp-bg-surface-2 rfp-text-fg-secondary\"\n >\n <SkipForward className=\"rfp-w-[18px] rfp-h-[18px]\" />\n </motion.button>\n\n {/* 音量 */}\n <div\n ref={volumeRef}\n className=\"rfp-relative\"\n onMouseEnter={handleVolumeEnter}\n onMouseLeave={handleVolumeLeave}\n >\n <motion.button\n onClick={toggleMute}\n whileHover={{ scale: 1.1 }}\n whileTap={{ scale: 0.92 }}\n aria-label={isMuted ? t('audio.aria.unmute') : t('audio.aria.mute')}\n className={`rfp-w-9 rfp-h-9 rfp-rounded-full rfp-flex rfp-items-center rfp-justify-center rfp-transition-colors ${\n showVolume\n ? 'rfp-bg-accent-soft rfp-text-accent'\n : 'rfp-bg-surface-2 rfp-text-fg-secondary'\n }`}\n >\n <VolumeIcon className=\"rfp-w-4 rfp-h-4\" />\n </motion.button>\n\n <AnimatePresence>\n {showVolume && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ duration: 0.12 }}\n className=\"rfp-absolute rfp-bottom-full rfp-mb-2 rfp-rounded-xl rfp-p-3 rfp-border rfp-bg-surface-3 rfp-border-line\"\n style={{\n left: '50%',\n marginLeft: '-27px',\n backdropFilter: 'blur(16px)',\n }}\n onMouseEnter={handleVolumeEnter}\n onMouseLeave={handleVolumeLeave}\n >\n <div className=\"rfp-flex rfp-flex-col rfp-items-center rfp-gap-2\" style={{ height: '100px' }}>\n <div className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center\" style={{ width: '24px', height: '80px' }}>\n <div\n className=\"rfp-absolute rfp-rounded-full rfp-bg-surface-2\"\n style={{ width: '3px', height: '100%' }}\n />\n <div\n className=\"rfp-absolute rfp-bottom-0 rfp-rounded-full rfp-pointer-events-none\"\n style={{\n width: '3px',\n height: `${(isMuted ? 0 : volume) * 100}%`,\n background: 'var(--fp-accent-hover)',\n transition: 'height 0.1s linear',\n }}\n />\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.01\"\n value={isMuted ? 0 : volume}\n onChange={(e) => setVolume(parseFloat(e.target.value))}\n aria-label={t('audio.aria.volume')}\n className=\"volume-slider-vertical rfp-absolute\"\n style={{\n width: '80px',\n height: '24px',\n transform: 'rotate(-90deg)',\n transformOrigin: 'center center',\n }}\n />\n </div>\n <span className=\"rfp-text-[10px] rfp-tabular-nums rfp-text-fg-tertiary\">\n {Math.round((isMuted ? 0 : volume) * 100)}\n </span>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n </div>\n </div>\n\n <audio ref={audioRef} src={url} className=\"rfp-hidden\" />\n </div>\n );\n};\n"],"names":["useAudioPlayer","url","audioRef","useRef","isPlaying","setIsPlaying","useState","isLoading","setIsLoading","currentTime","setCurrentTime","duration","setDuration","volume","setVolumeState","isMuted","setIsMuted","isLoop","setIsLoop","error","setError","useEffect","audio","onTimeUpdate","onDurationChange","onCanPlay","onWaiting","onPlaying","onPlay","onPause","onEnded","onError","togglePlay","useCallback","seek","time","skip","seconds","setVolume","vol","clamped","toggleMute","toggleLoop","next","formatTime","minutes","MarqueeText","text","className","style","containerRef","innerRef","overflow","setOverflow","scrollDist","setScrollDist","check","container","inner","cw","tw","observer","gap","totalScroll","dur","jsxs","motion","jsx","Tonearm","AudioRenderer","fileName","t","useTranslator","showVolume","setShowVolume","volumeRef","volumeTimerRef","progress","handleClickOutside","e","handleVolumeEnter","handleVolumeLeave","VolumeIcon","VolumeX","Volume1","Volume2","Repeat","SkipBack","Pause","Play","SkipForward","AnimatePresence"],"mappings":"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"}