@eternalheart/vue-file-preview 1.3.6 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/FilePreviewContent.vue.d.ts.map +1 -1
- package/lib/FilePreviewEmbed.vue.d.ts.map +1 -1
- package/lib/FilePreviewModal.vue.d.ts.map +1 -1
- package/lib/chunks/index-5Smm2vx0.mjs +77 -0
- package/lib/chunks/index-5Smm2vx0.mjs.map +1 -0
- package/lib/chunks/index-BCkcZs4y.mjs +84 -0
- package/lib/chunks/index-BCkcZs4y.mjs.map +1 -0
- package/lib/chunks/index-BM9FaQUl.mjs +134 -0
- package/lib/chunks/index-BM9FaQUl.mjs.map +1 -0
- package/lib/chunks/index-BYzQg-jL.mjs +152 -0
- package/lib/chunks/index-BYzQg-jL.mjs.map +1 -0
- package/lib/chunks/index-BoL1b2w-.mjs +129 -0
- package/lib/chunks/index-BoL1b2w-.mjs.map +1 -0
- package/lib/chunks/index-Bri7VeRx.mjs +203 -0
- package/lib/chunks/index-Bri7VeRx.mjs.map +1 -0
- package/lib/chunks/index-C324a7kV.mjs +2017 -0
- package/lib/chunks/index-C324a7kV.mjs.map +1 -0
- package/lib/chunks/index-C7uOM7XL.mjs +139 -0
- package/lib/chunks/index-C7uOM7XL.mjs.map +1 -0
- package/lib/chunks/index-CTsscgqY.mjs +136 -0
- package/lib/chunks/index-CTsscgqY.mjs.map +1 -0
- package/lib/chunks/index-Ch7AEfnk.mjs +116 -0
- package/lib/chunks/index-Ch7AEfnk.mjs.map +1 -0
- package/lib/chunks/index-D9wf6m37.mjs +249 -0
- package/lib/chunks/index-D9wf6m37.mjs.map +1 -0
- package/lib/chunks/index-DAEQe-RI.mjs +111 -0
- package/lib/chunks/index-DAEQe-RI.mjs.map +1 -0
- package/lib/chunks/index-DAo-7spn.mjs +103 -0
- package/lib/chunks/index-DAo-7spn.mjs.map +1 -0
- package/lib/chunks/index-DXlcF1Dk.mjs +113 -0
- package/lib/chunks/index-DXlcF1Dk.mjs.map +1 -0
- package/lib/chunks/index-ELyTQZeF.mjs +281 -0
- package/lib/chunks/index-ELyTQZeF.mjs.map +1 -0
- package/lib/chunks/index-cZn4ih-x.mjs +111 -0
- package/lib/chunks/index-cZn4ih-x.mjs.map +1 -0
- package/lib/chunks/index-dzB4jd9b.mjs +353 -0
- package/lib/chunks/index-dzB4jd9b.mjs.map +1 -0
- package/lib/chunks/index-lHlugUBI.mjs +391 -0
- package/lib/chunks/index-lHlugUBI.mjs.map +1 -0
- package/lib/composables/useResolvedTheme.d.ts +15 -0
- package/lib/composables/useResolvedTheme.d.ts.map +1 -0
- package/lib/index.cjs +24 -499
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +12 -44597
- package/lib/index.mjs.map +1 -1
- package/lib/renderers/Audio/index.vue.d.ts.map +1 -1
- package/lib/renderers/Csv/index.vue.d.ts.map +1 -1
- package/lib/renderers/Json/index.vue.d.ts.map +1 -1
- package/lib/renderers/Markdown/index.vue.d.ts.map +1 -1
- package/lib/renderers/Pptx/index.vue.d.ts.map +1 -1
- package/lib/renderers/RendererLoading.vue.d.ts +3 -0
- package/lib/renderers/RendererLoading.vue.d.ts.map +1 -0
- package/lib/renderers/Text/index.vue.d.ts.map +1 -1
- package/lib/renderers/Video/index.vue.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.vue.d.ts.map +1 -1
- package/lib/renderers/Xml/index.vue.d.ts.map +1 -1
- package/lib/renderers/Zip/index.vue.d.ts.map +1 -1
- package/lib/renderers/lazy.d.ts +19 -0
- package/lib/renderers/lazy.d.ts.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { defineComponent as $, computed as G, ref as c, watch as _, nextTick as I, openBlock as a, createElementBlock as d, createElementVNode as i, toDisplayString as H } from "vue";
|
|
2
|
+
import P from "markdown-it";
|
|
3
|
+
import D from "@traptitech/markdown-it-katex";
|
|
4
|
+
import { codeToHtml as E } from "shiki";
|
|
5
|
+
import { u as K, b as O, h as R, _ as N } from "./index-C324a7kV.mjs";
|
|
6
|
+
import "katex/dist/katex.min.css";
|
|
7
|
+
const Y = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full"
|
|
10
|
+
}, W = {
|
|
11
|
+
key: 1,
|
|
12
|
+
class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full"
|
|
13
|
+
}, z = { class: "vfp-text-fg-secondary vfp-text-center" }, F = { class: "vfp-text-lg" }, J = {
|
|
14
|
+
key: 2,
|
|
15
|
+
class: "vfp-w-full vfp-h-full vfp-overflow-auto",
|
|
16
|
+
style: { background: "var(--fp-code-bg)" }
|
|
17
|
+
}, Q = {
|
|
18
|
+
key: 0,
|
|
19
|
+
class: "vfp-p-6 vfp-text-fg-primary vfp-font-mono vfp-text-sm vfp-whitespace-pre-wrap vfp-break-words"
|
|
20
|
+
}, U = ["innerHTML"], X = {
|
|
21
|
+
key: 3,
|
|
22
|
+
class: "vfp-w-full vfp-h-full vfp-overflow-auto vfp-p-6 md:vfp-p-10"
|
|
23
|
+
}, Z = { class: "vfp-max-w-full md:vfp-max-w-4xl vfp-mx-auto" }, ee = ["innerHTML"], L = '<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>', B = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>', te = '<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>', oe = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>', re = /* @__PURE__ */ $({
|
|
24
|
+
__name: "index",
|
|
25
|
+
props: {
|
|
26
|
+
url: {},
|
|
27
|
+
viewMode: {}
|
|
28
|
+
},
|
|
29
|
+
setup(b) {
|
|
30
|
+
const x = b, { t: p } = K(), j = O(), g = G(() => j.value === "light" ? "github-light" : "github-dark"), y = c(""), u = c(""), v = c(""), f = c(!0), h = c(null), m = c(null), l = new P({
|
|
31
|
+
html: !0,
|
|
32
|
+
linkify: !0,
|
|
33
|
+
typographer: !1,
|
|
34
|
+
breaks: !1
|
|
35
|
+
});
|
|
36
|
+
l.use(D), l.renderer.rules.fence = (o, r) => {
|
|
37
|
+
const e = o[r], n = e.info ? e.info.trim() : "", t = e.content;
|
|
38
|
+
return n ? `<div class="code-block-wrapper">
|
|
39
|
+
<div class="code-block-header">
|
|
40
|
+
<span>${n}</span>
|
|
41
|
+
</div>
|
|
42
|
+
<pre data-shiki-pending="1" data-lang="${n}"><code>${l.utils.escapeHtml(t)}</code></pre>
|
|
43
|
+
</div>` : `<div class="code-block-wrapper">
|
|
44
|
+
<pre class="no-lang-pre"><code>${l.utils.escapeHtml(t)}</code></pre>
|
|
45
|
+
</div>`;
|
|
46
|
+
}, l.renderer.rules.code_block = (o, r) => {
|
|
47
|
+
const e = o[r].content;
|
|
48
|
+
return `<div class="code-block-wrapper">
|
|
49
|
+
<pre class="no-lang-pre"><code>${l.utils.escapeHtml(e)}</code></pre>
|
|
50
|
+
</div>`;
|
|
51
|
+
};
|
|
52
|
+
const q = l.renderer.rules.table_open || ((o, r, e, n, t) => t.renderToken(o, r, e));
|
|
53
|
+
l.renderer.rules.table_open = (o, r, e, n, t) => '<div class="table-wrapper">' + q(o, r, e, n, t);
|
|
54
|
+
const V = l.renderer.rules.table_close || ((o, r, e, n, t) => t.renderToken(o, r, e));
|
|
55
|
+
l.renderer.rules.table_close = (o, r, e, n, t) => V(o, r, e, n, t) + "</div>";
|
|
56
|
+
const C = async () => {
|
|
57
|
+
f.value = !0, h.value = null;
|
|
58
|
+
try {
|
|
59
|
+
const o = await R(x.url);
|
|
60
|
+
y.value = o, u.value = l.render(o), f.value = !1;
|
|
61
|
+
try {
|
|
62
|
+
v.value = await E(o, { lang: "markdown", theme: g.value });
|
|
63
|
+
} catch {
|
|
64
|
+
v.value = "";
|
|
65
|
+
}
|
|
66
|
+
} catch (o) {
|
|
67
|
+
console.error(o), h.value = p.value("markdown.load_failed"), f.value = !1;
|
|
68
|
+
}
|
|
69
|
+
}, M = (o, r) => {
|
|
70
|
+
const e = document.createElement("button");
|
|
71
|
+
return e.type = "button", e.className = r ? "code-copy-btn" : "code-copy-btn code-copy-float", e.title = p.value("markdown.copy_code"), e.innerHTML = r ? L : B, e.addEventListener("click", async (n) => {
|
|
72
|
+
n.stopPropagation();
|
|
73
|
+
try {
|
|
74
|
+
await navigator.clipboard.writeText(o);
|
|
75
|
+
} catch {
|
|
76
|
+
const t = document.createElement("textarea");
|
|
77
|
+
t.value = o, document.body.appendChild(t), t.select(), document.execCommand("copy"), document.body.removeChild(t);
|
|
78
|
+
}
|
|
79
|
+
e.innerHTML = r ? te : oe, e.title = p.value("markdown.copied"), setTimeout(() => {
|
|
80
|
+
e.innerHTML = r ? L : B, e.title = p.value("markdown.copy_code");
|
|
81
|
+
}, 2e3);
|
|
82
|
+
}), e;
|
|
83
|
+
}, A = async () => {
|
|
84
|
+
var e, n;
|
|
85
|
+
if (!m.value) return;
|
|
86
|
+
const o = m.value.querySelectorAll('pre[data-shiki-pending="1"]');
|
|
87
|
+
for (const t of o) {
|
|
88
|
+
const w = t.getAttribute("data-lang") || "text", s = ((e = t.querySelector("code")) == null ? void 0 : e.textContent) || "";
|
|
89
|
+
try {
|
|
90
|
+
const k = await E(s, { lang: w, theme: g.value }), T = document.createElement("div");
|
|
91
|
+
T.innerHTML = k;
|
|
92
|
+
const S = T.firstElementChild;
|
|
93
|
+
S && t.replaceWith(S);
|
|
94
|
+
} catch {
|
|
95
|
+
t.style.backgroundColor = "var(--fp-code-bg)", t.removeAttribute("data-shiki-pending");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const r = m.value.querySelectorAll(".code-block-wrapper");
|
|
99
|
+
for (const t of r) {
|
|
100
|
+
if (t.querySelector(".code-copy-btn")) continue;
|
|
101
|
+
const w = t.querySelector(".code-block-header"), s = t.querySelector("pre"), k = ((n = s == null ? void 0 : s.querySelector("code")) == null ? void 0 : n.textContent) ?? (s == null ? void 0 : s.textContent) ?? "";
|
|
102
|
+
w ? w.appendChild(M(k, !0)) : t.appendChild(M(k, !1));
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
return _(() => x.url, C, { immediate: !0 }), _(u, async () => {
|
|
106
|
+
u.value && (await I(), A());
|
|
107
|
+
}), _(g, () => {
|
|
108
|
+
y.value && C();
|
|
109
|
+
}), (o, r) => f.value ? (a(), d("div", Y, [...r[0] || (r[0] = [
|
|
110
|
+
i("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
111
|
+
])])) : h.value ? (a(), d("div", W, [
|
|
112
|
+
i("div", z, [
|
|
113
|
+
i("p", F, H(h.value), 1)
|
|
114
|
+
])
|
|
115
|
+
])) : b.viewMode === "source" ? (a(), d("div", J, [
|
|
116
|
+
v.value ? (a(), d("div", {
|
|
117
|
+
key: 1,
|
|
118
|
+
class: "shiki-wrapper",
|
|
119
|
+
innerHTML: v.value
|
|
120
|
+
}, null, 8, U)) : (a(), d("pre", Q, H(y.value), 1))
|
|
121
|
+
])) : (a(), d("div", X, [
|
|
122
|
+
i("div", Z, [
|
|
123
|
+
i("div", {
|
|
124
|
+
ref_key: "containerRef",
|
|
125
|
+
ref: m,
|
|
126
|
+
class: "markdown-body",
|
|
127
|
+
innerHTML: u.value
|
|
128
|
+
}, null, 8, ee)
|
|
129
|
+
])
|
|
130
|
+
]));
|
|
131
|
+
}
|
|
132
|
+
}), ie = /* @__PURE__ */ N(re, [["__scopeId", "data-v-b709ebf4"]]);
|
|
133
|
+
export {
|
|
134
|
+
ie as default
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=index-CTsscgqY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CTsscgqY.mjs","sources":["../../src/renderers/Markdown/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue';\nimport MarkdownIt from 'markdown-it';\nimport MarkdownItKatex from '@traptitech/markdown-it-katex';\nimport { codeToHtml } from 'shiki';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\nimport { useResolvedTheme } from '../../composables/useResolvedTheme';\nimport 'katex/dist/katex.min.css';\n\nconst props = defineProps<{\n url: string;\n viewMode?: 'preview' | 'source';\n}>();\n\nconst { t } = useTranslator();\nconst resolvedTheme = useResolvedTheme();\nconst shikiTheme = computed(() => (resolvedTheme.value === 'light' ? 'github-light' : 'github-dark'));\n\nconst content = ref('');\nconst html = ref('');\nconst highlightedSource = ref('');\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\n\n// 创建 markdown-it 实例(支持 GFM 表格、删除线、任务列表、HTML、数学公式)\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n typographer: false,\n breaks: false,\n});\nmd.use(MarkdownItKatex);\n\n// 自定义代码块渲染:包裹 code-block-wrapper + header(不含复制按钮,由 JS 动态注入)\nmd.renderer.rules.fence = (tokens, idx) => {\n const token = tokens[idx];\n const info = token.info ? token.info.trim() : '';\n const code = token.content;\n\n if (!info) {\n return `<div class=\"code-block-wrapper\">\n <pre class=\"no-lang-pre\"><code>${md.utils.escapeHtml(code)}</code></pre>\n </div>`;\n }\n\n return `<div class=\"code-block-wrapper\">\n <div class=\"code-block-header\">\n <span>${info}</span>\n </div>\n <pre data-shiki-pending=\"1\" data-lang=\"${info}\"><code>${md.utils.escapeHtml(code)}</code></pre>\n </div>`;\n};\n\n// 4-space 缩进代码块:同样包裹 code-block-wrapper(无头,注入浮动复制按钮)\nmd.renderer.rules.code_block = (tokens, idx) => {\n const code = tokens[idx].content;\n return `<div class=\"code-block-wrapper\">\n <pre class=\"no-lang-pre\"><code>${md.utils.escapeHtml(code)}</code></pre>\n </div>`;\n};\n\n// 表格添加包裹层(用于横向滚动)\nconst defaultTableOpen =\n md.renderer.rules.table_open ||\n ((tokens, idx, options, _env, self) => self.renderToken(tokens, idx, options));\nmd.renderer.rules.table_open = (tokens, idx, options, env, self) => {\n return '<div class=\"table-wrapper\">' + defaultTableOpen(tokens, idx, options, env, self);\n};\nconst defaultTableClose =\n md.renderer.rules.table_close ||\n ((tokens, idx, options, _env, self) => self.renderToken(tokens, idx, options));\nmd.renderer.rules.table_close = (tokens, idx, options, env, self) => {\n return defaultTableClose(tokens, idx, options, env, self) + '</div>';\n};\n\nconst loadMarkdown = async () => {\n loading.value = true;\n error.value = null;\n try {\n const text = await fetchTextUtf8(props.url);\n content.value = text;\n html.value = md.render(text);\n loading.value = false;\n // 异步生成源码高亮(不阻塞预览渲染)\n try {\n highlightedSource.value = await codeToHtml(text, { lang: 'markdown', theme: shikiTheme.value });\n } catch {\n highlightedSource.value = '';\n }\n } catch (err) {\n console.error(err);\n error.value = t.value('markdown.load_failed');\n loading.value = false;\n }\n};\n\nconst COPY_SVG_SM = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg>`;\nconst COPY_SVG_MD = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg>`;\nconst CHECK_SVG_SM = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>`;\nconst CHECK_SVG_MD = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>`;\n\nconst createCopyButton = (code: string, inline: boolean): HTMLButtonElement => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = inline ? 'code-copy-btn' : 'code-copy-btn code-copy-float';\n btn.title = t.value('markdown.copy_code');\n btn.innerHTML = inline ? COPY_SVG_SM : COPY_SVG_MD;\n btn.addEventListener('click', async (e) => {\n e.stopPropagation();\n try {\n await navigator.clipboard.writeText(code);\n } catch {\n const ta = document.createElement('textarea');\n ta.value = code;\n document.body.appendChild(ta);\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n }\n btn.innerHTML = inline ? CHECK_SVG_SM : CHECK_SVG_MD;\n btn.title = t.value('markdown.copied');\n setTimeout(() => {\n btn.innerHTML = inline ? COPY_SVG_SM : COPY_SVG_MD;\n btn.title = t.value('markdown.copy_code');\n }, 2000);\n });\n return btn;\n};\n\nconst highlightAndInjectCopyButtons = async () => {\n if (!containerRef.value) return;\n\n // 1. shiki 高亮有语言的代码块\n const pending = containerRef.value.querySelectorAll<HTMLPreElement>('pre[data-shiki-pending=\"1\"]');\n for (const pre of pending) {\n const lang = pre.getAttribute('data-lang') || 'text';\n const code = pre.querySelector('code')?.textContent || '';\n try {\n const highlighted = await codeToHtml(code, { lang, theme: shikiTheme.value });\n const tmp = document.createElement('div');\n tmp.innerHTML = highlighted;\n const newPre = tmp.firstElementChild as HTMLElement;\n if (newPre) pre.replaceWith(newPre);\n } catch {\n pre.style.backgroundColor = 'var(--fp-code-bg)';\n pre.removeAttribute('data-shiki-pending');\n }\n }\n\n // 2. 为所有代码块注入复制按钮(避免重复注入)\n const wrappers = containerRef.value.querySelectorAll<HTMLElement>('.code-block-wrapper');\n for (const wrapper of wrappers) {\n if (wrapper.querySelector('.code-copy-btn')) continue;\n const header = wrapper.querySelector('.code-block-header');\n const pre = wrapper.querySelector('pre');\n const code = pre?.querySelector('code')?.textContent ?? pre?.textContent ?? '';\n if (header) {\n // 有语言:按钮放入 header 右侧\n header.appendChild(createCopyButton(code, true));\n } else {\n // 无语言:浮动按钮\n wrapper.appendChild(createCopyButton(code, false));\n }\n }\n};\n\nwatch(() => props.url, loadMarkdown, { immediate: true });\n\nwatch(html, async () => {\n if (!html.value) return;\n await nextTick();\n highlightAndInjectCopyButtons();\n});\n\n// 主题切换时重新加载(让 shiki 用新主题重新高亮)\nwatch(shikiTheme, () => {\n if (content.value) loadMarkdown();\n});\n</script>\n\n<template>\n <div v-if=\"loading\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <div v-else-if=\"error\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div class=\"vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error }}</p>\n </div>\n </div>\n\n <!-- 源码视图 -->\n <div v-else-if=\"viewMode === 'source'\" class=\"vfp-w-full vfp-h-full vfp-overflow-auto\" style=\"background: var(--fp-code-bg);\">\n <pre\n v-if=\"!highlightedSource\"\n class=\"vfp-p-6 vfp-text-fg-primary vfp-font-mono vfp-text-sm vfp-whitespace-pre-wrap vfp-break-words\"\n >{{ content }}</pre\n >\n <div v-else class=\"shiki-wrapper\" v-html=\"highlightedSource\" />\n </div>\n\n <!-- 预览视图 -->\n <div v-else class=\"vfp-w-full vfp-h-full vfp-overflow-auto vfp-p-6 md:vfp-p-10\">\n <div class=\"vfp-max-w-full md:vfp-max-w-4xl vfp-mx-auto\">\n <div ref=\"containerRef\" class=\"markdown-body\" v-html=\"html\" />\n </div>\n </div>\n</template>\n\n<style scoped>\n.markdown-body :deep(.table-wrapper) {\n overflow-x: auto;\n margin: 1rem 0;\n border-radius: 0.375rem;\n border: 1px solid var(--fp-surface-3);\n}\n.markdown-body :deep(.table-wrapper > table) {\n margin: 0;\n border: 0;\n border-radius: 0;\n}\n/* shiki 生成的 pre:修正在 code-block-wrapper 内的边距与圆角 */\n.markdown-body :deep(.code-block-wrapper pre.shiki) {\n margin: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-top: 0;\n}\n/* 无语言代码块:pre 不裁剪,让浮动按钮可见 */\n.markdown-body :deep(.code-block-wrapper) {\n overflow: visible;\n}\n.markdown-body :deep(.code-block-wrapper pre) {\n overflow: visible;\n}\n/* 无语言代码块纯文本样式 */\n.markdown-body :deep(.no-lang-pre) {\n margin: 0;\n padding: 1rem;\n background: var(--fp-code-bg);\n border-radius: 0.375rem;\n border: 1px solid var(--fp-line);\n}\n.markdown-body :deep(.no-lang-pre code) {\n display: block;\n font-size: 0.8125rem;\n line-height: 1.5;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--fp-fg-primary);\n white-space: pre;\n overflow-x: auto;\n}\n/* shiki 生成的 code:补充 padding,使代码有适当内边距 */\n.markdown-body :deep(pre.shiki code) {\n display: block;\n padding: 1rem;\n font-size: 0.8125rem;\n line-height: 1.5;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n}\n/* KaTeX 公式颜色适配暗色背景 */\n.markdown-body :deep(.katex) {\n color: var(--fp-fg-primary);\n}\n.markdown-body :deep(.katex-display) {\n margin: 1.25rem 0;\n overflow-x: auto;\n overflow-y: hidden;\n}\n/* 源码视图 shiki */\n.shiki-wrapper :deep(pre) {\n margin: 0;\n padding: 1.5rem;\n background: transparent !important;\n font-size: 0.875rem;\n overflow-x: auto;\n}\n.shiki-wrapper :deep(code) {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n}\n</style>\n"],"names":["COPY_SVG_SM","COPY_SVG_MD","CHECK_SVG_SM","CHECK_SVG_MD","props","__props","t","useTranslator","resolvedTheme","useResolvedTheme","shikiTheme","computed","content","ref","html","highlightedSource","loading","error","containerRef","md","MarkdownIt","MarkdownItKatex","tokens","idx","token","info","code","defaultTableOpen","options","_env","self","env","defaultTableClose","loadMarkdown","text","fetchTextUtf8","codeToHtml","err","createCopyButton","inline","btn","e","ta","highlightAndInjectCopyButtons","pending","pre","lang","_a","highlighted","tmp","newPre","wrappers","wrapper","header","_b","watch","nextTick","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_hoisted_6","_hoisted_8","_hoisted_9"],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { defineComponent as L, ref as h, watch as j, computed as y, openBlock as a, createElementBlock as r, createElementVNode as t, toDisplayString as o, unref as c, normalizeClass as b, Fragment as x, renderList as k, createCommentVNode as C } from "vue";
|
|
2
|
+
import { u as S, c as V, x as d, h as z, _ as A } from "./index-C324a7kV.mjs";
|
|
3
|
+
const D = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-bg-[#0f0f12]"
|
|
6
|
+
}, I = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-bg-[#0f0f12]"
|
|
9
|
+
}, M = { class: "vfp-text-fg-secondary vfp-text-center" }, O = { class: "vfp-text-lg" }, R = { class: "content-scroll" }, X = { class: "timeline" }, Y = { class: "cues" }, q = { class: "cue-meta" }, G = { class: "cue-time" }, H = { class: "cue-time" }, J = { class: "cue-id" }, K = {
|
|
10
|
+
key: 0,
|
|
11
|
+
class: "cue-style"
|
|
12
|
+
}, P = {
|
|
13
|
+
key: 0,
|
|
14
|
+
class: "cue-words"
|
|
15
|
+
}, Q = ["title"], U = { class: "cue-word-time" }, W = { class: "cue-word-text" }, Z = { class: "status-pill" }, $ = /* @__PURE__ */ L({
|
|
16
|
+
__name: "index",
|
|
17
|
+
props: {
|
|
18
|
+
url: {},
|
|
19
|
+
fileName: {}
|
|
20
|
+
},
|
|
21
|
+
setup(N) {
|
|
22
|
+
const v = N, { t: i } = S(), f = h(""), p = h(!0), u = h(null), T = {
|
|
23
|
+
srt: "srt",
|
|
24
|
+
vtt: "vtt",
|
|
25
|
+
lrc: "lrc",
|
|
26
|
+
elrc: "elrc",
|
|
27
|
+
ass: "ass",
|
|
28
|
+
ssa: "ssa",
|
|
29
|
+
ttml: "ttml",
|
|
30
|
+
dfxp: "ttml"
|
|
31
|
+
}, B = (s) => {
|
|
32
|
+
var l;
|
|
33
|
+
const e = ((l = s.split(".").pop()) == null ? void 0 : l.toLowerCase()) || "";
|
|
34
|
+
return T[e];
|
|
35
|
+
};
|
|
36
|
+
j(() => v.url, async () => {
|
|
37
|
+
p.value = !0, u.value = null;
|
|
38
|
+
try {
|
|
39
|
+
f.value = await z(v.url);
|
|
40
|
+
} catch (s) {
|
|
41
|
+
console.error(s), u.value = i.value("subtitle.load_failed");
|
|
42
|
+
} finally {
|
|
43
|
+
p.value = !1;
|
|
44
|
+
}
|
|
45
|
+
}, { immediate: !0 });
|
|
46
|
+
const n = y(() => {
|
|
47
|
+
if (!f.value) return null;
|
|
48
|
+
try {
|
|
49
|
+
return V(f.value, B(v.fileName));
|
|
50
|
+
} catch (s) {
|
|
51
|
+
return console.error(s), null;
|
|
52
|
+
}
|
|
53
|
+
}), _ = y(() => {
|
|
54
|
+
var s, e;
|
|
55
|
+
return ((s = n.value) == null ? void 0 : s.format) === "lrc" || ((e = n.value) == null ? void 0 : e.format) === "elrc";
|
|
56
|
+
}), w = y(() => {
|
|
57
|
+
var s;
|
|
58
|
+
return ((s = n.value) == null ? void 0 : s.metadata) ?? {};
|
|
59
|
+
}), E = (s) => d(s).slice(3, 8);
|
|
60
|
+
return (s, e) => p.value ? (a(), r("div", D, [...e[0] || (e[0] = [
|
|
61
|
+
t("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
62
|
+
])])) : u.value || !n.value ? (a(), r("div", I, [
|
|
63
|
+
t("div", M, [
|
|
64
|
+
t("p", O, o(u.value || c(i)("subtitle.parse_failed")), 1)
|
|
65
|
+
])
|
|
66
|
+
])) : (a(), r("div", {
|
|
67
|
+
key: 2,
|
|
68
|
+
class: b(["vfp-relative vfp-w-full vfp-h-full vfp-bg-[#0f0f12]", _.value ? "flavor-lyric" : "flavor-subtitle"])
|
|
69
|
+
}, [
|
|
70
|
+
t("div", R, [
|
|
71
|
+
t("div", X, [
|
|
72
|
+
e[3] || (e[3] = t("div", { class: "timeline-line" }, null, -1)),
|
|
73
|
+
t("ol", Y, [
|
|
74
|
+
(a(!0), r(x, null, k(n.value.cues, (l, g) => (a(), r("li", {
|
|
75
|
+
key: "cue-" + g,
|
|
76
|
+
class: "cue-row"
|
|
77
|
+
}, [
|
|
78
|
+
e[2] || (e[2] = t("div", { class: "cue-dot" }, null, -1)),
|
|
79
|
+
t("div", q, [
|
|
80
|
+
t("span", G, o(c(d)(l.start)), 1),
|
|
81
|
+
e[1] || (e[1] = t("span", { class: "cue-arrow" }, "→", -1)),
|
|
82
|
+
t("span", H, o(c(d)(l.end)), 1),
|
|
83
|
+
t("span", J, "#" + o(l.id ?? g + 1), 1),
|
|
84
|
+
l.style ? (a(), r("span", K, o(l.style), 1)) : C("", !0)
|
|
85
|
+
]),
|
|
86
|
+
l.words && l.words.length > 0 ? (a(), r("div", P, [
|
|
87
|
+
(a(!0), r(x, null, k(l.words, (m, F) => (a(), r("span", {
|
|
88
|
+
key: "w-" + F,
|
|
89
|
+
class: "cue-word",
|
|
90
|
+
title: c(d)(m.start)
|
|
91
|
+
}, [
|
|
92
|
+
t("span", U, o(E(m.start)), 1),
|
|
93
|
+
t("span", W, o(m.text), 1)
|
|
94
|
+
], 8, Q))), 128))
|
|
95
|
+
])) : (a(), r("p", {
|
|
96
|
+
key: 1,
|
|
97
|
+
class: b(["cue-text", { lyric: _.value }])
|
|
98
|
+
}, o(l.text), 3))
|
|
99
|
+
]))), 128))
|
|
100
|
+
])
|
|
101
|
+
])
|
|
102
|
+
]),
|
|
103
|
+
t("div", Z, [
|
|
104
|
+
t("span", null, o(n.value.cues.length) + " " + o(_.value ? c(i)("subtitle.lines") : c(i)("subtitle.cues")), 1),
|
|
105
|
+
w.value.length ? (a(), r(x, { key: 0 }, [
|
|
106
|
+
e[4] || (e[4] = t("span", { class: "dot" }, "·", -1)),
|
|
107
|
+
t("span", null, o(w.value.length), 1)
|
|
108
|
+
], 64)) : C("", !0)
|
|
109
|
+
])
|
|
110
|
+
], 2));
|
|
111
|
+
}
|
|
112
|
+
}), lt = /* @__PURE__ */ A($, [["__scopeId", "data-v-f4c7d945"]]);
|
|
113
|
+
export {
|
|
114
|
+
lt as default
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=index-Ch7AEfnk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Ch7AEfnk.mjs","sources":["../../src/renderers/Subtitle/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue';\nimport {\n parseSubtitle,\n formatSubtitleTime,\n fetchTextUtf8,\n type SubtitleParseResult,\n type SubtitleFormat,\n} from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst props = defineProps<{\n url: string;\n fileName: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst text = ref<string>('');\nconst loading = ref(true);\nconst error = ref<string | null>(null);\n\nconst FORMAT_BY_EXT: Record<string, SubtitleFormat> = {\n srt: 'srt',\n vtt: 'vtt',\n lrc: 'lrc',\n elrc: 'elrc',\n ass: 'ass',\n ssa: 'ssa',\n ttml: 'ttml',\n dfxp: 'ttml',\n};\n\nconst getFormat = (fileName: string): SubtitleFormat | undefined => {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n return FORMAT_BY_EXT[ext];\n};\n\nconst load = async () => {\n loading.value = true;\n error.value = null;\n try {\n text.value = await fetchTextUtf8(props.url);\n } catch (err) {\n console.error(err);\n error.value = t.value('subtitle.load_failed');\n } finally {\n loading.value = false;\n }\n};\n\nwatch(() => props.url, load, { immediate: true });\n\nconst parsed = computed<SubtitleParseResult | null>(() => {\n if (!text.value) return null;\n try {\n return parseSubtitle(text.value, getFormat(props.fileName));\n } catch (err) {\n console.error(err);\n return null;\n }\n});\n\nconst isLyric = computed(() => parsed.value?.format === 'lrc' || parsed.value?.format === 'elrc');\n\nconst meta = computed<Record<string, string>>(() => parsed.value?.metadata ?? {});\n\nconst wordTimeShort = (t: number) => formatSubtitleTime(t).slice(3, 8);\n</script>\n\n<template>\n <div\n v-if=\"loading\"\n class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-bg-[#0f0f12]\"\n >\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <div\n v-else-if=\"error || !parsed\"\n class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-bg-[#0f0f12]\"\n >\n <div class=\"vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error || t('subtitle.parse_failed') }}</p>\n </div>\n </div>\n\n <div\n v-else\n class=\"vfp-relative vfp-w-full vfp-h-full vfp-bg-[#0f0f12]\"\n :class=\"isLyric ? 'flavor-lyric' : 'flavor-subtitle'\"\n >\n <!-- 内容滚动区 -->\n <div class=\"content-scroll\">\n <div class=\"timeline\">\n <div class=\"timeline-line\" />\n <ol class=\"cues\">\n <li v-for=\"(cue, i) in parsed.cues\" :key=\"'cue-' + i\" class=\"cue-row\">\n <div class=\"cue-dot\" />\n <div class=\"cue-meta\">\n <span class=\"cue-time\">{{ formatSubtitleTime(cue.start) }}</span>\n <span class=\"cue-arrow\">→</span>\n <span class=\"cue-time\">{{ formatSubtitleTime(cue.end) }}</span>\n <span class=\"cue-id\">#{{ cue.id ?? i + 1 }}</span>\n <span v-if=\"cue.style\" class=\"cue-style\">{{ cue.style }}</span>\n </div>\n <div v-if=\"cue.words && cue.words.length > 0\" class=\"cue-words\">\n <span\n v-for=\"(word, wi) in cue.words\"\n :key=\"'w-' + wi\"\n class=\"cue-word\"\n :title=\"formatSubtitleTime(word.start)\"\n >\n <span class=\"cue-word-time\">{{ wordTimeShort(word.start) }}</span>\n <span class=\"cue-word-text\">{{ word.text }}</span>\n </span>\n </div>\n <p v-else class=\"cue-text\" :class=\"{ lyric: isLyric }\">{{ cue.text }}</p>\n </li>\n </ol>\n </div>\n </div>\n\n <!-- 右下角浮签 -->\n <div class=\"status-pill\">\n <span>{{ parsed.cues.length }} {{ isLyric ? t('subtitle.lines') : t('subtitle.cues') }}</span>\n <template v-if=\"meta.length\">\n <span class=\"dot\">·</span>\n <span>{{ meta.length }}</span>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.content-scroll {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 1.5rem 1.5rem 4rem;\n}\n@media (min-width: 768px) {\n .content-scroll {\n padding: 1.5rem 2.5rem 5rem;\n }\n}\n.status-pill {\n pointer-events: none;\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.25rem 0.625rem;\n border-radius: 9999px;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(8px);\n border: 1px solid var(--fp-line);\n font-size: 0.625rem;\n color: var(--fp-fg-tertiary);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n}\n@media (min-width: 768px) {\n .status-pill {\n bottom: 1rem;\n right: 1rem;\n }\n}\n.dot {\n color: var(--fp-fg-disabled);\n}\n\n.timeline {\n position: relative;\n max-width: 64rem;\n margin: 0 auto;\n}\n.timeline-line {\n position: absolute;\n left: 5px;\n top: 0.5rem;\n bottom: 0.5rem;\n width: 1px;\n background: var(--fp-line-weak);\n}\n@media (min-width: 768px) {\n .timeline-line {\n left: 7px;\n }\n}\n.cues {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 1.25rem;\n}\n@media (min-width: 768px) {\n .cues {\n gap: 1.5rem;\n }\n}\n.cue-row {\n position: relative;\n padding-left: 1.5rem;\n}\n@media (min-width: 768px) {\n .cue-row {\n padding-left: 2rem;\n }\n}\n.cue-dot {\n position: absolute;\n left: 0;\n top: 0.5rem;\n width: 0.75rem;\n height: 0.75rem;\n border-radius: 9999px;\n background: var(--fp-surface-3);\n border: 2px solid #0f0f12;\n transition: background-color 0.2s;\n}\n.flavor-lyric .cue-row:hover .cue-dot {\n background: rgb(167, 139, 250);\n}\n.flavor-subtitle .cue-row:hover .cue-dot {\n background: rgb(56, 189, 248);\n}\n.cue-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 0.25rem 0.75rem;\n margin-bottom: 0.375rem;\n}\n.cue-time {\n font-size: 0.6875rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--fp-fg-muted);\n font-variant-numeric: tabular-nums;\n}\n.cue-arrow {\n font-size: 0.6875rem;\n color: var(--fp-fg-disabled);\n}\n.cue-id {\n font-size: 0.625rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: var(--fp-fg-disabled);\n font-variant-numeric: tabular-nums;\n}\n.cue-style {\n font-size: 0.5625rem;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n color: var(--fp-fg-tertiary);\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n background: var(--fp-line-weak);\n border: 1px solid var(--fp-line);\n}\n.cue-text {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.625;\n color: var(--fp-fg-primary);\n font-size: 0.875rem;\n transition: color 0.2s;\n}\n@media (min-width: 768px) {\n .cue-text {\n font-size: 1rem;\n }\n}\n.cue-text.lyric {\n font-size: 1rem;\n font-weight: 500;\n}\n@media (min-width: 768px) {\n .cue-text.lyric {\n font-size: 1.25rem;\n }\n}\n.cue-row:hover .cue-text {\n color: #fff;\n}\n.cue-words {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem 0.375rem;\n font-size: 1rem;\n color: var(--fp-fg-primary);\n line-height: 1.625;\n transition: color 0.2s;\n}\n@media (min-width: 768px) {\n .cue-words {\n font-size: 1.125rem;\n }\n}\n.cue-row:hover .cue-words {\n color: #fff;\n}\n.cue-word {\n display: inline-flex;\n flex-direction: column;\n align-items: flex-start;\n}\n.cue-word-time {\n font-size: 0.5625rem;\n color: var(--fp-fg-disabled);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n line-height: 1;\n font-variant-numeric: tabular-nums;\n}\n.cue-word-text {\n line-height: 1.4;\n}\n</style>\n"],"names":["props","__props","t","useTranslator","text","ref","loading","error","FORMAT_BY_EXT","getFormat","fileName","ext","_a","watch","fetchTextUtf8","err","parsed","computed","parseSubtitle","isLyric","_b","meta","wordTimeShort","formatSubtitleTime","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_unref","_normalizeClass","_hoisted_5","_hoisted_6","_hoisted_7","_Fragment","cue","i","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","word","wi","_hoisted_15","_hoisted_16","_hoisted_17"],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { defineComponent as Z, ref as h, onMounted as ee, watch as te, onBeforeUnmount as oe, openBlock as u, createElementBlock as c, createElementVNode as v, toDisplayString as E, createCommentVNode as y, normalizeStyle as b, unref as X, createVNode as re, Fragment as $, renderList as D } from "vue";
|
|
2
|
+
import ae from "@likecoin/epub-ts";
|
|
3
|
+
import { X as ne } from "lucide-vue-next";
|
|
4
|
+
import { u as le } from "./index-C324a7kV.mjs";
|
|
5
|
+
const se = {
|
|
6
|
+
class: "vfp-relative vfp-w-full vfp-h-full vfp-flex vfp-justify-center vfp-overflow-hidden",
|
|
7
|
+
style: { background: "#f5f5f0" }
|
|
8
|
+
}, ie = {
|
|
9
|
+
key: 0,
|
|
10
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-text-fg-secondary vfp-text-center"
|
|
11
|
+
}, fe = { class: "vfp-text-lg" }, pe = {
|
|
12
|
+
key: 1,
|
|
13
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-z-10"
|
|
14
|
+
}, ue = {
|
|
15
|
+
class: "vfp-flex vfp-items-center vfp-justify-between vfp-flex-shrink-0",
|
|
16
|
+
style: { padding: "12px 16px", "border-bottom": "1px solid rgba(255,255,255,0.1)" }
|
|
17
|
+
}, ce = { style: { color: "white", "font-weight": "500", "font-size": "14px" } }, ve = {
|
|
18
|
+
class: "vfp-flex-1 vfp-overflow-y-auto",
|
|
19
|
+
style: { padding: "8px 4px" }
|
|
20
|
+
}, de = ["title", "onClick", "onMouseenter", "onMouseleave"], he = ["title", "onClick", "onMouseenter", "onMouseleave"], ge = 794, we = /* @__PURE__ */ Z({
|
|
21
|
+
__name: "index",
|
|
22
|
+
props: {
|
|
23
|
+
url: {}
|
|
24
|
+
},
|
|
25
|
+
emits: ["chapterChange", "fullWidthChange"],
|
|
26
|
+
setup(I, { expose: O, emit: U }) {
|
|
27
|
+
const w = I, { t: R } = le(), k = U, l = h(null), _ = h(!0), g = h(null), C = h(!1), x = h([]), f = h(!1), L = h("");
|
|
28
|
+
let s = null, e = null, m = 0, S = null;
|
|
29
|
+
const F = () => {
|
|
30
|
+
var o;
|
|
31
|
+
try {
|
|
32
|
+
(o = e == null ? void 0 : e.destroy) == null || o.call(e);
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
s == null || s.destroy();
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
e = null, s = null, m = 0, S = null;
|
|
40
|
+
}, G = () => {
|
|
41
|
+
e == null || e.prev();
|
|
42
|
+
}, J = () => {
|
|
43
|
+
e == null || e.next();
|
|
44
|
+
}, K = () => {
|
|
45
|
+
C.value = !C.value, k("fullWidthChange", C.value), setTimeout(() => {
|
|
46
|
+
l.value && e && (e.resize(l.value.offsetWidth, l.value.offsetHeight), S && e.display(S), P());
|
|
47
|
+
}, 350);
|
|
48
|
+
}, Q = () => {
|
|
49
|
+
f.value = !f.value;
|
|
50
|
+
}, B = (o) => {
|
|
51
|
+
L.value = o, e == null || e.display(o), f.value = !1;
|
|
52
|
+
}, p = (o) => o === L.value;
|
|
53
|
+
O({ prevPage: G, nextPage: J, toggleFullWidth: K, toggleToc: Q });
|
|
54
|
+
const N = async () => {
|
|
55
|
+
if (l.value) {
|
|
56
|
+
_.value = !0, g.value = null, x.value = [], f.value = !1, l.value.innerHTML = "", F();
|
|
57
|
+
try {
|
|
58
|
+
let o = w.url;
|
|
59
|
+
w.url.startsWith("blob:") && (o = await (await fetch(w.url)).arrayBuffer()), s = ae(o), e = s.renderTo(l.value, {
|
|
60
|
+
manager: "continuous",
|
|
61
|
+
flow: "scrolled",
|
|
62
|
+
width: "100%",
|
|
63
|
+
height: "100%"
|
|
64
|
+
}), e.themes.register("default", {
|
|
65
|
+
body: {
|
|
66
|
+
background: "#ffffff !important",
|
|
67
|
+
color: "#1a1a1a !important",
|
|
68
|
+
"font-family": '"Noto Serif SC", "Source Han Serif SC", Georgia, "Times New Roman", serif !important',
|
|
69
|
+
"font-size": "16px !important",
|
|
70
|
+
"line-height": "2 !important",
|
|
71
|
+
padding: "40px 60px !important",
|
|
72
|
+
"max-width": "100% !important",
|
|
73
|
+
"box-sizing": "border-box !important",
|
|
74
|
+
"word-break": "break-word !important",
|
|
75
|
+
"overflow-wrap": "break-word !important"
|
|
76
|
+
},
|
|
77
|
+
p: { "text-indent": "2em !important", margin: "0.8em 0 !important" },
|
|
78
|
+
h1: { "text-align": "center !important", margin: "1.5em 0 1em !important" },
|
|
79
|
+
h2: { margin: "1.2em 0 0.8em !important" },
|
|
80
|
+
h3: { margin: "1em 0 0.6em !important" },
|
|
81
|
+
img: { "max-width": "100% !important", height: "auto !important" },
|
|
82
|
+
a: { color: "#2563eb !important", "text-decoration": "none !important" }
|
|
83
|
+
}), e.themes.select("default"), await s.ready, s.locations.generate(1024).then(() => {
|
|
84
|
+
var r;
|
|
85
|
+
if (!s) return;
|
|
86
|
+
m = s.locations.length();
|
|
87
|
+
const t = e == null ? void 0 : e.currentLocation(), n = ((r = t == null ? void 0 : t.start) == null ? void 0 : r.location) ?? 0;
|
|
88
|
+
k("chapterChange", n + 1, m);
|
|
89
|
+
}).catch(() => {
|
|
90
|
+
});
|
|
91
|
+
const a = await s.loaded.navigation;
|
|
92
|
+
Array.isArray(a == null ? void 0 : a.toc) && (x.value = a.toc), await e.display(), _.value = !1, k("chapterChange", 1, m || 1), e.on("relocated", (t) => {
|
|
93
|
+
var W, d, q;
|
|
94
|
+
const n = t;
|
|
95
|
+
if ((W = n == null ? void 0 : n.start) != null && W.cfi && (S = n.start.cfi), (d = n == null ? void 0 : n.start) != null && d.href) {
|
|
96
|
+
const A = n.start.href, H = [], V = (Y) => {
|
|
97
|
+
for (const z of Y) {
|
|
98
|
+
const T = z.href.split("#")[0];
|
|
99
|
+
T && (A === T || A.endsWith("/" + T) || A.endsWith(T)) && H.push(z.href), z.subitems && V(z.subitems);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
V(x.value), H.length === 1 && (L.value = H[0]);
|
|
103
|
+
}
|
|
104
|
+
const r = (q = n == null ? void 0 : n.start) == null ? void 0 : q.location;
|
|
105
|
+
typeof r == "number" && m > 0 && k("chapterChange", r + 1, m);
|
|
106
|
+
});
|
|
107
|
+
} catch (o) {
|
|
108
|
+
console.error("EPUB 加载错误:", o), g.value = R.value("epub.load_failed"), _.value = !1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, j = () => {
|
|
112
|
+
!l.value || !e || e.resize(l.value.offsetWidth, l.value.offsetHeight);
|
|
113
|
+
};
|
|
114
|
+
let i = null;
|
|
115
|
+
const M = () => {
|
|
116
|
+
var a;
|
|
117
|
+
if (!i) return;
|
|
118
|
+
const o = i;
|
|
119
|
+
if (o.scrollTop + o.clientHeight >= o.scrollHeight - 200)
|
|
120
|
+
try {
|
|
121
|
+
const t = e == null ? void 0 : e.manager;
|
|
122
|
+
(a = t == null ? void 0 : t.check) == null || a.call(t, 500, 500);
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
}, P = () => {
|
|
126
|
+
i && (i.removeEventListener("scroll", M), i = null);
|
|
127
|
+
const o = () => {
|
|
128
|
+
var a;
|
|
129
|
+
i = ((a = l.value) == null ? void 0 : a.querySelector(".epub-container")) ?? null, i ? i.addEventListener("scroll", M, { passive: !0 }) : requestAnimationFrame(o);
|
|
130
|
+
};
|
|
131
|
+
requestAnimationFrame(o);
|
|
132
|
+
};
|
|
133
|
+
return ee(() => {
|
|
134
|
+
N(), window.addEventListener("resize", j), P();
|
|
135
|
+
}), te(() => w.url, () => N()), oe(() => {
|
|
136
|
+
window.removeEventListener("resize", j), i == null || i.removeEventListener("scroll", M), F();
|
|
137
|
+
}), (o, a) => (u(), c("div", se, [
|
|
138
|
+
g.value ? (u(), c("div", ie, [
|
|
139
|
+
v("p", fe, E(g.value), 1)
|
|
140
|
+
])) : y("", !0),
|
|
141
|
+
_.value && !g.value ? (u(), c("div", pe, [...a[2] || (a[2] = [
|
|
142
|
+
v("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
143
|
+
])])) : y("", !0),
|
|
144
|
+
x.value.length > 0 ? (u(), c("div", {
|
|
145
|
+
key: 2,
|
|
146
|
+
class: "vfp-absolute vfp-inset-0 vfp-z-20 vfp-flex",
|
|
147
|
+
style: b({ opacity: f.value ? 1 : 0, pointerEvents: f.value ? "auto" : "none", transition: "opacity 0.3s" })
|
|
148
|
+
}, [
|
|
149
|
+
v("div", {
|
|
150
|
+
class: "vfp-w-72 vfp-h-full vfp-flex vfp-flex-col",
|
|
151
|
+
style: b({
|
|
152
|
+
maxWidth: "80%",
|
|
153
|
+
background: "rgba(0,0,0,0.9)",
|
|
154
|
+
backdropFilter: "blur(12px)",
|
|
155
|
+
borderRight: "1px solid rgba(255,255,255,0.1)",
|
|
156
|
+
boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)",
|
|
157
|
+
transform: f.value ? "translateX(0)" : "translateX(-100%)",
|
|
158
|
+
transition: "transform 0.3s ease"
|
|
159
|
+
})
|
|
160
|
+
}, [
|
|
161
|
+
v("div", ue, [
|
|
162
|
+
v("span", ce, E(X(R)("toolbar.toc")), 1),
|
|
163
|
+
v("button", {
|
|
164
|
+
style: { color: "rgba(255,255,255,0.6)", background: "none", border: "none", cursor: "pointer", padding: "4px" },
|
|
165
|
+
onClick: a[0] || (a[0] = (t) => f.value = !1)
|
|
166
|
+
}, [
|
|
167
|
+
re(X(ne), { style: { width: "16px", height: "16px" } })
|
|
168
|
+
])
|
|
169
|
+
]),
|
|
170
|
+
v("div", ve, [
|
|
171
|
+
(u(!0), c($, null, D(x.value, (t, n) => (u(), c($, {
|
|
172
|
+
key: `${t.href}-${n}`
|
|
173
|
+
}, [
|
|
174
|
+
v("button", {
|
|
175
|
+
style: b({
|
|
176
|
+
width: "100%",
|
|
177
|
+
textAlign: "left",
|
|
178
|
+
padding: "8px 12px",
|
|
179
|
+
fontSize: "14px",
|
|
180
|
+
color: p(t.href) ? "white" : "rgba(255,255,255,0.7)",
|
|
181
|
+
fontWeight: p(t.href) ? "500" : "400",
|
|
182
|
+
background: p(t.href) ? "rgba(255,255,255,0.15)" : "none",
|
|
183
|
+
border: "none",
|
|
184
|
+
cursor: "pointer",
|
|
185
|
+
borderRadius: "4px",
|
|
186
|
+
overflow: "hidden",
|
|
187
|
+
textOverflow: "ellipsis",
|
|
188
|
+
whiteSpace: "nowrap",
|
|
189
|
+
display: "block",
|
|
190
|
+
transition: "all 0.15s"
|
|
191
|
+
}),
|
|
192
|
+
title: t.label,
|
|
193
|
+
onClick: (r) => B(t.href),
|
|
194
|
+
onMouseenter: (r) => !p(t.href) && (r.target.style.background = "rgba(255,255,255,0.1)"),
|
|
195
|
+
onMouseleave: (r) => !p(t.href) && (r.target.style.background = "none")
|
|
196
|
+
}, E(t.label.trim()), 45, de),
|
|
197
|
+
t.subitems && t.subitems.length > 0 ? (u(!0), c($, { key: 0 }, D(t.subitems, (r, W) => (u(), c("button", {
|
|
198
|
+
key: `${r.href}-${W}`,
|
|
199
|
+
style: b({
|
|
200
|
+
width: "100%",
|
|
201
|
+
textAlign: "left",
|
|
202
|
+
padding: "8px 12px 8px 28px",
|
|
203
|
+
fontSize: "13px",
|
|
204
|
+
color: p(r.href) ? "white" : "rgba(255,255,255,0.6)",
|
|
205
|
+
fontWeight: p(r.href) ? "500" : "400",
|
|
206
|
+
background: p(r.href) ? "rgba(255,255,255,0.15)" : "none",
|
|
207
|
+
border: "none",
|
|
208
|
+
cursor: "pointer",
|
|
209
|
+
borderRadius: "4px",
|
|
210
|
+
overflow: "hidden",
|
|
211
|
+
textOverflow: "ellipsis",
|
|
212
|
+
whiteSpace: "nowrap",
|
|
213
|
+
display: "block",
|
|
214
|
+
transition: "all 0.15s"
|
|
215
|
+
}),
|
|
216
|
+
title: r.label,
|
|
217
|
+
onClick: (d) => B(r.href),
|
|
218
|
+
onMouseenter: (d) => !p(r.href) && (d.target.style.background = "rgba(255,255,255,0.1)"),
|
|
219
|
+
onMouseleave: (d) => !p(r.href) && (d.target.style.background = "none")
|
|
220
|
+
}, E(r.label.trim()), 45, he))), 128)) : y("", !0)
|
|
221
|
+
], 64))), 128))
|
|
222
|
+
])
|
|
223
|
+
], 4),
|
|
224
|
+
v("div", {
|
|
225
|
+
class: "vfp-flex-1",
|
|
226
|
+
style: b({ background: f.value ? "rgba(0,0,0,0.3)" : "transparent", transition: "background 0.3s" }),
|
|
227
|
+
onClick: a[1] || (a[1] = (t) => f.value = !1)
|
|
228
|
+
}, null, 4)
|
|
229
|
+
], 4)) : y("", !0),
|
|
230
|
+
g.value ? y("", !0) : (u(), c("div", {
|
|
231
|
+
key: 3,
|
|
232
|
+
ref_key: "viewerRef",
|
|
233
|
+
ref: l,
|
|
234
|
+
class: "vfp-h-full vfp-bg-surface-toolbar",
|
|
235
|
+
style: b({
|
|
236
|
+
width: C.value ? "100%" : `${ge}px`,
|
|
237
|
+
maxWidth: "100%",
|
|
238
|
+
transition: "width 0.3s ease",
|
|
239
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.12)",
|
|
240
|
+
overflow: "hidden"
|
|
241
|
+
})
|
|
242
|
+
}, null, 4))
|
|
243
|
+
]));
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
export {
|
|
247
|
+
we as default
|
|
248
|
+
};
|
|
249
|
+
//# sourceMappingURL=index-D9wf6m37.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-D9wf6m37.mjs","sources":["../../src/renderers/Epub/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport ePub from '@likecoin/epub-ts';\nimport { X } from 'lucide-vue-next';\nimport { useTranslator } from '../../composables/useTranslator';\n\ninterface TocItem {\n label: string;\n href: string;\n subitems?: TocItem[];\n}\n\ninterface RenditionLike {\n display: (target?: string) => Promise<unknown>;\n next: () => Promise<unknown>;\n prev: () => Promise<unknown>;\n on: (event: string, cb: (...args: unknown[]) => void) => void;\n resize: (width: number, height: number) => void;\n currentLocation: () => unknown;\n destroy?: () => void;\n themes: {\n register: (name: string, styles: Record<string, unknown>) => void;\n select: (name: string) => void;\n };\n}\n\ninterface BookLike {\n ready: Promise<unknown>;\n loaded: { navigation: Promise<unknown> };\n locations: {\n generate: (chars: number) => Promise<string[]>;\n length: () => number;\n locationFromCfi: (cfi: string) => number;\n };\n renderTo: (el: HTMLElement, opts: Record<string, unknown>) => RenditionLike;\n destroy: () => void;\n}\n\nconst A4_WIDTH = 794;\n\nconst props = defineProps<{ url: string }>();\n\nconst { t } = useTranslator();\n\nconst emit = defineEmits<{\n (e: 'chapterChange', current: number, total: number): void;\n (e: 'fullWidthChange', isFullWidth: boolean): void;\n}>();\n\nconst viewerRef = ref<HTMLDivElement | null>(null);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst isFullWidth = ref(false);\nconst toc = ref<TocItem[]>([]);\nconst showToc = ref(false);\nconst activeTocHref = ref('');\n\nlet book: BookLike | null = null;\nlet rendition: RenditionLike | null = null;\nlet totalLocations = 0;\nlet lastCfi: string | null = null;\n\nconst cleanup = () => {\n try { rendition?.destroy?.(); } catch { /* ignore */ }\n try { book?.destroy(); } catch { /* ignore */ }\n rendition = null;\n book = null;\n totalLocations = 0;\n lastCfi = null;\n};\n\nconst prevPage = () => { rendition?.prev(); };\nconst nextPage = () => { rendition?.next(); };\nconst toggleFullWidth = () => {\n isFullWidth.value = !isFullWidth.value;\n emit('fullWidthChange', isFullWidth.value);\n setTimeout(() => {\n if (viewerRef.value && rendition) {\n rendition.resize(viewerRef.value.offsetWidth, viewerRef.value.offsetHeight);\n if (lastCfi) {\n rendition.display(lastCfi);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }\n }, 350);\n};\nconst toggleToc = () => { showToc.value = !showToc.value; };\nconst handleTocClick = (href: string) => {\n activeTocHref.value = href;\n rendition?.display(href);\n showToc.value = false;\n};\n\nconst isActive = (href: string) => {\n return href === activeTocHref.value;\n};\n\ndefineExpose({ prevPage, nextPage, toggleFullWidth, toggleToc });\n\nconst loadEpub = async () => {\n if (!viewerRef.value) return;\n\n loading.value = true;\n error.value = null;\n toc.value = [];\n showToc.value = false;\n viewerRef.value.innerHTML = '';\n cleanup();\n\n try {\n let bookInput: string | ArrayBuffer = props.url;\n if (props.url.startsWith('blob:')) {\n const resp = await fetch(props.url);\n bookInput = await resp.arrayBuffer();\n }\n\n book = ePub(bookInput) as unknown as BookLike;\n\n rendition = book.renderTo(viewerRef.value, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n\n rendition.themes.register('default', {\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 padding: '40px 60px !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: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引\n book.locations.generate(1024).then(() => {\n if (!book) return;\n totalLocations = book.locations.length();\n const loc = rendition?.currentLocation() as { start?: { location?: number } } | undefined;\n const cur = loc?.start?.location ?? 0;\n emit('chapterChange', cur + 1, totalLocations);\n }).catch(() => { /* ignore */ });\n\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (Array.isArray(nav?.toc)) {\n toc.value = nav.toc;\n }\n\n await rendition.display();\n\n loading.value = false;\n emit('chapterChange', 1, totalLocations || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfi = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(toc.value);\n if (matches.length === 1) {\n activeTocHref.value = matches[0];\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n if (typeof cur === 'number' && totalLocations > 0) {\n emit('chapterChange', cur + 1, totalLocations);\n }\n });\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n error.value = t.value('epub.load_failed');\n loading.value = false;\n }\n};\n\nconst onResize = () => {\n if (!viewerRef.value || !rendition) return;\n rendition.resize(viewerRef.value.offsetWidth, viewerRef.value.offsetHeight);\n};\n\n// 监听 epub-container 滚动,接近底部时强制加载后续 section\nlet scrollContainer: Element | null = null;\nconst onContainerScroll = () => {\n if (!scrollContainer) return;\n const el = scrollContainer as HTMLElement;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 200) {\n try {\n const mgr = (rendition as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n // 传递垂直偏移量参数,让 check() 在接近底部时就触发加载下一节\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n};\n\nconst reattachScrollListener = () => {\n // 清理旧监听\n if (scrollContainer) {\n scrollContainer.removeEventListener('scroll', onContainerScroll);\n scrollContainer = null;\n }\n const tryAttach = () => {\n scrollContainer = viewerRef.value?.querySelector('.epub-container') ?? null;\n if (scrollContainer) {\n scrollContainer.addEventListener('scroll', onContainerScroll, { passive: true });\n } else {\n requestAnimationFrame(tryAttach);\n }\n };\n requestAnimationFrame(tryAttach);\n};\n\nonMounted(() => {\n loadEpub();\n window.addEventListener('resize', onResize);\n reattachScrollListener();\n});\n\nwatch(() => props.url, () => loadEpub());\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', onResize);\n scrollContainer?.removeEventListener('scroll', onContainerScroll);\n cleanup();\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-w-full vfp-h-full vfp-flex vfp-justify-center vfp-overflow-hidden\" style=\"background: #f5f5f0\">\n <div v-if=\"error\" class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error }}</p>\n </div>\n\n <div\n v-if=\"loading && !error\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-z-10\"\n >\n <div class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\" />\n </div>\n\n <!-- 目录侧栏 - 滑入动画 -->\n <div\n v-if=\"toc.length > 0\"\n class=\"vfp-absolute vfp-inset-0 vfp-z-20 vfp-flex\"\n :style=\"{ opacity: showToc ? 1 : 0, pointerEvents: showToc ? 'auto' : 'none', transition: 'opacity 0.3s' }\"\n >\n <div\n class=\"vfp-w-72 vfp-h-full vfp-flex vfp-flex-col\"\n :style=\"{\n maxWidth: '80%',\n background: 'rgba(0,0,0,0.9)',\n backdropFilter: 'blur(12px)',\n borderRight: '1px solid rgba(255,255,255,0.1)',\n boxShadow: '0 25px 50px -12px rgba(0,0,0,0.25)',\n transform: showToc ? 'translateX(0)' : 'translateX(-100%)',\n transition: 'transform 0.3s ease',\n }\"\n >\n <div class=\"vfp-flex vfp-items-center vfp-justify-between vfp-flex-shrink-0\" style=\"padding: 12px 16px; border-bottom: 1px solid rgba(255,255,255,0.1)\">\n <span style=\"color: white; font-weight: 500; font-size: 14px\">{{ t('toolbar.toc') }}</span>\n <button style=\"color: rgba(255,255,255,0.6); background: none; border: none; cursor: pointer; padding: 4px\" @click=\"showToc = false\">\n <X style=\"width: 16px; height: 16px\" />\n </button>\n </div>\n <div class=\"vfp-flex-1 vfp-overflow-y-auto\" style=\"padding: 8px 4px\">\n <template v-for=\"(item, i) in toc\" :key=\"`${item.href}-${i}`\">\n <button\n :style=\"{\n width: '100%', textAlign: 'left', padding: '8px 12px', fontSize: '14px',\n color: isActive(item.href) ? 'white' : 'rgba(255,255,255,0.7)',\n fontWeight: isActive(item.href) ? '500' : '400',\n background: isActive(item.href) ? 'rgba(255,255,255,0.15)' : 'none',\n border: 'none', cursor: 'pointer', borderRadius: '4px',\n overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block',\n transition: 'all 0.15s',\n }\"\n :title=\"item.label\"\n @click=\"handleTocClick(item.href)\"\n @mouseenter=\"!isActive(item.href) && (($event.target as HTMLElement).style.background = 'rgba(255,255,255,0.1)')\"\n @mouseleave=\"!isActive(item.href) && (($event.target as HTMLElement).style.background = 'none')\"\n >\n {{ item.label.trim() }}\n </button>\n <template v-if=\"item.subitems && item.subitems.length > 0\">\n <button\n v-for=\"(sub, j) in item.subitems\"\n :key=\"`${sub.href}-${j}`\"\n :style=\"{\n width: '100%', textAlign: 'left', padding: '8px 12px 8px 28px', fontSize: '13px',\n color: isActive(sub.href) ? 'white' : 'rgba(255,255,255,0.6)',\n fontWeight: isActive(sub.href) ? '500' : '400',\n background: isActive(sub.href) ? 'rgba(255,255,255,0.15)' : 'none',\n border: 'none', cursor: 'pointer', borderRadius: '4px',\n overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block',\n transition: 'all 0.15s',\n }\"\n :title=\"sub.label\"\n @click=\"handleTocClick(sub.href)\"\n @mouseenter=\"!isActive(sub.href) && (($event.target as HTMLElement).style.background = 'rgba(255,255,255,0.1)')\"\n @mouseleave=\"!isActive(sub.href) && (($event.target as HTMLElement).style.background = 'none')\"\n >\n {{ sub.label.trim() }}\n </button>\n </template>\n </template>\n </div>\n </div>\n <div\n class=\"vfp-flex-1\"\n :style=\"{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent', transition: 'background 0.3s' }\"\n @click=\"showToc = false\"\n />\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"viewerRef\"\n class=\"vfp-h-full vfp-bg-surface-toolbar\"\n :style=\"{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n boxShadow: '0 1px 3px rgba(0,0,0,0.12)',\n overflow: 'hidden',\n }\"\n />\n </div>\n</template>\n\n<style>\n.epub-container { overflow-y: auto !important; scrollbar-width: thin; }\n.epub-container::-webkit-scrollbar { width: 8px; }\n.epub-container::-webkit-scrollbar-track { background: transparent; }\n.epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }\n.epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }\n.epub-view > iframe { background: white; }\n</style>\n"],"names":["A4_WIDTH","props","__props","t","useTranslator","emit","__emit","viewerRef","ref","loading","error","isFullWidth","toc","showToc","activeTocHref","book","rendition","totalLocations","lastCfi","cleanup","_a","prevPage","nextPage","toggleFullWidth","reattachScrollListener","toggleToc","handleTocClick","href","isActive","__expose","loadEpub","bookInput","ePub","loc","cur","nav","location","_b","spineHref","matches","collect","items","item","base","_c","err","onResize","scrollContainer","onContainerScroll","el","mgr","tryAttach","onMounted","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_toDisplayString","_hoisted_4","_cache","_normalizeStyle","_hoisted_5","_hoisted_6","_unref","_createVNode","X","_hoisted_7","_Fragment","_renderList","i","$event","_hoisted_8","sub","j","_hoisted_9"],"mappings":"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"}
|