@eternalheart/vue-file-preview 1.3.6 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/lib/FilePreviewContent.vue.d.ts.map +1 -1
  2. package/lib/FilePreviewEmbed.vue.d.ts.map +1 -1
  3. package/lib/FilePreviewModal.vue.d.ts.map +1 -1
  4. package/lib/chunks/index-BI0dSTSM.mjs +77 -0
  5. package/lib/chunks/index-BI0dSTSM.mjs.map +1 -0
  6. package/lib/chunks/index-BW61ZRev.mjs +111 -0
  7. package/lib/chunks/index-BW61ZRev.mjs.map +1 -0
  8. package/lib/chunks/index-C8ZF84WX.mjs +113 -0
  9. package/lib/chunks/index-C8ZF84WX.mjs.map +1 -0
  10. package/lib/chunks/index-CB0zCxJb.mjs +353 -0
  11. package/lib/chunks/index-CB0zCxJb.mjs.map +1 -0
  12. package/lib/chunks/index-CBCQs1ZC.mjs +116 -0
  13. package/lib/chunks/index-CBCQs1ZC.mjs.map +1 -0
  14. package/lib/chunks/index-CbKSdAt_.mjs +391 -0
  15. package/lib/chunks/index-CbKSdAt_.mjs.map +1 -0
  16. package/lib/chunks/index-CcJ5NmY1.mjs +152 -0
  17. package/lib/chunks/index-CcJ5NmY1.mjs.map +1 -0
  18. package/lib/chunks/index-ClxBxmPR.mjs +249 -0
  19. package/lib/chunks/index-ClxBxmPR.mjs.map +1 -0
  20. package/lib/chunks/index-D9lByoJw.mjs +111 -0
  21. package/lib/chunks/index-D9lByoJw.mjs.map +1 -0
  22. package/lib/chunks/index-DTLDLOGO.mjs +129 -0
  23. package/lib/chunks/index-DTLDLOGO.mjs.map +1 -0
  24. package/lib/chunks/index-DUUsS_T4.mjs +134 -0
  25. package/lib/chunks/index-DUUsS_T4.mjs.map +1 -0
  26. package/lib/chunks/index-Doy0FvQW.mjs +136 -0
  27. package/lib/chunks/index-Doy0FvQW.mjs.map +1 -0
  28. package/lib/chunks/index-DpAxU2JM.mjs +2017 -0
  29. package/lib/chunks/index-DpAxU2JM.mjs.map +1 -0
  30. package/lib/chunks/index-DsznjwsH.mjs +103 -0
  31. package/lib/chunks/index-DsznjwsH.mjs.map +1 -0
  32. package/lib/chunks/index-SAfVQyNJ.mjs +281 -0
  33. package/lib/chunks/index-SAfVQyNJ.mjs.map +1 -0
  34. package/lib/chunks/index-S_kGRh6H.mjs +203 -0
  35. package/lib/chunks/index-S_kGRh6H.mjs.map +1 -0
  36. package/lib/chunks/index-kBPb_OKm.mjs +139 -0
  37. package/lib/chunks/index-kBPb_OKm.mjs.map +1 -0
  38. package/lib/chunks/index-yMb1JUC4.mjs +84 -0
  39. package/lib/chunks/index-yMb1JUC4.mjs.map +1 -0
  40. package/lib/composables/useResolvedTheme.d.ts +15 -0
  41. package/lib/composables/useResolvedTheme.d.ts.map +1 -0
  42. package/lib/index.cjs +24 -499
  43. package/lib/index.cjs.map +1 -1
  44. package/lib/index.css +1 -1
  45. package/lib/index.mjs +12 -44597
  46. package/lib/index.mjs.map +1 -1
  47. package/lib/renderers/Audio/index.vue.d.ts.map +1 -1
  48. package/lib/renderers/Csv/index.vue.d.ts.map +1 -1
  49. package/lib/renderers/Json/index.vue.d.ts.map +1 -1
  50. package/lib/renderers/Markdown/index.vue.d.ts.map +1 -1
  51. package/lib/renderers/Pptx/index.vue.d.ts.map +1 -1
  52. package/lib/renderers/RendererLoading.vue.d.ts +3 -0
  53. package/lib/renderers/RendererLoading.vue.d.ts.map +1 -0
  54. package/lib/renderers/Text/index.vue.d.ts.map +1 -1
  55. package/lib/renderers/Video/index.vue.d.ts.map +1 -1
  56. package/lib/renderers/Xlsx/index.vue.d.ts.map +1 -1
  57. package/lib/renderers/Xml/index.vue.d.ts.map +1 -1
  58. package/lib/renderers/Zip/index.vue.d.ts.map +1 -1
  59. package/lib/renderers/lazy.d.ts +19 -0
  60. package/lib/renderers/lazy.d.ts.map +1 -0
  61. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CcJ5NmY1.mjs","sources":["../../src/renderers/Pptx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { Presentation } from 'lucide-vue-next';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst props = withDefaults(\n defineProps<{\n url: string;\n tiled?: boolean;\n }>(),\n { tiled: true }\n);\n\nconst { t } = useTranslator();\n\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst slideCount = ref(0);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet previewer: ReturnType<typeof init> | null = null;\nlet resizeObserver: ResizeObserver | null = null;\nlet arrayBufferRef: ArrayBuffer | null = null;\nlet resizeTimeout: number | null = null;\nlet lastDimensions = { width: 0, height: 0 };\n\nconst calculateDimensions = () => {\n if (!containerRef.value) return { width: 960, height: 540 };\n const rawWidth = containerRef.value.clientWidth;\n const parentWidth = containerRef.value.parentElement?.clientWidth || 0;\n const containerWidth = rawWidth > 100 ? rawWidth : parentWidth > 100 ? parentWidth : 300;\n const height = Math.floor((containerWidth * 9) / 16);\n return { width: containerWidth, height };\n};\n\nconst reinitializePreviewer = async () => {\n if (!containerRef.value || !arrayBufferRef || slideCount.value === 0) return;\n\n try {\n if (previewer) {\n try {\n previewer.destroy();\n } catch {\n // ignore\n }\n }\n\n containerRef.value.innerHTML = '';\n\n const currentDimensions = calculateDimensions();\n previewer = init(containerRef.value, {\n width: currentDimensions.width,\n height: props.tiled ? currentDimensions.height * slideCount.value : currentDimensions.height,\n mode: props.tiled ? 'list' : 'slide',\n });\n\n await previewer.preview(arrayBufferRef);\n } catch {\n // 静默处理\n }\n};\n\nconst loadPptx = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n let timeoutId: number | null = window.setTimeout(() => {\n error.value = t.value('pptx.timeout');\n loading.value = false;\n }, 30000);\n\n try {\n const response = await fetch(props.url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) throw new Error(t.value('pptx.not_found'));\n if (response.status === 403) throw new Error('无权限访问此文件');\n if (response.status >= 500) throw new Error('服务器错误,请稍后重试');\n throw new Error(`文件加载失败 (${response.status})`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n if (arrayBuffer.byteLength === 0) throw new Error('文件为空');\n\n arrayBufferRef = arrayBuffer;\n\n // 步骤 1: 创建隐藏容器获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t.value('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n if (!count || count === 0) throw new Error(t.value('pptx.no_pages'));\n\n tempPreviewer.destroy();\n\n slideCount.value = count;\n\n if (containerRef.value) {\n containerRef.value.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n previewer = init(containerRef.value, {\n width: currentDimensions.width,\n height: props.tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: props.tiled ? 'list' : 'slide',\n });\n\n await previewer.preview(arrayBuffer);\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n loading.value = false;\n } finally {\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n if (timeoutId !== null) clearTimeout(timeoutId);\n let errorMsg = t.value('pptx.parse_failed');\n if (err instanceof Error) errorMsg = err.message;\n else if (typeof err === 'string') errorMsg = err;\n error.value = errorMsg;\n loading.value = false;\n }\n};\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n let isInitialRender = true;\n\n resizeObserver = new ResizeObserver(() => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensions = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensions = newDimensions;\n\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n\n resizeTimeout = window.setTimeout(() => {\n if (previewer && arrayBufferRef) reinitializePreviewer();\n }, 800);\n });\n\n resizeObserver.observe(containerRef.value);\n\n setTimeout(() => {\n requestAnimationFrame(() => requestAnimationFrame(() => loadPptx()));\n }, 150);\n});\n\nwatch(\n () => props.url,\n () => {\n loadPptx();\n }\n);\n\nonBeforeUnmount(() => {\n if (resizeObserver) resizeObserver.disconnect();\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n arrayBufferRef = null;\n slideCount.value = 0;\n if (previewer) {\n try {\n previewer.destroy();\n } catch {\n // ignore\n }\n }\n previewer = null;\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full\">\n <div\n v-if=\"loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('pptx.loading') }}</p>\n </div>\n </div>\n\n <div\n v-if=\"error && !loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4\">\n <div\n class=\"vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-orange-500 vfp-via-red-500 vfp-to-pink-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl\"\n >\n <Presentation class=\"vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary\" />\n </div>\n <p class=\"vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium\">\n {{ t('pptx.load_failed') }}\n </p>\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6\">{{ error }}</p>\n <a\n :href=\"url\"\n download\n class=\"vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg\"\n >\n 下载文件\n </a>\n <p class=\"vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"containerRef\"\n class=\"pptx-wrapper vfp-w-full vfp-max-w-full md:vfp-max-w-6xl\"\n :style=\"{ opacity: loading ? 0 : 1 }\"\n />\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","loading","ref","error","slideCount","containerRef","previewer","resizeObserver","arrayBufferRef","resizeTimeout","lastDimensions","calculateDimensions","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","init","loadPptx","timeoutId","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","onMounted","isInitialRender","newDimensions","widthDiff","heightDiff","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_hoisted_4","_toDisplayString","_unref","_hoisted_5","_hoisted_6","_hoisted_7","_createVNode","Presentation","_hoisted_8","_hoisted_9","_hoisted_10","_cache"],"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-DpAxU2JM.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-ClxBxmPR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-ClxBxmPR.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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"}
@@ -0,0 +1,111 @@
1
+ import { defineComponent as H, ref as x, onMounted as M, watch as S, onBeforeUnmount as j, openBlock as u, createElementBlock as g, createElementVNode as y, toDisplayString as b, createCommentVNode as w, withDirectives as W, vShow as q, nextTick as A } from "vue";
2
+ import { S as F, u as I } from "./index-DpAxU2JM.mjs";
3
+ import * as D from "pdfjs-dist/build/pdf.mjs";
4
+ const N = {
5
+ key: 0,
6
+ class: "vfp-text-fg-secondary vfp-text-center"
7
+ }, U = { class: "vfp-text-lg" }, G = {
8
+ key: 1,
9
+ class: "vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen"
10
+ }, J = { class: "pdf-pages vfp-flex vfp-flex-col vfp-gap-4" }, K = {
11
+ key: 2,
12
+ class: "vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak"
13
+ }, X = /* @__PURE__ */ H({
14
+ __name: "index",
15
+ props: {
16
+ url: {},
17
+ zoom: {},
18
+ currentPage: {}
19
+ },
20
+ emits: ["pageChange", "totalPagesChange", "pageWidthChange"],
21
+ setup(C, { emit: R }) {
22
+ F(D);
23
+ const p = C, v = R, { t: V } = I(), l = x(0), i = x(null), r = x(null);
24
+ let n = null;
25
+ const m = [], B = async (e, o, a) => {
26
+ if (!n) return;
27
+ const c = await n.getPage(e), s = c.getViewport({ scale: o }), t = document.createElement("canvas");
28
+ t.width = s.width, t.height = s.height, t.style.maxWidth = "100%", t.style.height = "auto", t.style.borderRadius = "0", t.style.display = "block", t.style.boxShadow = "0 25px 50px -12px rgba(0,0,0,0.25)", t.style.filter = "brightness(0.95) contrast(1.05)";
29
+ const d = t.getContext("2d");
30
+ if (!d) return;
31
+ if (await c.render({ canvasContext: d, viewport: s }).promise, e === 1) {
32
+ const h = c.getViewport({ scale: 1 });
33
+ v("pageWidthChange", h.width);
34
+ }
35
+ a.innerHTML = "", a.appendChild(t);
36
+ const f = document.createElement("div");
37
+ f.textContent = String(e), f.style.cssText = "position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;", a.appendChild(f);
38
+ }, k = async () => {
39
+ if (!n || !r.value) return;
40
+ const e = r.value.querySelector(".pdf-pages");
41
+ if (e) {
42
+ e.innerHTML = "", m.length = 0;
43
+ for (let o = 1; o <= l.value; o++) {
44
+ const a = document.createElement("div");
45
+ a.style.cssText = "position:relative;display:flex;justify-content:center;", e.appendChild(a), m.push(a), await B(o, p.zoom, a);
46
+ }
47
+ }
48
+ }, _ = async () => {
49
+ if (i.value = null, l.value = 0, n) {
50
+ try {
51
+ n.destroy();
52
+ } catch {
53
+ }
54
+ n = null;
55
+ }
56
+ try {
57
+ n = await D.getDocument({ url: p.url }).promise, l.value = n.numPages, v("totalPagesChange", n.numPages), v("pageChange", 1), await A(), await k();
58
+ } catch (e) {
59
+ console.error("PDF 加载错误:", e), i.value = V.value("pdf.load_failed");
60
+ }
61
+ }, P = () => {
62
+ if (!r.value) return;
63
+ const e = r.value, o = e.scrollTop, a = e.clientHeight, c = o + a / 2;
64
+ let s = 1, t = 1 / 0;
65
+ m.forEach((d, f) => {
66
+ const h = f + 1, T = d.getBoundingClientRect(), L = e.getBoundingClientRect(), z = T.top - L.top + T.height / 2 + o, E = Math.abs(z - c);
67
+ E < t && (t = E, s = h);
68
+ }), s !== p.currentPage && v("pageChange", s);
69
+ };
70
+ return M(() => {
71
+ _(), r.value && r.value.addEventListener("scroll", P);
72
+ }), S(
73
+ () => p.url,
74
+ () => {
75
+ _();
76
+ }
77
+ ), S(
78
+ () => p.zoom,
79
+ () => {
80
+ k();
81
+ }
82
+ ), j(() => {
83
+ if (r.value && r.value.removeEventListener("scroll", P), n) {
84
+ try {
85
+ n.destroy();
86
+ } catch {
87
+ }
88
+ n = null;
89
+ }
90
+ }), (e, o) => (u(), g("div", {
91
+ ref_key: "containerRef",
92
+ ref: r,
93
+ class: "vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4"
94
+ }, [
95
+ i.value ? (u(), g("div", N, [
96
+ y("p", U, b(i.value), 1)
97
+ ])) : w("", !0),
98
+ !i.value && l.value === 0 ? (u(), g("div", G, [...o[0] || (o[0] = [
99
+ y("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)
100
+ ])])) : w("", !0),
101
+ W(y("div", J, null, 512), [
102
+ [q, !i.value && l.value > 0]
103
+ ]),
104
+ l.value > 0 ? (u(), g("div", K, " 第 " + b(C.currentPage) + " 页 / 共 " + b(l.value) + " 页 ", 1)) : w("", !0)
105
+ ], 512));
106
+ }
107
+ });
108
+ export {
109
+ X as default
110
+ };
111
+ //# sourceMappingURL=index-D9lByoJw.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-D9lByoJw.mjs","sources":["../../src/renderers/Pdf/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';\nimport { configurePdfWorker } from '@eternalheart/file-preview-core';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\nimport { useTranslator } from '../../composables/useTranslator';\n\n// 在模块加载时配置 PDF.js worker(默认走 CDN)\nconfigurePdfWorker(pdfjsLib);\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\nconst props = defineProps<{\n url: string;\n zoom: number;\n currentPage: number;\n}>();\n\nconst emit = defineEmits<{\n (e: 'pageChange', page: number): void;\n (e: 'totalPagesChange', total: number): void;\n (e: 'pageWidthChange', width: number): void;\n}>();\n\nconst { t } = useTranslator();\n\nconst numPages = ref(0);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet pdfDoc: PdfDocumentProxy | null = null;\nconst pageElements: HTMLDivElement[] = [];\n\nconst renderPage = async (pageNumber: number, scale: number, container: HTMLDivElement) => {\n if (!pdfDoc) return;\n const page = await pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n canvas.style.boxShadow = '0 25px 50px -12px rgba(0,0,0,0.25)';\n canvas.style.filter = 'brightness(0.95) contrast(1.05)';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n await page.render({ canvasContext: ctx, viewport }).promise;\n\n // 上报第一页原始宽度\n if (pageNumber === 1) {\n const baseViewport = page.getViewport({ scale: 1 });\n emit('pageWidthChange', baseViewport.width);\n }\n\n container.innerHTML = '';\n container.appendChild(canvas);\n\n // 页码标签\n const label = document.createElement('div');\n label.textContent = String(pageNumber);\n label.style.cssText =\n 'position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;';\n container.appendChild(label);\n};\n\nconst renderAll = async () => {\n if (!pdfDoc || !containerRef.value) return;\n const wrapper = containerRef.value.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n wrapper.innerHTML = '';\n pageElements.length = 0;\n\n for (let i = 1; i <= numPages.value; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.style.cssText = 'position:relative;display:flex;justify-content:center;';\n wrapper.appendChild(pageDiv);\n pageElements.push(pageDiv);\n // eslint-disable-next-line no-await-in-loop\n await renderPage(i, props.zoom, pageDiv);\n }\n};\n\nconst loadPdf = async () => {\n error.value = null;\n numPages.value = 0;\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url: props.url });\n pdfDoc = (await loadingTask.promise) as PdfDocumentProxy;\n numPages.value = pdfDoc.numPages;\n emit('totalPagesChange', pdfDoc.numPages);\n emit('pageChange', 1);\n await nextTick();\n await renderAll();\n } catch (err) {\n console.error('PDF 加载错误:', err);\n error.value = t.value('pdf.load_failed');\n }\n};\n\nconst handleScroll = () => {\n if (!containerRef.value) return;\n\n const container = containerRef.value;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageElements.forEach((pageEl, idx) => {\n const pageNumber = idx + 1;\n const rect = pageEl.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== props.currentPage) {\n emit('pageChange', currentVisiblePage);\n }\n};\n\nonMounted(() => {\n loadPdf();\n if (containerRef.value) {\n containerRef.value.addEventListener('scroll', handleScroll);\n }\n});\n\nwatch(\n () => props.url,\n () => {\n loadPdf();\n }\n);\n\nwatch(\n () => props.zoom,\n () => {\n renderAll();\n }\n);\n\nonBeforeUnmount(() => {\n if (containerRef.value) {\n containerRef.value.removeEventListener('scroll', handleScroll);\n }\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n});\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4\"\n >\n <div v-if=\"error\" class=\"vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error }}</p>\n </div>\n\n <div v-if=\"!error && numPages === 0\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen\">\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-show=\"!error && numPages > 0\" class=\"pdf-pages vfp-flex vfp-flex-col vfp-gap-4\" />\n\n <div\n v-if=\"numPages > 0\"\n class=\"vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak\"\n >\n 第 {{ currentPage }} 页 / 共 {{ numPages }} 页\n </div>\n </div>\n</template>\n"],"names":["configurePdfWorker","pdfjsLib","props","__props","emit","__emit","t","useTranslator","numPages","ref","error","containerRef","pdfDoc","pageElements","renderPage","pageNumber","scale","container","page","viewport","canvas","ctx","baseViewport","label","renderAll","wrapper","i","pageDiv","loadPdf","nextTick","err","handleScroll","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","pageEl","idx","rect","containerRect","pageCenter","distance","onMounted","watch","onBeforeUnmount","_createElementBlock","_openBlock","_hoisted_1","_createElementVNode","_hoisted_2","_toDisplayString","_hoisted_3","_cache","_withDirectives","_hoisted_4","_vShow","_hoisted_5"],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import { defineComponent as E, ref as h, onMounted as T, watch as D, onBeforeUnmount as M, openBlock as u, createElementBlock as c, createElementVNode as s, toDisplayString as x, unref as w, createCommentVNode as g, createVNode as S, normalizeStyle as z } from "vue";
2
+ import { FileSpreadsheet as W } from "lucide-vue-next";
3
+ import B from "exceljs";
4
+ import C from "x-data-spreadsheet";
5
+ /* empty css */
6
+ import { u as H, C as R } from "./index-DpAxU2JM.mjs";
7
+ const j = { class: "vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full" }, L = {
8
+ key: 0,
9
+ class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10"
10
+ }, N = { class: "vfp-text-center" }, V = { class: "vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium" }, F = {
11
+ key: 1,
12
+ class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10"
13
+ }, O = { class: "vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4" }, q = { class: "vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-green-500 vfp-via-emerald-500 vfp-to-teal-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl" }, A = { class: "vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium" }, G = { class: "vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6" }, I = ["href"], X = /* @__PURE__ */ E({
14
+ __name: "index",
15
+ props: {
16
+ url: {}
17
+ },
18
+ setup(b) {
19
+ const _ = b, { t: p } = H(), o = h(!0), l = h(null), r = h(null);
20
+ let n = null, v = null, a = null, d = { width: 0, height: 0 };
21
+ const m = () => {
22
+ if (!r.value) return { width: 800, height: 600 };
23
+ const e = r.value.clientWidth, t = r.value.clientHeight, f = e > 100 ? e : 800, i = t > 100 ? t : 600;
24
+ return { width: f, height: i };
25
+ }, y = () => {
26
+ if (!r.value || !n) return;
27
+ r.value.innerHTML = "";
28
+ const { width: e, height: t } = m(), f = e < 640;
29
+ new C(r.value, {
30
+ mode: "read",
31
+ showToolbar: !1,
32
+ showContextmenu: !1,
33
+ showGrid: !0,
34
+ row: {
35
+ len: 100,
36
+ height: 25
37
+ },
38
+ col: {
39
+ len: 26,
40
+ width: f ? 80 : 100,
41
+ indexWidth: f ? 40 : 60,
42
+ minWidth: f ? 40 : 60
43
+ },
44
+ view: {
45
+ height: () => t,
46
+ width: () => e
47
+ }
48
+ }).loadData(n);
49
+ }, k = async () => {
50
+ if (r.value) {
51
+ o.value = !0, l.value = null;
52
+ try {
53
+ const e = await fetch(_.url, {
54
+ mode: "cors",
55
+ credentials: "omit",
56
+ redirect: "follow"
57
+ });
58
+ if (!e.ok)
59
+ throw e.status === 404 ? new Error(p.value("xlsx.not_found")) : e.status === 403 ? new Error("无权限访问此文件") : new Error(`文件加载失败 (${e.status})`);
60
+ const t = await e.arrayBuffer();
61
+ if (t.byteLength === 0)
62
+ throw new Error("文件为空");
63
+ const f = new B.Workbook();
64
+ await f.xlsx.load(t), n = R(f), y(), o.value = !1;
65
+ } catch (e) {
66
+ console.error("Excel 解析错误:", e);
67
+ let t = p.value("xlsx.parse_failed");
68
+ e instanceof Error && (t = e.message), l.value = t, o.value = !1;
69
+ }
70
+ }
71
+ };
72
+ return T(() => {
73
+ if (!r.value) return;
74
+ let e = !0;
75
+ v = new ResizeObserver(() => {
76
+ if (e) {
77
+ e = !1, d = m();
78
+ return;
79
+ }
80
+ const t = m(), f = Math.abs(d.width - t.width), i = Math.abs(d.height - t.height);
81
+ f < 10 && i < 10 || (d = t, a !== null && clearTimeout(a), a = window.setTimeout(() => {
82
+ n && y();
83
+ }, 500));
84
+ }), v.observe(r.value), setTimeout(() => {
85
+ requestAnimationFrame(() => k());
86
+ }, 100);
87
+ }), D(
88
+ () => _.url,
89
+ () => {
90
+ k();
91
+ }
92
+ ), M(() => {
93
+ v && v.disconnect(), a !== null && clearTimeout(a), n = null, r.value && (r.value.innerHTML = "");
94
+ }), (e, t) => (u(), c("div", j, [
95
+ o.value ? (u(), c("div", L, [
96
+ s("div", N, [
97
+ t[0] || (t[0] = s("div", { class: "vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)),
98
+ s("p", V, x(w(p)("xlsx.loading")), 1)
99
+ ])
100
+ ])) : g("", !0),
101
+ l.value && !o.value ? (u(), c("div", F, [
102
+ s("div", O, [
103
+ s("div", q, [
104
+ S(w(W), { class: "vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary" })
105
+ ]),
106
+ s("p", A, x(w(p)("xlsx.load_failed")), 1),
107
+ s("p", G, x(l.value), 1),
108
+ s("a", {
109
+ href: b.url,
110
+ download: "",
111
+ class: "vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg"
112
+ }, " 下载文件 ", 8, I),
113
+ t[1] || (t[1] = s("p", { class: "vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4" }, "提示:可以使用 Microsoft Excel 或 WPS 打开", -1))
114
+ ])
115
+ ])) : g("", !0),
116
+ l.value ? g("", !0) : (u(), c("div", {
117
+ key: 2,
118
+ ref_key: "containerRef",
119
+ ref: r,
120
+ class: "xlsx-spreadsheet-container vfp-w-full vfp-h-full",
121
+ style: z({ opacity: o.value ? 0 : 1 })
122
+ }, null, 4))
123
+ ]));
124
+ }
125
+ });
126
+ export {
127
+ X as default
128
+ };
129
+ //# sourceMappingURL=index-DTLDLOGO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DTLDLOGO.mjs","sources":["../../src/renderers/Xlsx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { FileSpreadsheet } from 'lucide-vue-next';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet sheetData: Record<string, unknown>[] | null = null;\nlet resizeObserver: ResizeObserver | null = null;\nlet resizeTimeout: number | null = null;\nlet lastDimensions = { width: 0, height: 0 };\n\nconst calculateDimensions = () => {\n if (!containerRef.value) return { width: 800, height: 600 };\n const rawWidth = containerRef.value.clientWidth;\n const rawHeight = containerRef.value.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n};\n\nconst mountSpreadsheet = () => {\n if (!containerRef.value || !sheetData) return;\n\n containerRef.value.innerHTML = '';\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.value, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetData as unknown as Record<string, unknown>);\n};\n\nconst loadExcel = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(props.url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) throw new Error(t.value('xlsx.not_found'));\n if (response.status === 403) throw new Error('无权限访问此文件');\n throw new Error(`文件加载失败 (${response.status})`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n const data = convertWorkbookToSpreadsheetData(workbook);\n\n sheetData = data as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n loading.value = false;\n } catch (err) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t.value('xlsx.parse_failed');\n if (err instanceof Error) errorMsg = err.message;\n error.value = errorMsg;\n loading.value = false;\n }\n};\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n let isInitialRender = true;\n\n resizeObserver = new ResizeObserver(() => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensions = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensions = newDimensions;\n\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n\n resizeTimeout = window.setTimeout(() => {\n if (sheetData) mountSpreadsheet();\n }, 500);\n });\n\n resizeObserver.observe(containerRef.value);\n\n setTimeout(() => {\n requestAnimationFrame(() => loadExcel());\n }, 100);\n});\n\nwatch(\n () => props.url,\n () => {\n loadExcel();\n }\n);\n\nonBeforeUnmount(() => {\n if (resizeObserver) resizeObserver.disconnect();\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n sheetData = null;\n if (containerRef.value) containerRef.value.innerHTML = '';\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full\">\n <div\n v-if=\"loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('xlsx.loading') }}</p>\n </div>\n </div>\n\n <div\n v-if=\"error && !loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4\">\n <div\n class=\"vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-green-500 vfp-via-emerald-500 vfp-to-teal-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl\"\n >\n <FileSpreadsheet class=\"vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary\" />\n </div>\n <p class=\"vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium\">\n {{ t('xlsx.load_failed') }}\n </p>\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6\">{{ error }}</p>\n <a\n :href=\"url\"\n download\n class=\"vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg\"\n >\n 下载文件\n </a>\n <p class=\"vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4\">提示:可以使用 Microsoft Excel 或 WPS 打开</p>\n </div>\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"containerRef\"\n class=\"xlsx-spreadsheet-container vfp-w-full vfp-h-full\"\n :style=\"{ opacity: loading ? 0 : 1 }\"\n />\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","loading","ref","error","containerRef","sheetData","resizeObserver","resizeTimeout","lastDimensions","calculateDimensions","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","Spreadsheet","loadExcel","response","arrayBuffer","workbook","ExcelJS","convertWorkbookToSpreadsheetData","err","errorMsg","onMounted","isInitialRender","newDimensions","widthDiff","heightDiff","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_hoisted_4","_toDisplayString","_unref","_hoisted_5","_hoisted_6","_hoisted_7","_createVNode","FileSpreadsheet","_hoisted_8","_hoisted_9","_hoisted_10","_cache"],"mappings":"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"}