@eternalheart/react-file-preview 1.3.9 → 1.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/README.zh-CN.md +10 -0
- package/lib/FilePreviewContent.d.ts.map +1 -1
- package/lib/chunks/{index-B-H9HQiI.mjs → index-B0JUZ5rS.mjs} +10 -10
- package/lib/chunks/{index-B-H9HQiI.mjs.map → index-B0JUZ5rS.mjs.map} +1 -1
- package/lib/chunks/{index-r3q2xCCI.mjs → index-BAYc4aBz.mjs} +2 -2
- package/lib/chunks/{index-r3q2xCCI.mjs.map → index-BAYc4aBz.mjs.map} +1 -1
- package/lib/chunks/{index-BNUiNUWa.mjs → index-BOQJNL71.mjs} +2 -2
- package/lib/chunks/{index-BNUiNUWa.mjs.map → index-BOQJNL71.mjs.map} +1 -1
- package/lib/chunks/{index-BdYkTSTt.mjs → index-BkU8rK-0.mjs} +3 -3
- package/lib/chunks/{index-BdYkTSTt.mjs.map → index-BkU8rK-0.mjs.map} +1 -1
- package/lib/chunks/{index-CgV8T0G5.mjs → index-BnDoXBnH.mjs} +2 -2
- package/lib/chunks/{index-CgV8T0G5.mjs.map → index-BnDoXBnH.mjs.map} +1 -1
- package/lib/chunks/index-C5YHI0Zs.mjs +160 -0
- package/lib/chunks/index-C5YHI0Zs.mjs.map +1 -0
- package/lib/chunks/{index-Bv93wiEK.mjs → index-CGNWXFy3.mjs} +716 -666
- package/lib/chunks/index-CGNWXFy3.mjs.map +1 -0
- package/lib/chunks/{index-DdOEWhrk.mjs → index-CwmZQ-JO.mjs} +16 -16
- package/lib/chunks/{index-DdOEWhrk.mjs.map → index-CwmZQ-JO.mjs.map} +1 -1
- package/lib/chunks/{index-CKirCT35.mjs → index-CzflrElZ.mjs} +5 -5
- package/lib/chunks/{index-CKirCT35.mjs.map → index-CzflrElZ.mjs.map} +1 -1
- package/lib/chunks/{index-D8GtNeDn.mjs → index-CztCCF7q.mjs} +2 -2
- package/lib/chunks/{index-D8GtNeDn.mjs.map → index-CztCCF7q.mjs.map} +1 -1
- package/lib/chunks/{index-BGeyzo6u.mjs → index-DKEcGewg.mjs} +2 -2
- package/lib/chunks/{index-BGeyzo6u.mjs.map → index-DKEcGewg.mjs.map} +1 -1
- package/lib/chunks/{index-DV5Jd7Qe.mjs → index-DN8BQIqo.mjs} +2 -2
- package/lib/chunks/{index-DV5Jd7Qe.mjs.map → index-DN8BQIqo.mjs.map} +1 -1
- package/lib/chunks/{index-zEVVgWCH.mjs → index-DPpUj8Yy.mjs} +2 -2
- package/lib/chunks/{index-zEVVgWCH.mjs.map → index-DPpUj8Yy.mjs.map} +1 -1
- package/lib/chunks/{index-BSD3w5eG.mjs → index-DSAXdrgU.mjs} +2 -2
- package/lib/chunks/{index-BSD3w5eG.mjs.map → index-DSAXdrgU.mjs.map} +1 -1
- package/lib/chunks/{index-DGuiWJr7.mjs → index-DveR0rOk.mjs} +15 -15
- package/lib/chunks/{index-DGuiWJr7.mjs.map → index-DveR0rOk.mjs.map} +1 -1
- package/lib/chunks/{index-BqEuP_8r.mjs → index-QfO-sASN.mjs} +2 -2
- package/lib/chunks/{index-BqEuP_8r.mjs.map → index-QfO-sASN.mjs.map} +1 -1
- package/lib/chunks/{index-BcBe6KW7.mjs → index-h9bO9wmq.mjs} +4 -4
- package/lib/chunks/{index-BcBe6KW7.mjs.map → index-h9bO9wmq.mjs.map} +1 -1
- package/lib/chunks/index-mvSVNKlQ.mjs +228 -0
- package/lib/chunks/index-mvSVNKlQ.mjs.map +1 -0
- package/lib/chunks/{index-U3w45GW8.mjs → index-tecGXW2S.mjs} +43 -43
- package/lib/chunks/{index-U3w45GW8.mjs.map → index-tecGXW2S.mjs.map} +1 -1
- package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs → useShikiHighlight-DHFYu0BU.mjs} +3 -3
- package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs.map → useShikiHighlight-DHFYu0BU.mjs.map} +1 -1
- package/lib/index.cjs +22 -18
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.mjs +13 -12
- package/lib/renderers/Font/index.d.ts +6 -0
- package/lib/renderers/Font/index.d.ts.map +1 -0
- package/lib/renderers/Pdf/index.d.ts +0 -1
- package/lib/renderers/Pdf/index.d.ts.map +1 -1
- package/lib/renderers/lazy.d.ts +2 -0
- package/lib/renderers/lazy.d.ts.map +1 -1
- package/lib/utils/pdfConfig.d.ts +2 -2
- package/lib/utils/pdfConfig.d.ts.map +1 -1
- package/package.json +3 -2
- package/lib/chunks/index-Bv93wiEK.mjs.map +0 -1
- package/lib/chunks/index-DmepcY31.mjs +0 -96
- package/lib/chunks/index-DmepcY31.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DdOEWhrk.mjs","sources":["../../src/renderers/Markdown/index.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport { Copy, Check } from 'lucide-react';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport 'katex/dist/katex.min.css';\n\ninterface MarkdownRendererProps {\n url: string;\n viewMode?: 'preview' | 'source';\n}\n\nconst useCopy = (text: string) => {\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [text]);\n return { copied, handleCopy };\n};\n\n/** 内联版复制按钮:放在代码块 header 行内,始终可见 */\nconst InlineCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-p-1 rfp-rounded rfp-text-fg-muted hover:rfp-text-fg-secondary rfp-transition-colors rfp-flex rfp-items-center rfp-gap-1\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n );\n};\n\n/** 浮动版复制按钮:无 header 时绝对定位于代码块右上角(hover 显示) */\nconst FloatingCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-absolute rfp-top-2 rfp-right-2 rfp-p-1.5 rfp-rounded-md rfp-bg-surface-2 hover:rfp-bg-surface-3 rfp-text-fg-tertiary hover:rfp-text-fg-secondary rfp-transition-colors rfp-opacity-0 group-hover:rfp-opacity-100 rfp-border rfp-border-line\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n );\n};\n\n/** 带语言标注的代码块:shiki 高亮 + header + 复制按钮 */\nconst ShikiCodeBlock = ({ code, lang }: { code: string; lang: string }) => {\n const { html } = useShikiHighlight(code, lang);\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-1.5 rfp-bg-surface-1 rfp-border rfp-border-line-weak rfp-rounded-t-md rfp-border-b-0\">\n <span className=\"rfp-text-xs rfp-text-fg-secondary rfp-font-mono rfp-select-none\">{lang}</span>\n <InlineCopyButton text={code} />\n </div>\n {html ? (\n <div\n className=\"rfp-shiki-wrapper rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : (\n <pre\n className=\"rfp-m-0 rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{code}</code>\n </pre>\n )}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url, viewMode = 'preview' }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const { html: sourceHtml } = useShikiHighlight(\n viewMode === 'source' ? content : '',\n 'markdown',\n );\n\n useEffect(() => {\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher });\n setContent(text);\n } catch (err) {\n setError(t('markdown.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n }, [url, fetcher, t]);\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) {\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 // 源码视图\n if (viewMode === 'source') {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {sourceHtml ? (\n <div\n className=\"rfp-shiki-wrapper with-line-numbers\"\n dangerouslySetInnerHTML={{ __html: sourceHtml }}\n />\n ) : (\n <pre className=\"rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n )}\n </div>\n );\n }\n\n // 预览视图\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-p-6 md:rfp-p-10\">\n <div className=\"rfp-max-w-full md:rfp-max-w-4xl rfp-mx-auto\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm, remarkMath]}\n rehypePlugins={[rehypeRaw, rehypeKatex]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n const codeString = String(children).replace(/\\n$/, '');\n if (!inline && match) {\n // 有语言标注的代码块 - shiki 高亮\n return <ShikiCodeBlock code={codeString} lang={match[1]} />;\n }\n if (!inline) {\n // 无语言标注的代码块 - 纯文本暗色显示\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <FloatingCopyButton text={codeString} />\n <pre\n className=\"rfp-m-0 rfp-rounded-md rfp-border rfp-border-line-weak rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{children}</code>\n </pre>\n </div>\n );\n }\n // 行内代码\n return (\n <code\n className=\"rfp-bg-surface-2 rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-text-sm rfp-font-mono rfp-text-fg-primary rfp-border rfp-border-line-weak\"\n {...props}\n >\n {children}\n </code>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"rfp-text-3xl rfp-font-semibold rfp-mb-4 rfp-mt-6 rfp-text-fg-primary first:rfp-mt-0\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"rfp-text-2xl rfp-font-semibold rfp-mb-3 rfp-mt-8 rfp-text-fg-primary\">\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"rfp-text-xl rfp-font-semibold rfp-mb-2 rfp-mt-6 rfp-text-fg-primary\">{children}</h3>\n ),\n h4: ({ children }) => (\n <h4 className=\"rfp-text-lg rfp-font-semibold rfp-mb-2 rfp-mt-4 rfp-text-fg-primary\">{children}</h4>\n ),\n p: ({ children }) => (\n <p className=\"rfp-text-fg-secondary rfp-mb-4 rfp-leading-7 rfp-text-base\">{children}</p>\n ),\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"rfp-text-indigo-400 hover:rfp-text-indigo-300 rfp-underline rfp-decoration-indigo-600 hover:rfp-decoration-indigo-400\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => (\n <ul className=\"rfp-list-disc rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ul>\n ),\n ol: ({ children }) => (\n <ol className=\"rfp-list-decimal rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ol>\n ),\n li: ({ children }) => <li className=\"rfp-leading-7\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"rfp-border-l-4 rfp-border-line-strong rfp-pl-4 rfp-text-fg-tertiary rfp-my-4 rfp-italic\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"rfp-overflow-x-auto rfp-my-4 rfp-rounded-md rfp-border rfp-border-line\">\n <table className=\"rfp-min-w-full rfp-divide-y rfp-divide-divide\">{children}</table>\n </div>\n ),\n thead: ({ children }) => <thead className=\"rfp-bg-surface-1\">{children}</thead>,\n tbody: ({ children }) => (\n <tbody className=\"rfp-divide-y rfp-divide-divide rfp-bg-transparent\">{children}</tbody>\n ),\n tr: ({ children }) => (\n <tr className=\"hover:rfp-bg-surface-1 rfp-transition-colors\">{children}</tr>\n ),\n th: ({ children }) => (\n <th className=\"rfp-px-4 rfp-py-3 rfp-text-left rfp-text-xs rfp-font-semibold rfp-text-fg-tertiary rfp-uppercase rfp-tracking-wider\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"rfp-px-4 rfp-py-3 rfp-text-sm rfp-text-fg-secondary\">{children}</td>\n ),\n hr: () => <hr className=\"rfp-border-line rfp-my-6\" />,\n img: ({ src, alt }) => (\n <img\n src={src}\n alt={alt}\n className=\"rfp-rounded-md rfp-max-w-full rfp-h-auto rfp-my-4 rfp-mx-auto rfp-block rfp-shadow-sm\"\n />\n ),\n input: ({ type, checked, ...props }) => {\n if (type === 'checkbox') {\n return (\n <input\n type=\"checkbox\"\n checked={checked}\n readOnly\n className=\"rfp-mr-2 rfp-rounded rfp-border-line\"\n {...props}\n />\n );\n }\n return <input type={type} {...props} />;\n },\n strong: ({ children }) => (\n <strong className=\"rfp-font-semibold rfp-text-fg-primary\">{children}</strong>\n ),\n em: ({ children }) => <em className=\"rfp-italic\">{children}</em>,\n del: ({ children }) => (\n <del className=\"rfp-text-fg-muted rfp-line-through\">{children}</del>\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n );\n};\n"],"names":["useCopy","text","copied","setCopied","useState","handleCopy","useCallback","textarea","InlineCopyButton","t","useTranslator","jsx","Check","Copy","FloatingCopyButton","ShikiCodeBlock","code","lang","html","useShikiHighlight","jsxs","MarkdownRenderer","url","viewMode","fetcher","useFetcher","content","setContent","loading","setLoading","error","setError","sourceHtml","useEffect","fetchTextUtf8","err","ReactMarkdown","remarkGfm","remarkMath","rehypeRaw","rehypeKatex","node","inline","className","children","props","match","codeString","href","src","alt","type","checked"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-CwmZQ-JO.mjs","sources":["../../src/renderers/Markdown/index.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport { Copy, Check } from 'lucide-react';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport 'katex/dist/katex.min.css';\n\ninterface MarkdownRendererProps {\n url: string;\n viewMode?: 'preview' | 'source';\n}\n\nconst useCopy = (text: string) => {\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [text]);\n return { copied, handleCopy };\n};\n\n/** 内联版复制按钮:放在代码块 header 行内,始终可见 */\nconst InlineCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-p-1 rfp-rounded rfp-text-fg-muted hover:rfp-text-fg-secondary rfp-transition-colors rfp-flex rfp-items-center rfp-gap-1\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n );\n};\n\n/** 浮动版复制按钮:无 header 时绝对定位于代码块右上角(hover 显示) */\nconst FloatingCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-absolute rfp-top-2 rfp-right-2 rfp-p-1.5 rfp-rounded-md rfp-bg-surface-2 hover:rfp-bg-surface-3 rfp-text-fg-tertiary hover:rfp-text-fg-secondary rfp-transition-colors rfp-opacity-0 group-hover:rfp-opacity-100 rfp-border rfp-border-line\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n );\n};\n\n/** 带语言标注的代码块:shiki 高亮 + header + 复制按钮 */\nconst ShikiCodeBlock = ({ code, lang }: { code: string; lang: string }) => {\n const { html } = useShikiHighlight(code, lang);\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-1.5 rfp-bg-surface-1 rfp-border rfp-border-line-weak rfp-rounded-t-md rfp-border-b-0\">\n <span className=\"rfp-text-xs rfp-text-fg-secondary rfp-font-mono rfp-select-none\">{lang}</span>\n <InlineCopyButton text={code} />\n </div>\n {html ? (\n <div\n className=\"rfp-shiki-wrapper rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : (\n <pre\n className=\"rfp-m-0 rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{code}</code>\n </pre>\n )}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url, viewMode = 'preview' }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const { html: sourceHtml } = useShikiHighlight(\n viewMode === 'source' ? content : '',\n 'markdown',\n );\n\n useEffect(() => {\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher });\n setContent(text);\n } catch (err) {\n setError(t('markdown.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n }, [url, fetcher, t]);\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) {\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 // 源码视图\n if (viewMode === 'source') {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {sourceHtml ? (\n <div\n className=\"rfp-shiki-wrapper with-line-numbers\"\n dangerouslySetInnerHTML={{ __html: sourceHtml }}\n />\n ) : (\n <pre className=\"rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n )}\n </div>\n );\n }\n\n // 预览视图\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-p-6 md:rfp-p-10\">\n <div className=\"rfp-max-w-full md:rfp-max-w-4xl rfp-mx-auto\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm, remarkMath]}\n rehypePlugins={[rehypeRaw, rehypeKatex]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n const codeString = String(children).replace(/\\n$/, '');\n if (!inline && match) {\n // 有语言标注的代码块 - shiki 高亮\n return <ShikiCodeBlock code={codeString} lang={match[1]} />;\n }\n if (!inline) {\n // 无语言标注的代码块 - 纯文本暗色显示\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <FloatingCopyButton text={codeString} />\n <pre\n className=\"rfp-m-0 rfp-rounded-md rfp-border rfp-border-line-weak rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{children}</code>\n </pre>\n </div>\n );\n }\n // 行内代码\n return (\n <code\n className=\"rfp-bg-surface-2 rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-text-sm rfp-font-mono rfp-text-fg-primary rfp-border rfp-border-line-weak\"\n {...props}\n >\n {children}\n </code>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"rfp-text-3xl rfp-font-semibold rfp-mb-4 rfp-mt-6 rfp-text-fg-primary first:rfp-mt-0\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"rfp-text-2xl rfp-font-semibold rfp-mb-3 rfp-mt-8 rfp-text-fg-primary\">\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"rfp-text-xl rfp-font-semibold rfp-mb-2 rfp-mt-6 rfp-text-fg-primary\">{children}</h3>\n ),\n h4: ({ children }) => (\n <h4 className=\"rfp-text-lg rfp-font-semibold rfp-mb-2 rfp-mt-4 rfp-text-fg-primary\">{children}</h4>\n ),\n p: ({ children }) => (\n <p className=\"rfp-text-fg-secondary rfp-mb-4 rfp-leading-7 rfp-text-base\">{children}</p>\n ),\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"rfp-text-indigo-400 hover:rfp-text-indigo-300 rfp-underline rfp-decoration-indigo-600 hover:rfp-decoration-indigo-400\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => (\n <ul className=\"rfp-list-disc rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ul>\n ),\n ol: ({ children }) => (\n <ol className=\"rfp-list-decimal rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ol>\n ),\n li: ({ children }) => <li className=\"rfp-leading-7\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"rfp-border-l-4 rfp-border-line-strong rfp-pl-4 rfp-text-fg-tertiary rfp-my-4 rfp-italic\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"rfp-overflow-x-auto rfp-my-4 rfp-rounded-md rfp-border rfp-border-line\">\n <table className=\"rfp-min-w-full rfp-divide-y rfp-divide-divide\">{children}</table>\n </div>\n ),\n thead: ({ children }) => <thead className=\"rfp-bg-surface-1\">{children}</thead>,\n tbody: ({ children }) => (\n <tbody className=\"rfp-divide-y rfp-divide-divide rfp-bg-transparent\">{children}</tbody>\n ),\n tr: ({ children }) => (\n <tr className=\"hover:rfp-bg-surface-1 rfp-transition-colors\">{children}</tr>\n ),\n th: ({ children }) => (\n <th className=\"rfp-px-4 rfp-py-3 rfp-text-left rfp-text-xs rfp-font-semibold rfp-text-fg-tertiary rfp-uppercase rfp-tracking-wider\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"rfp-px-4 rfp-py-3 rfp-text-sm rfp-text-fg-secondary\">{children}</td>\n ),\n hr: () => <hr className=\"rfp-border-line rfp-my-6\" />,\n img: ({ src, alt }) => (\n <img\n src={src}\n alt={alt}\n className=\"rfp-rounded-md rfp-max-w-full rfp-h-auto rfp-my-4 rfp-mx-auto rfp-block rfp-shadow-sm\"\n />\n ),\n input: ({ type, checked, ...props }) => {\n if (type === 'checkbox') {\n return (\n <input\n type=\"checkbox\"\n checked={checked}\n readOnly\n className=\"rfp-mr-2 rfp-rounded rfp-border-line\"\n {...props}\n />\n );\n }\n return <input type={type} {...props} />;\n },\n strong: ({ children }) => (\n <strong className=\"rfp-font-semibold rfp-text-fg-primary\">{children}</strong>\n ),\n em: ({ children }) => <em className=\"rfp-italic\">{children}</em>,\n del: ({ children }) => (\n <del className=\"rfp-text-fg-muted rfp-line-through\">{children}</del>\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n );\n};\n"],"names":["useCopy","text","copied","setCopied","useState","handleCopy","useCallback","textarea","InlineCopyButton","t","useTranslator","jsx","Check","Copy","FloatingCopyButton","ShikiCodeBlock","code","lang","html","useShikiHighlight","jsxs","MarkdownRenderer","url","viewMode","fetcher","useFetcher","content","setContent","loading","setLoading","error","setError","sourceHtml","useEffect","fetchTextUtf8","err","ReactMarkdown","remarkGfm","remarkMath","rehypeRaw","rehypeKatex","node","inline","className","children","props","match","codeString","href","src","alt","type","checked"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as r } from "react/jsx-runtime";
|
|
2
2
|
import { useState as l, useEffect as x } from "react";
|
|
3
|
-
import { u as w, a as b,
|
|
4
|
-
import { u as y } from "./useShikiHighlight-
|
|
5
|
-
const
|
|
3
|
+
import { u as w, a as b, p as N, F as v } from "./index-CGNWXFy3.mjs";
|
|
4
|
+
import { u as y } from "./useShikiHighlight-DHFYu0BU.mjs";
|
|
5
|
+
const _ = ({
|
|
6
6
|
url: s,
|
|
7
7
|
fileName: a,
|
|
8
8
|
wordWrap: n = !0,
|
|
@@ -47,6 +47,6 @@ const E = ({
|
|
|
47
47
|
) });
|
|
48
48
|
};
|
|
49
49
|
export {
|
|
50
|
-
|
|
50
|
+
_ as TextRenderer
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=index-
|
|
52
|
+
//# sourceMappingURL=index-CzflrElZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-CzflrElZ.mjs","sources":["../../src/renderers/Text/index.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { fetchTextUtf8, getLanguageFromFileName } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n wordWrap?: boolean;\n htmlPreview?: boolean;\n}\n\nexport const TextRenderer: React.FC<TextRendererProps> = ({\n url,\n fileName,\n wordWrap = true,\n htmlPreview = false,\n}) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const language = getLanguageFromFileName(fileName);\n const { html: highlighted } = useShikiHighlight(\n language !== 'text' ? content : '',\n language,\n );\n\n useEffect(() => {\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher });\n setContent(text);\n } catch (err) {\n setError(t('text.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"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) {\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 // HTML 预览模式\n if (htmlPreview && (language === 'html')) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-bg-surface-toolbar\">\n <iframe\n srcDoc={content}\n sandbox=\"allow-same-origin\"\n className=\"rfp-w-full rfp-h-full rfp-border-0\"\n title={fileName}\n />\n </div>\n );\n }\n\n // 源码模式\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {language === 'text' || !highlighted ? (\n <pre\n className={`rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${\n wordWrap ? 'rfp-whitespace-pre-wrap rfp-break-words' : 'rfp-whitespace-pre'\n }`}\n >\n {content}\n </pre>\n ) : (\n <div\n className={`rfp-shiki-wrapper with-line-numbers ${wordWrap ? '' : 'no-wrap'}`}\n dangerouslySetInnerHTML={{ __html: highlighted }}\n />\n )}\n </div>\n );\n};\n"],"names":["TextRenderer","url","fileName","wordWrap","htmlPreview","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","language","getLanguageFromFileName","highlighted","useShikiHighlight","useEffect","text","fetchTextUtf8","err","jsx"],"mappings":";;;;AAaO,MAAMA,IAA4C,CAAC;AAAA,EACxD,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,aAAAC,IAAc;AAChB,MAAM;AACJ,QAAMC,IAAIC,EAAA,GACJC,IAAUC,EAAA,GACV,CAACC,GAASC,CAAU,IAAIC,EAAiB,EAAE,GAC3C,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAI,GACrC,CAACG,GAAOC,CAAQ,IAAIJ,EAAwB,IAAI,GAChDK,IAAWC,EAAwBf,CAAQ,GAC3C,EAAE,MAAMgB,EAAA,IAAgBC;AAAA,IAC5BH,MAAa,SAASP,IAAU;AAAA,IAChCO;AAAA,EAAA;AAqBF,SAlBAI,EAAU,MAAM;AAed,KAdiB,YAAY;AAC3B,UAAI;AACF,QAAAP,EAAW,EAAI,GACfE,EAAS,IAAI;AACb,cAAMM,IAAO,MAAMC,EAAcrB,GAAK,EAAE,SAAAM,GAAS;AACjD,QAAAG,EAAWW,CAAI;AAAA,MACjB,SAASE,GAAK;AACZ,QAAAR,EAASV,EAAE,kBAAkB,CAAC,GAC9B,QAAQ,MAAMkB,CAAG;AAAA,MACnB,UAAA;AACE,QAAAV,EAAW,EAAK;AAAA,MAClB;AAAA,IACF,GAEA;AAAA,EACF,GAAG,CAACZ,CAAG,CAAC,GAEJW,IAEA,gBAAAY,EAAC,SAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI,IAIAV,IAEA,gBAAAU,EAAC,OAAA,EAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,yCACb,UAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,eAAe,UAAAV,EAAA,CAAM,GACpC,GACF,IAKAV,KAAgBY,MAAa,SAE7B,gBAAAQ,EAAC,OAAA,EAAI,WAAU,gDACb,UAAA,gBAAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAQf;AAAA,MACR,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,OAAOP;AAAA,IAAA;AAAA,EAAA,GAEX,sBAMD,OAAA,EAAI,WAAU,0DACZ,UAAAc,MAAa,UAAU,CAACE,IACvB,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,yDACTrB,IAAW,4CAA4C,oBACzD;AAAA,MAEC,UAAAM;AAAA,IAAA;AAAA,EAAA,IAGH,gBAAAe;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,uCAAuCrB,IAAW,KAAK,SAAS;AAAA,MAC3E,yBAAyB,EAAE,QAAQe,EAAA;AAAA,IAAY;AAAA,EAAA,GAGrD;AAEJ;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as U, jsx as m } from "react/jsx-runtime";
|
|
2
2
|
import { useState as a, useRef as W, useEffect as M, useCallback as b } from "react";
|
|
3
3
|
import { motion as S } from "framer-motion";
|
|
4
|
-
import { u as V } from "./index-
|
|
4
|
+
import { u as V } from "./index-CGNWXFy3.mjs";
|
|
5
5
|
const et = ({
|
|
6
6
|
url: j,
|
|
7
7
|
zoom: B,
|
|
@@ -113,4 +113,4 @@ const et = ({
|
|
|
113
113
|
export {
|
|
114
114
|
et as ImageRenderer
|
|
115
115
|
};
|
|
116
|
-
//# sourceMappingURL=index-
|
|
116
|
+
//# sourceMappingURL=index-CztCCF7q.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-D8GtNeDn.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n resetKey?: number;\n fileSize?: number;\n onZoomChange?: (zoom: number) => void;\n onNaturalWidthChange?: (width: number) => void;\n onNaturalHeightChange?: (height: number) => void;\n}\n\nexport const ImageRenderer: React.FC<ImageRendererProps> = ({\n url,\n zoom,\n rotation,\n resetKey,\n fileSize,\n onZoomChange,\n onNaturalWidthChange,\n onNaturalHeightChange\n}) => {\n const t = useTranslator();\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [internalZoom, setInternalZoom] = useState(1);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n const imgRef = useRef<HTMLImageElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLoaded(false);\n setError(null);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n }, [url]);\n\n // 当外部 zoom 改变时,同步内部 zoom\n useEffect(() => {\n setInternalZoom(zoom);\n }, [zoom]);\n\n // 适应窗口/原始尺寸等操作时重置位置居中\n useEffect(() => {\n if (resetKey !== undefined) {\n setPosition({ x: 0, y: 0 });\n }\n }, [resetKey]);\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n setNaturalSize({ width: img.naturalWidth, height: img.naturalHeight });\n onNaturalWidthChange?.(img.naturalWidth);\n onNaturalHeightChange?.(img.naturalHeight);\n };\n\n // 边界限制:确保图片至少有一部分可见\n const clampPosition = useCallback((pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.current;\n if (!container || naturalSize.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.width * currentZoom;\n const imgH = naturalSize.height * currentZoom;\n\n // 至少保留 margin px 的图片在视口内\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n }, [naturalSize]);\n\n const handleError = () => {\n setError(t('image.load_failed'));\n setLoaded(true);\n };\n\n // 双击复原:居中 + 缩放100%\n const handleDoubleClick = () => {\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n onZoomChange?.(1);\n };\n\n // 鼠标滚轮缩放 —— 以鼠标位置为缩放原点\n // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setInternalZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n onZoomChange?.(newZoom);\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [onZoomChange, clampPosition]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, internalZoom));\n }, [isDragging, dragStart, internalZoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {!loaded && !error && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center\">\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 {error && (\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n <motion.img\n ref={imgRef}\n src={url}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded ? 'rfp-hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${internalZoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n\n {/* 右下角分辨率 */}\n {loaded && !error && naturalSize.width > 0 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default\">\n {naturalSize.width} × {naturalSize.height}{fileSize != null && ` · ${fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`}`}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageRenderer","url","zoom","rotation","resetKey","fileSize","onZoomChange","onNaturalWidthChange","onNaturalHeightChange","t","useTranslator","loaded","setLoaded","useState","error","setError","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","naturalSize","setNaturalSize","imgRef","useRef","containerRef","useEffect","handleLoad","e","img","clampPosition","useCallback","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleWheelNative","rect","mouseX","mouseY","delta","prev","newZoom","scale","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","motion"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-CztCCF7q.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n resetKey?: number;\n fileSize?: number;\n onZoomChange?: (zoom: number) => void;\n onNaturalWidthChange?: (width: number) => void;\n onNaturalHeightChange?: (height: number) => void;\n}\n\nexport const ImageRenderer: React.FC<ImageRendererProps> = ({\n url,\n zoom,\n rotation,\n resetKey,\n fileSize,\n onZoomChange,\n onNaturalWidthChange,\n onNaturalHeightChange\n}) => {\n const t = useTranslator();\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [internalZoom, setInternalZoom] = useState(1);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n const imgRef = useRef<HTMLImageElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLoaded(false);\n setError(null);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n }, [url]);\n\n // 当外部 zoom 改变时,同步内部 zoom\n useEffect(() => {\n setInternalZoom(zoom);\n }, [zoom]);\n\n // 适应窗口/原始尺寸等操作时重置位置居中\n useEffect(() => {\n if (resetKey !== undefined) {\n setPosition({ x: 0, y: 0 });\n }\n }, [resetKey]);\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n setNaturalSize({ width: img.naturalWidth, height: img.naturalHeight });\n onNaturalWidthChange?.(img.naturalWidth);\n onNaturalHeightChange?.(img.naturalHeight);\n };\n\n // 边界限制:确保图片至少有一部分可见\n const clampPosition = useCallback((pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.current;\n if (!container || naturalSize.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.width * currentZoom;\n const imgH = naturalSize.height * currentZoom;\n\n // 至少保留 margin px 的图片在视口内\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n }, [naturalSize]);\n\n const handleError = () => {\n setError(t('image.load_failed'));\n setLoaded(true);\n };\n\n // 双击复原:居中 + 缩放100%\n const handleDoubleClick = () => {\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n onZoomChange?.(1);\n };\n\n // 鼠标滚轮缩放 —— 以鼠标位置为缩放原点\n // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setInternalZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n onZoomChange?.(newZoom);\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [onZoomChange, clampPosition]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, internalZoom));\n }, [isDragging, dragStart, internalZoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {!loaded && !error && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center\">\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 {error && (\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n <motion.img\n ref={imgRef}\n src={url}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded ? 'rfp-hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${internalZoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n\n {/* 右下角分辨率 */}\n {loaded && !error && naturalSize.width > 0 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default\">\n {naturalSize.width} × {naturalSize.height}{fileSize != null && ` · ${fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`}`}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageRenderer","url","zoom","rotation","resetKey","fileSize","onZoomChange","onNaturalWidthChange","onNaturalHeightChange","t","useTranslator","loaded","setLoaded","useState","error","setError","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","naturalSize","setNaturalSize","imgRef","useRef","containerRef","useEffect","handleLoad","e","img","clampPosition","useCallback","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleWheelNative","rect","mouseX","mouseY","delta","prev","newZoom","scale","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","motion"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as e, jsxs as a } from "react/jsx-runtime";
|
|
2
2
|
import { useState as u, useRef as v, useEffect as g } from "react";
|
|
3
3
|
import x from "video.js";
|
|
4
|
-
import { u as y } from "./index-
|
|
4
|
+
import { u as y } from "./index-CGNWXFy3.mjs";
|
|
5
5
|
const b = (r) => {
|
|
6
6
|
var s;
|
|
7
7
|
const o = ((s = r.split(".").pop()) == null ? void 0 : s.toLowerCase().split("?")[0]) || "";
|
|
@@ -93,4 +93,4 @@ const b = (r) => {
|
|
|
93
93
|
export {
|
|
94
94
|
L as VideoRenderer
|
|
95
95
|
};
|
|
96
|
-
//# sourceMappingURL=index-
|
|
96
|
+
//# sourceMappingURL=index-DKEcGewg.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DKEcGewg.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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"}
|
|
@@ -2,7 +2,7 @@ import { jsxs as x, jsx as n } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as lr, useRef as c, useState as p, useCallback as l, useImperativeHandle as cr, useEffect as pr } from "react";
|
|
3
3
|
import { X as dr } from "lucide-react";
|
|
4
4
|
import "foliate-js/view.js";
|
|
5
|
-
import { u as ur, a as mr } from "./index-
|
|
5
|
+
import { u as ur, a as mr } from "./index-CGNWXFy3.mjs";
|
|
6
6
|
const hr = `
|
|
7
7
|
@namespace epub "http://www.idpf.org/2007/ops";
|
|
8
8
|
html { color-scheme: light; }
|
|
@@ -190,4 +190,4 @@ xr.displayName = "MobiRenderer";
|
|
|
190
190
|
export {
|
|
191
191
|
xr as MobiRenderer
|
|
192
192
|
};
|
|
193
|
-
//# sourceMappingURL=index-
|
|
193
|
+
//# sourceMappingURL=index-DN8BQIqo.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DV5Jd7Qe.mjs","sources":["../../src/renderers/Mobi/index.tsx"],"sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n} from 'react';\nimport { X } from 'lucide-react';\nimport 'foliate-js/view.js';\nimport type { FoliateView, TocItem } from 'foliate-js/view.js';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\nconst READER_CSS = `\n @namespace epub \"http://www.idpf.org/2007/ops\";\n html { color-scheme: light; }\n body {\n background: #ffffff !important;\n color: #1a1a1a !important;\n font-family: \"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important;\n font-size: 16px !important;\n line-height: 2 !important;\n max-width: 100% !important;\n box-sizing: border-box !important;\n word-break: break-word !important;\n overflow-wrap: break-word !important;\n }\n p, li, blockquote, dd { line-height: 2; text-align: justify; }\n p { text-indent: 2em; margin: 0.8em 0; }\n h1 { text-align: center; margin: 1.5em 0 1em; }\n h2 { margin: 1.2em 0 0.8em; }\n h3 { margin: 1em 0 0.6em; }\n img { max-width: 100% !important; height: auto !important; }\n a { color: #2563eb; text-decoration: none; }\n pre { white-space: pre-wrap !important; }\n`;\n\nconst A4_WIDTH = 794;\n\nexport interface MobiRendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface MobiRendererProps {\n url: string;\n onChapterChange?: (current: number, total: number) => void;\n onFullWidthChange?: (isFullWidth: boolean) => void;\n}\n\nexport const MobiRenderer = forwardRef<MobiRendererHandle, MobiRendererProps>(\n ({ url, onChapterChange, onFullWidthChange }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const hostRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<FoliateView | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n // 模拟 epub.js 的 locations 显示\n const totalLocationsRef = useRef(1);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const [isFullWidth, setIsFullWidth] = useState(false);\n const isFullWidthRef = useRef(false);\n isFullWidthRef.current = isFullWidth;\n\n const reportProgress = useCallback((current: number, total: number) => {\n if (total > 0) totalLocationsRef.current = total;\n onChapterChangeRef.current?.(Math.max(1, current + 1), totalLocationsRef.current);\n }, []);\n\n const handlePrev = useCallback(() => {\n const view = viewRef.current;\n if (!view) return;\n view.prev().catch(() => {});\n }, []);\n\n const handleNext = useCallback(() => {\n const view = viewRef.current;\n if (!view) return;\n view.next().catch(() => {});\n }, []);\n\n const toggleToc = useCallback(() => setShowToc((prev) => !prev), []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 宽度改变后 paginator 需要重新分页\n const view = viewRef.current;\n if (!view) return;\n const renderer = (view as unknown as { renderer?: HTMLElement }).renderer;\n if (renderer) {\n renderer.setAttribute('max-inline-size', newVal ? '9999' : '720');\n }\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n setShowToc(false);\n viewRef.current?.goTo(href).catch(() => {});\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n setActiveTocHref('');\n host.replaceChildren();\n\n let cancelled = false;\n let view: FoliateView | null = null;\n\n const load = async () => {\n try {\n if (cancelled) return;\n\n view = document.createElement('foliate-view') as FoliateView;\n host.appendChild(view);\n viewRef.current = view;\n\n // 先注册事件\n view.addEventListener('relocate', (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail) return;\n // SectionProgress 返回的 location 对象: { current, next, total }\n const loc = detail.location as { current?: number; total?: number } | undefined;\n if (loc && typeof loc.current === 'number' && typeof loc.total === 'number') {\n reportProgress(loc.current, loc.total);\n } else {\n // fallback:用 section 级别估算\n const sections = viewRef.current?.book?.sections ?? [];\n const idx = detail.index ?? 0;\n const frac = detail.fraction ?? 0;\n const total = Math.max(sections.length, 1);\n const current = Math.round((idx + frac) / total * total);\n reportProgress(current, total);\n }\n const tocItem = detail.tocItem as { href?: string } | undefined;\n if (tocItem?.href) {\n setActiveTocHref(tocItem.href);\n }\n });\n\n const res = await fetcher(url);\n if (!res.ok) throw new Error(`请求失败: ${res.status}`);\n const blob = await res.blob();\n let name = 'book.mobi';\n try {\n const u = new URL(url, window.location.href);\n const base = u.pathname.split('/').pop();\n if (base) name = decodeURIComponent(base);\n } catch { /* blob: URL */ }\n const file = new File([blob], name);\n\n await view.open(file);\n if (cancelled) { view.book?.destroy?.(); return; }\n\n // 配置 paginator:paginated 模式(默认),带动画\n const renderer = (view as unknown as { renderer: HTMLElement & {\n setStyles?: (css: string) => void;\n next?: () => Promise<void>;\n } }).renderer;\n\n if (renderer) {\n // flow=\"paginated\" 是默认值,不需要显式设置\n renderer.setAttribute('animated', '');\n renderer.setAttribute('max-inline-size', '720');\n renderer.setAttribute('margin', '48');\n renderer.setAttribute('gap', '5%');\n renderer.setStyles?.(READER_CSS);\n // 必须调 next() 渲染首页\n await renderer.next?.();\n }\n\n setToc(view.book?.toc ?? []);\n setLoading(false);\n reportProgress(0, view.book?.sections.length ?? 1);\n } catch (err) {\n console.error('MOBI/AZW3 加载错误:', err);\n if (!cancelled) {\n setError(t('mobi.load_failed'));\n setLoading(false);\n }\n }\n };\n\n load();\n\n return () => {\n cancelled = true;\n try { viewRef.current?.book?.destroy?.(); } catch { /* ignore */ }\n viewRef.current = null;\n host.replaceChildren();\n };\n }, [url, reportProgress]);\n\n const isActive = useCallback(\n (href: string | undefined) => !!href && href === activeTocHref,\n [activeTocHref]\n );\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ listStyle: 'none', padding: 0, margin: depth > 0 ? '0 0 0 16px' : 0 }}>\n {items.map((item, i) => (\n <li key={`${item.href ?? item.label}-${i}`}>\n {item.href ? (\n <button\n onClick={() => handleTocClick(item.href!)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${\n isActive(item.href)\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label?.trim()}\n </button>\n ) : (\n <div className=\"rfp-w-full rfp-py-2 rfp-px-3 rfp-text-sm rfp-text-fg-tertiary rfp-truncate\">\n {item.label?.trim()}\n </div>\n )}\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n ))}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden\">\n {error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center rfp-p-6\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\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 {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{ opacity: showToc ? 1 : 0, pointerEvents: showToc ? 'auto' : 'none' }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={hostRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n }}\n />\n )}\n </div>\n );\n }\n);\n\nMobiRenderer.displayName = 'MobiRenderer';\n"],"names":["READER_CSS","A4_WIDTH","MobiRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","fetcher","useFetcher","hostRef","useRef","viewRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","loading","setLoading","useState","error","setError","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","isFullWidth","setIsFullWidth","isFullWidthRef","reportProgress","useCallback","current","total","_a","handlePrev","view","handleNext","toggleToc","prev","toggleFullWidth","newVal","renderer","handleTocClick","href","useImperativeHandle","useEffect","host","cancelled","e","detail","loc","sections","_b","idx","frac","tocItem","res","blob","name","base","file","_c","_d","_e","_f","err","isActive","renderTocItems","items","depth","item","i","jsxs","jsx","X"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-DN8BQIqo.mjs","sources":["../../src/renderers/Mobi/index.tsx"],"sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n} from 'react';\nimport { X } from 'lucide-react';\nimport 'foliate-js/view.js';\nimport type { FoliateView, TocItem } from 'foliate-js/view.js';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\nconst READER_CSS = `\n @namespace epub \"http://www.idpf.org/2007/ops\";\n html { color-scheme: light; }\n body {\n background: #ffffff !important;\n color: #1a1a1a !important;\n font-family: \"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important;\n font-size: 16px !important;\n line-height: 2 !important;\n max-width: 100% !important;\n box-sizing: border-box !important;\n word-break: break-word !important;\n overflow-wrap: break-word !important;\n }\n p, li, blockquote, dd { line-height: 2; text-align: justify; }\n p { text-indent: 2em; margin: 0.8em 0; }\n h1 { text-align: center; margin: 1.5em 0 1em; }\n h2 { margin: 1.2em 0 0.8em; }\n h3 { margin: 1em 0 0.6em; }\n img { max-width: 100% !important; height: auto !important; }\n a { color: #2563eb; text-decoration: none; }\n pre { white-space: pre-wrap !important; }\n`;\n\nconst A4_WIDTH = 794;\n\nexport interface MobiRendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface MobiRendererProps {\n url: string;\n onChapterChange?: (current: number, total: number) => void;\n onFullWidthChange?: (isFullWidth: boolean) => void;\n}\n\nexport const MobiRenderer = forwardRef<MobiRendererHandle, MobiRendererProps>(\n ({ url, onChapterChange, onFullWidthChange }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const hostRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<FoliateView | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n // 模拟 epub.js 的 locations 显示\n const totalLocationsRef = useRef(1);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const [isFullWidth, setIsFullWidth] = useState(false);\n const isFullWidthRef = useRef(false);\n isFullWidthRef.current = isFullWidth;\n\n const reportProgress = useCallback((current: number, total: number) => {\n if (total > 0) totalLocationsRef.current = total;\n onChapterChangeRef.current?.(Math.max(1, current + 1), totalLocationsRef.current);\n }, []);\n\n const handlePrev = useCallback(() => {\n const view = viewRef.current;\n if (!view) return;\n view.prev().catch(() => {});\n }, []);\n\n const handleNext = useCallback(() => {\n const view = viewRef.current;\n if (!view) return;\n view.next().catch(() => {});\n }, []);\n\n const toggleToc = useCallback(() => setShowToc((prev) => !prev), []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 宽度改变后 paginator 需要重新分页\n const view = viewRef.current;\n if (!view) return;\n const renderer = (view as unknown as { renderer?: HTMLElement }).renderer;\n if (renderer) {\n renderer.setAttribute('max-inline-size', newVal ? '9999' : '720');\n }\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n setShowToc(false);\n viewRef.current?.goTo(href).catch(() => {});\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n setActiveTocHref('');\n host.replaceChildren();\n\n let cancelled = false;\n let view: FoliateView | null = null;\n\n const load = async () => {\n try {\n if (cancelled) return;\n\n view = document.createElement('foliate-view') as FoliateView;\n host.appendChild(view);\n viewRef.current = view;\n\n // 先注册事件\n view.addEventListener('relocate', (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail) return;\n // SectionProgress 返回的 location 对象: { current, next, total }\n const loc = detail.location as { current?: number; total?: number } | undefined;\n if (loc && typeof loc.current === 'number' && typeof loc.total === 'number') {\n reportProgress(loc.current, loc.total);\n } else {\n // fallback:用 section 级别估算\n const sections = viewRef.current?.book?.sections ?? [];\n const idx = detail.index ?? 0;\n const frac = detail.fraction ?? 0;\n const total = Math.max(sections.length, 1);\n const current = Math.round((idx + frac) / total * total);\n reportProgress(current, total);\n }\n const tocItem = detail.tocItem as { href?: string } | undefined;\n if (tocItem?.href) {\n setActiveTocHref(tocItem.href);\n }\n });\n\n const res = await fetcher(url);\n if (!res.ok) throw new Error(`请求失败: ${res.status}`);\n const blob = await res.blob();\n let name = 'book.mobi';\n try {\n const u = new URL(url, window.location.href);\n const base = u.pathname.split('/').pop();\n if (base) name = decodeURIComponent(base);\n } catch { /* blob: URL */ }\n const file = new File([blob], name);\n\n await view.open(file);\n if (cancelled) { view.book?.destroy?.(); return; }\n\n // 配置 paginator:paginated 模式(默认),带动画\n const renderer = (view as unknown as { renderer: HTMLElement & {\n setStyles?: (css: string) => void;\n next?: () => Promise<void>;\n } }).renderer;\n\n if (renderer) {\n // flow=\"paginated\" 是默认值,不需要显式设置\n renderer.setAttribute('animated', '');\n renderer.setAttribute('max-inline-size', '720');\n renderer.setAttribute('margin', '48');\n renderer.setAttribute('gap', '5%');\n renderer.setStyles?.(READER_CSS);\n // 必须调 next() 渲染首页\n await renderer.next?.();\n }\n\n setToc(view.book?.toc ?? []);\n setLoading(false);\n reportProgress(0, view.book?.sections.length ?? 1);\n } catch (err) {\n console.error('MOBI/AZW3 加载错误:', err);\n if (!cancelled) {\n setError(t('mobi.load_failed'));\n setLoading(false);\n }\n }\n };\n\n load();\n\n return () => {\n cancelled = true;\n try { viewRef.current?.book?.destroy?.(); } catch { /* ignore */ }\n viewRef.current = null;\n host.replaceChildren();\n };\n }, [url, reportProgress]);\n\n const isActive = useCallback(\n (href: string | undefined) => !!href && href === activeTocHref,\n [activeTocHref]\n );\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ listStyle: 'none', padding: 0, margin: depth > 0 ? '0 0 0 16px' : 0 }}>\n {items.map((item, i) => (\n <li key={`${item.href ?? item.label}-${i}`}>\n {item.href ? (\n <button\n onClick={() => handleTocClick(item.href!)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${\n isActive(item.href)\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label?.trim()}\n </button>\n ) : (\n <div className=\"rfp-w-full rfp-py-2 rfp-px-3 rfp-text-sm rfp-text-fg-tertiary rfp-truncate\">\n {item.label?.trim()}\n </div>\n )}\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n ))}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden\">\n {error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center rfp-p-6\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\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 {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{ opacity: showToc ? 1 : 0, pointerEvents: showToc ? 'auto' : 'none' }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={hostRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n }}\n />\n )}\n </div>\n );\n }\n);\n\nMobiRenderer.displayName = 'MobiRenderer';\n"],"names":["READER_CSS","A4_WIDTH","MobiRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","fetcher","useFetcher","hostRef","useRef","viewRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","loading","setLoading","useState","error","setError","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","isFullWidth","setIsFullWidth","isFullWidthRef","reportProgress","useCallback","current","total","_a","handlePrev","view","handleNext","toggleToc","prev","toggleFullWidth","newVal","renderer","handleTocClick","href","useImperativeHandle","useEffect","host","cancelled","e","detail","loc","sections","_b","idx","frac","tocItem","res","blob","name","base","file","_c","_d","_e","_f","err","isActive","renderTocItems","items","depth","item","i","jsxs","jsx","X"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
|
2
2
|
import { useRef as S, useState as d, useEffect as R, useCallback as y } from "react";
|
|
3
3
|
import { motion as h, AnimatePresence as A } from "framer-motion";
|
|
4
4
|
import { Repeat as _, SkipBack as z, Pause as B, Play as q, SkipForward as U, VolumeX as X, Volume1 as J, Volume2 as K } from "lucide-react";
|
|
5
|
-
import { u as Q } from "./index-
|
|
5
|
+
import { u as Q } from "./index-CGNWXFy3.mjs";
|
|
6
6
|
function Y({
|
|
7
7
|
url: l
|
|
8
8
|
}) {
|
|
@@ -525,4 +525,4 @@ const Z = ({ text: l, className: o = "", style: i }) => {
|
|
|
525
525
|
export {
|
|
526
526
|
se as AudioRenderer
|
|
527
527
|
};
|
|
528
|
-
//# sourceMappingURL=index-
|
|
528
|
+
//# sourceMappingURL=index-DPpUj8Yy.mjs.map
|