@eternalheart/vue-file-preview 1.3.7 → 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.
Files changed (39) hide show
  1. package/lib/chunks/{index-BI0dSTSM.mjs → index-5Smm2vx0.mjs} +2 -2
  2. package/lib/chunks/{index-BI0dSTSM.mjs.map → index-5Smm2vx0.mjs.map} +1 -1
  3. package/lib/chunks/{index-yMb1JUC4.mjs → index-BCkcZs4y.mjs} +2 -2
  4. package/lib/chunks/{index-yMb1JUC4.mjs.map → index-BCkcZs4y.mjs.map} +1 -1
  5. package/lib/chunks/{index-DUUsS_T4.mjs → index-BM9FaQUl.mjs} +2 -2
  6. package/lib/chunks/{index-DUUsS_T4.mjs.map → index-BM9FaQUl.mjs.map} +1 -1
  7. package/lib/chunks/{index-CcJ5NmY1.mjs → index-BYzQg-jL.mjs} +2 -2
  8. package/lib/chunks/{index-CcJ5NmY1.mjs.map → index-BYzQg-jL.mjs.map} +1 -1
  9. package/lib/chunks/{index-DTLDLOGO.mjs → index-BoL1b2w-.mjs} +2 -2
  10. package/lib/chunks/{index-DTLDLOGO.mjs.map → index-BoL1b2w-.mjs.map} +1 -1
  11. package/lib/chunks/{index-S_kGRh6H.mjs → index-Bri7VeRx.mjs} +2 -2
  12. package/lib/chunks/{index-S_kGRh6H.mjs.map → index-Bri7VeRx.mjs.map} +1 -1
  13. package/lib/chunks/{index-DpAxU2JM.mjs → index-C324a7kV.mjs} +3 -3
  14. package/lib/chunks/{index-DpAxU2JM.mjs.map → index-C324a7kV.mjs.map} +1 -1
  15. package/lib/chunks/{index-kBPb_OKm.mjs → index-C7uOM7XL.mjs} +2 -2
  16. package/lib/chunks/{index-kBPb_OKm.mjs.map → index-C7uOM7XL.mjs.map} +1 -1
  17. package/lib/chunks/{index-Doy0FvQW.mjs → index-CTsscgqY.mjs} +2 -2
  18. package/lib/chunks/{index-Doy0FvQW.mjs.map → index-CTsscgqY.mjs.map} +1 -1
  19. package/lib/chunks/{index-CBCQs1ZC.mjs → index-Ch7AEfnk.mjs} +2 -2
  20. package/lib/chunks/{index-CBCQs1ZC.mjs.map → index-Ch7AEfnk.mjs.map} +1 -1
  21. package/lib/chunks/{index-ClxBxmPR.mjs → index-D9wf6m37.mjs} +2 -2
  22. package/lib/chunks/{index-ClxBxmPR.mjs.map → index-D9wf6m37.mjs.map} +1 -1
  23. package/lib/chunks/{index-BW61ZRev.mjs → index-DAEQe-RI.mjs} +2 -2
  24. package/lib/chunks/{index-BW61ZRev.mjs.map → index-DAEQe-RI.mjs.map} +1 -1
  25. package/lib/chunks/{index-DsznjwsH.mjs → index-DAo-7spn.mjs} +2 -2
  26. package/lib/chunks/{index-DsznjwsH.mjs.map → index-DAo-7spn.mjs.map} +1 -1
  27. package/lib/chunks/{index-C8ZF84WX.mjs → index-DXlcF1Dk.mjs} +2 -2
  28. package/lib/chunks/{index-C8ZF84WX.mjs.map → index-DXlcF1Dk.mjs.map} +1 -1
  29. package/lib/chunks/{index-SAfVQyNJ.mjs → index-ELyTQZeF.mjs} +3 -3
  30. package/lib/chunks/{index-SAfVQyNJ.mjs.map → index-ELyTQZeF.mjs.map} +1 -1
  31. package/lib/chunks/{index-D9lByoJw.mjs → index-cZn4ih-x.mjs} +2 -2
  32. package/lib/chunks/{index-D9lByoJw.mjs.map → index-cZn4ih-x.mjs.map} +1 -1
  33. package/lib/chunks/{index-CB0zCxJb.mjs → index-dzB4jd9b.mjs} +2 -2
  34. package/lib/chunks/{index-CB0zCxJb.mjs.map → index-dzB4jd9b.mjs.map} +1 -1
  35. package/lib/chunks/{index-CbKSdAt_.mjs → index-lHlugUBI.mjs} +2 -2
  36. package/lib/chunks/{index-CbKSdAt_.mjs.map → index-lHlugUBI.mjs.map} +1 -1
  37. package/lib/index.cjs +1 -1
  38. package/lib/index.mjs +1 -1
  39. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { defineComponent as k, ref as f, watch as x, openBlock as h, createElementBlock as g, createElementVNode as m, toDisplayString as $, createVNode as E, unref as L, h as t, inject as N, computed as _ } from "vue";
2
- import { u as C, h as O, L as S, M as J, b as R } from "./index-DpAxU2JM.mjs";
2
+ import { u as C, h as O, L as S, M as J, b as R } from "./index-C324a7kV.mjs";
3
3
  import { ChevronDown as A, ChevronRight as T } from "lucide-vue-next";
4
4
  const B = {
5
5
  key: 0,
@@ -136,4 +136,4 @@ const b = k({
136
136
  export {
137
137
  U as default
138
138
  };
139
- //# sourceMappingURL=index-kBPb_OKm.mjs.map
139
+ //# sourceMappingURL=index-C7uOM7XL.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-kBPb_OKm.mjs","sources":["../../src/renderers/Json/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\nimport { fetchTextUtf8 } 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 data = ref<unknown>(null);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\n\nconst loadJson = async () => {\n loading.value = true;\n error.value = null;\n try {\n const text = await fetchTextUtf8(props.url);\n data.value = JSON.parse(text);\n } catch (err) {\n console.error(err);\n error.value = t.value('json.load_failed');\n } finally {\n loading.value = false;\n }\n};\n\nwatch(() => props.url, loadJson, { immediate: true });\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 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 <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 <div v-else class=\"vfp-w-full vfp-h-full vfp-overflow-auto vfp-bg-code-bg vfp-py-3 vfp-pr-4\">\n <JsonNode :value=\"data\" :depth=\"0\" :default-expanded=\"true\" />\n </div>\n</template>\n\n<!-- 递归 JSON 节点组件 -->\n<script lang=\"ts\">\nimport { defineComponent, h, inject, computed, type PropType } from 'vue';\nimport { ChevronRight, ChevronDown } from 'lucide-vue-next';\nimport { createTranslator, type Translator } from '@eternalheart/file-preview-core';\nimport { LOCALE_KEY } from '../../i18n/localeKey';\nimport { useResolvedTheme, type ResolvedTheme } from '../../composables/useResolvedTheme';\n\nexport default defineComponent({ name: 'JsonRenderer' });\n\ninterface JsonColors {\n key: string;\n string: string;\n number: string;\n keyword: string;\n bracket: string; // { } [ ]\n colon: string; // :\n collapsed: string; // \"N items / N keys\" 折叠提示\n arrow: string; // 折叠箭头\n}\n\n// VSCode Dark Plus / GitHub Light 两套配色,与 shiki 的 dark-plus / github-light 主题保持一致\nconst DARK_COLORS: JsonColors = {\n key: '#9cdcfe',\n string: '#ce9178',\n number: '#b5cea8',\n keyword: '#569cd6',\n bracket: '#d4d4d4',\n colon: 'rgb(255 255 255 / 0.6)',\n collapsed: 'rgb(255 255 255 / 0.4)',\n arrow: 'rgb(255 255 255 / 0.5)',\n};\n\nconst LIGHT_COLORS: JsonColors = {\n key: '#005cc5',\n string: '#032f62',\n number: '#005cc5',\n keyword: '#d73a49',\n bracket: '#24292e',\n colon: 'rgb(23 23 23 / 0.6)',\n collapsed: 'rgb(23 23 23 / 0.45)',\n arrow: 'rgb(23 23 23 / 0.55)',\n};\n\nfunction pickColors(theme: ResolvedTheme): JsonColors {\n return theme === 'light' ? LIGHT_COLORS : DARK_COLORS;\n}\n\nfunction renderValue(value: unknown, colors: JsonColors) {\n if (value === null) return h('span', { class: 'json-null', style: { color: colors.keyword } }, 'null');\n if (value === undefined) return h('span', { class: 'json-null', style: { color: colors.keyword } }, 'undefined');\n if (typeof value === 'boolean') return h('span', { style: { color: colors.keyword } }, String(value));\n if (typeof value === 'number') return h('span', { style: { color: colors.number } }, String(value));\n if (typeof value === 'string') return h('span', { style: { color: colors.string } }, `\"${value}\"`);\n return h('span', { style: { color: colors.bracket } }, String(value));\n}\n\nfunction renderPrimitiveLine(\n keyName: string | undefined,\n value: unknown,\n indent: number,\n colors: JsonColors,\n override?: string,\n) {\n return h('div', { class: 'json-row', style: { paddingLeft: `${indent}px` } }, [\n h('span', { class: 'json-arrow-placeholder' }),\n keyName !== undefined\n ? h('span', { class: 'json-key', style: { color: colors.key } }, [\n `\"${keyName}\"`,\n h('span', { style: { color: colors.colon } }, ': '),\n ])\n : null,\n override\n ? h('span', { style: { color: colors.bracket } }, override)\n : renderValue(value, colors),\n ]);\n}\n\nconst JsonNode = defineComponent({\n name: 'JsonNode',\n props: {\n keyName: { type: String, default: undefined },\n value: { type: null as unknown as PropType<unknown>, required: true },\n depth: { type: Number, required: true },\n defaultExpanded: { type: Boolean, default: false },\n },\n setup(props) {\n const expanded = ref(props.defaultExpanded);\n const toggle = () => { expanded.value = !expanded.value; };\n const injected = inject(LOCALE_KEY, null);\n const tFunc = computed<Translator>(() => injected?.t.value ?? createTranslator({ locale: 'zh-CN' }));\n const resolvedTheme = useResolvedTheme();\n const colors = computed<JsonColors>(() => pickColors(resolvedTheme.value));\n return { expanded, toggle, tFunc, colors };\n },\n render() {\n const { keyName, value, depth, expanded, toggle, tFunc, colors } = this;\n const indent = depth * 20;\n\n // 基本类型\n if (value === null || value === undefined || typeof value !== 'object') {\n return renderPrimitiveLine(keyName, value, indent, colors);\n }\n\n const isArr = Array.isArray(value);\n const entries = isArr ? (value as unknown[]) : Object.entries(value as Record<string, unknown>);\n const count = entries.length;\n const open = isArr ? '[' : '{';\n const close = isArr ? ']' : '}';\n\n // 空对象/数组\n if (count === 0) {\n return renderPrimitiveLine(keyName, null, indent, colors, `${open}${close}`);\n }\n\n const children = [];\n\n // 折叠行\n children.push(\n h('div', {\n class: 'json-row json-toggle',\n style: { paddingLeft: `${indent}px` },\n onClick: toggle,\n }, [\n h('span', { class: 'json-arrow', style: { color: colors.arrow } }, [\n h(expanded ? ChevronDown : ChevronRight, { class: 'vfp-w-3.5 vfp-h-3.5' }),\n ]),\n keyName !== undefined\n ? h('span', { class: 'json-key', style: { color: colors.key } }, [\n `\"${keyName}\"`,\n h('span', { style: { color: colors.colon } }, ': '),\n ])\n : null,\n h('span', { style: { color: colors.bracket } }, open),\n !expanded\n ? h('span', { class: 'json-collapsed', style: { color: colors.collapsed } }, [\n isArr ? `${count} ${tFunc('json.items')}` : `${count} ${tFunc('json.keys')}`,\n h('span', { style: { color: colors.bracket } }, ` ${close}`),\n ])\n : null,\n ])\n );\n\n // 子节点\n if (expanded) {\n if (isArr) {\n (value as unknown[]).forEach((item, i) => {\n children.push(\n h(JsonNode, { key: i, value: item, depth: depth + 1, defaultExpanded: depth < 1 })\n );\n });\n } else {\n Object.entries(value as Record<string, unknown>).forEach(([k, v]) => {\n children.push(\n h(JsonNode, { key: k, keyName: k, value: v, depth: depth + 1, defaultExpanded: depth < 1 })\n );\n });\n }\n children.push(\n h('div', { class: 'json-row', style: { paddingLeft: `${indent + 20}px` } }, [\n h('span', { style: { color: colors.bracket } }, close),\n ])\n );\n }\n\n return h('div', null, children);\n },\n});\n</script>\n\n<style>\n.vfp-root .json-row {\n display: flex;\n align-items: flex-start;\n padding-top: 1px;\n padding-bottom: 1px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.875rem;\n line-height: 1.4;\n}\n.vfp-root .json-toggle {\n cursor: pointer;\n user-select: none;\n}\n.vfp-root .json-toggle:hover {\n background: var(--fp-surface-1);\n}\n.vfp-root .json-arrow {\n width: 16px;\n height: 20px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.vfp-root .json-arrow-placeholder {\n width: 16px;\n height: 20px;\n flex-shrink: 0;\n}\n.vfp-root .json-key {\n flex-shrink: 0;\n}\n.vfp-root .json-collapsed {\n margin-left: 4px;\n}\n.vfp-root .json-null {\n font-style: italic;\n}\n</style>\n"],"names":["__default__","defineComponent","DARK_COLORS","LIGHT_COLORS","pickColors","theme","renderValue","value","colors","h","renderPrimitiveLine","keyName","indent","override","JsonNode","props","expanded","ref","toggle","injected","inject","LOCALE_KEY","tFunc","computed","createTranslator","resolvedTheme","useResolvedTheme","depth","isArr","count","open","close","children","ChevronDown","ChevronRight","item","i","k","v","__props","t","useTranslator","data","loading","error","watch","text","fetchTextUtf8","err","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_createVNode","_unref"],"mappings":";;;;;;;;;;;;GAyDAA,IAAeC,EAAgB,EAAE,MAAM,gBAAgB,GAcjDC,IAA0B;AAAA,EAC9B,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW;AAAA,EACX,OAAO;AACT,GAEMC,IAA2B;AAAA,EAC/B,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW;AAAA,EACX,OAAO;AACT;AAEA,SAASC,EAAWC,GAAkC;AACpD,SAAOA,MAAU,UAAUF,IAAeD;AAC5C;AAEA,SAASI,EAAYC,GAAgBC,GAAoB;AACvD,SAAID,MAAU,OAAaE,EAAE,QAAQ,EAAE,OAAO,aAAa,OAAO,EAAE,OAAOD,EAAO,QAAA,EAAQ,GAAK,MAAM,IACjGD,MAAU,SAAkBE,EAAE,QAAQ,EAAE,OAAO,aAAa,OAAO,EAAE,OAAOD,EAAO,QAAA,EAAQ,GAAK,WAAW,IAC3G,OAAOD,KAAU,YAAkBE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,QAAA,EAAQ,GAAK,OAAOD,CAAK,CAAC,IAChG,OAAOA,KAAU,WAAiBE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,OAAA,EAAO,GAAK,OAAOD,CAAK,CAAC,IAC9F,OAAOA,KAAU,WAAiBE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,OAAA,EAAO,GAAK,IAAID,CAAK,GAAG,IAC1FE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,QAAA,EAAQ,GAAK,OAAOD,CAAK,CAAC;AACtE;AAEA,SAASG,EACPC,GACAJ,GACAK,GACAJ,GACAK,GACA;AACA,SAAOJ,EAAE,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,aAAa,GAAGG,CAAM,KAAA,EAAK,GAAK;AAAA,IAC5EH,EAAE,QAAQ,EAAE,OAAO,0BAA0B;AAAA,IAC7CE,MAAY,SACRF,EAAE,QAAQ,EAAE,OAAO,YAAY,OAAO,EAAE,OAAOD,EAAO,IAAA,KAAS;AAAA,MAC7D,IAAIG,CAAO;AAAA,MACXF,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,MAAA,EAAM,GAAK,IAAI;AAAA,IAAA,CACnD,IACD;AAAA,IACJK,IACIJ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,QAAA,KAAaK,CAAQ,IACxDP,EAAYC,GAAOC,CAAM;AAAA,EAAA,CAC9B;AACH;AAEA,MAAMM,IAAWb,EAAgB;AAAA,EAC/B,MAAM;AAAA,EACN,OAAO;AAAA,IACL,SAAS,EAAE,MAAM,QAAQ,SAAS,OAAA;AAAA,IAClC,OAAO,EAAE,MAAM,MAAsC,UAAU,GAAA;AAAA,IAC/D,OAAO,EAAE,MAAM,QAAQ,UAAU,GAAA;AAAA,IACjC,iBAAiB,EAAE,MAAM,SAAS,SAAS,GAAA;AAAA,EAAM;AAAA,EAEnD,MAAMc,GAAO;AACX,UAAMC,IAAWC,EAAIF,EAAM,eAAe,GACpCG,IAAS,MAAM;AAAE,MAAAF,EAAS,QAAQ,CAACA,EAAS;AAAA,IAAO,GACnDG,IAAWC,EAAOC,GAAY,IAAI,GAClCC,IAAQC,EAAqB,OAAMJ,KAAA,gBAAAA,EAAU,EAAE,UAASK,EAAiB,EAAE,QAAQ,QAAA,CAAS,CAAC,GAC7FC,IAAgBC,EAAA,GAChBlB,IAASe,EAAqB,MAAMnB,EAAWqB,EAAc,KAAK,CAAC;AACzE,WAAO,EAAE,UAAAT,GAAU,QAAAE,GAAQ,OAAAI,GAAO,QAAAd,EAAA;AAAA,EACpC;AAAA,EACA,SAAS;AACP,UAAM,EAAE,SAAAG,GAAS,OAAAJ,GAAO,OAAAoB,GAAO,UAAAX,GAAU,QAAAE,GAAQ,OAAAI,GAAO,QAAAd,MAAW,MAC7DI,IAASe,IAAQ;AAGvB,QAAIpB,KAAU,QAA+B,OAAOA,KAAU;AAC5D,aAAOG,EAAoBC,GAASJ,GAAOK,GAAQJ,CAAM;AAG3D,UAAMoB,IAAQ,MAAM,QAAQrB,CAAK,GAE3BsB,KADUD,IAASrB,IAAsB,OAAO,QAAQA,CAAgC,GACxE,QAChBuB,IAAOF,IAAQ,MAAM,KACrBG,IAAQH,IAAQ,MAAM;AAG5B,QAAIC,MAAU;AACZ,aAAOnB,EAAoBC,GAAS,MAAMC,GAAQJ,GAAQ,GAAGsB,CAAI,GAAGC,CAAK,EAAE;AAG7E,UAAMC,IAAW,CAAA;AAGjB,WAAAA,EAAS;AAAA,MACPvB,EAAE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO,EAAE,aAAa,GAAGG,CAAM,KAAA;AAAA,QAC/B,SAASM;AAAA,MAAA,GACR;AAAA,QACDT,EAAE,QAAQ,EAAE,OAAO,cAAc,OAAO,EAAE,OAAOD,EAAO,MAAA,KAAW;AAAA,UACjEC,EAAEO,IAAWiB,IAAcC,GAAc,EAAE,OAAO,uBAAuB;AAAA,QAAA,CAC1E;AAAA,QACDvB,MAAY,SACRF,EAAE,QAAQ,EAAE,OAAO,YAAY,OAAO,EAAE,OAAOD,EAAO,IAAA,KAAS;AAAA,UAC7D,IAAIG,CAAO;AAAA,UACXF,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,MAAA,EAAM,GAAK,IAAI;AAAA,QAAA,CACnD,IACD;AAAA,QACJC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,UAAQ,GAAKsB,CAAI;AAAA,QACnDd,IAKG,OAJAP,EAAE,QAAQ,EAAE,OAAO,kBAAkB,OAAO,EAAE,OAAOD,EAAO,UAAA,KAAe;AAAA,UACzEoB,IAAQ,GAAGC,CAAK,IAAIP,EAAM,YAAY,CAAC,KAAK,GAAGO,CAAK,IAAIP,EAAM,WAAW,CAAC;AAAA,UAC1Eb,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,UAAQ,GAAK,IAAIuB,CAAK,EAAE;AAAA,QAAA,CAC5D;AAAA,MACD,CACL;AAAA,IAAA,GAICf,MACEY,IACDrB,EAAoB,QAAQ,CAAC4B,GAAMC,MAAM;AACxC,MAAAJ,EAAS;AAAA,QACPvB,EAAEK,GAAU,EAAE,KAAKsB,GAAG,OAAOD,GAAM,OAAOR,IAAQ,GAAG,iBAAiBA,IAAQ,GAAG;AAAA,MAAA;AAAA,IAErF,CAAC,IAED,OAAO,QAAQpB,CAAgC,EAAE,QAAQ,CAAC,CAAC8B,GAAGC,CAAC,MAAM;AACnE,MAAAN,EAAS;AAAA,QACPvB,EAAEK,GAAU,EAAE,KAAKuB,GAAG,SAASA,GAAG,OAAOC,GAAG,OAAOX,IAAQ,GAAG,iBAAiBA,IAAQ,GAAG;AAAA,MAAA;AAAA,IAE9F,CAAC,GAEHK,EAAS;AAAA,MACPvB,EAAE,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,aAAa,GAAGG,IAAS,EAAE,KAAA,KAAU;AAAA,QAC1EH,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAOD,EAAO,QAAA,EAAQ,GAAKuB,CAAK;AAAA,MAAA,CACtD;AAAA,IAAA,IAIEtB,EAAE,OAAO,MAAMuB,CAAQ;AAAA,EAChC;AACF,CAAC;;;;;;;AAnND,UAAMjB,IAAQwB,GAKR,EAAE,GAAAC,EAAA,IAAMC,EAAA,GAERC,IAAOzB,EAAa,IAAI,GACxB0B,IAAU1B,EAAI,EAAI,GAClB2B,IAAQ3B,EAAmB,IAAI;AAgBrC,WAAA4B,EAAM,MAAM9B,EAAM,KAdD,YAAY;AAC3B,MAAA4B,EAAQ,QAAQ,IAChBC,EAAM,QAAQ;AACd,UAAI;AACF,cAAME,IAAO,MAAMC,EAAchC,EAAM,GAAG;AAC1C,QAAA2B,EAAK,QAAQ,KAAK,MAAMI,CAAI;AAAA,MAC9B,SAASE,GAAK;AACZ,gBAAQ,MAAMA,CAAG,GACjBJ,EAAM,QAAQJ,EAAE,MAAM,kBAAkB;AAAA,MAC1C,UAAA;AACE,QAAAG,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,GAEiC,EAAE,WAAW,IAAM,aAIvCA,EAAA,SAAXM,EAAA,GAAAC,EAEM,OAFNC,GAEM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,MADJC,EAAiI,OAAA,EAA5H,OAAM,oHAAA,GAAmH,MAAA,EAAA;AAAA,IAAA,QAGhHT,EAAA,SAAhBK,EAAA,GAAAC,EAIM,OAJNI,GAIM;AAAA,MAHJD,EAEM,OAFNE,GAEM;AAAA,QADJF,EAAsC,KAAtCG,GAAsCC,EAAZb,EAAA,KAAK,GAAA,CAAA;AAAA,MAAA;WAInCK,EAAA,GAAAC,EAEM,OAFNQ,GAEM;AAAA,MADJC,EAA8DC,EAAA9C,CAAA,GAAA;AAAA,QAAnD,OAAO4B,EAAA;AAAA,QAAO,OAAO;AAAA,QAAI,oBAAkB;AAAA,MAAA;;;;"}
1
+ {"version":3,"file":"index-C7uOM7XL.mjs","sources":["../../src/renderers/Json/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\nimport { fetchTextUtf8 } 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 data = ref<unknown>(null);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\n\nconst loadJson = async () => {\n loading.value = true;\n error.value = null;\n try {\n const text = await fetchTextUtf8(props.url);\n data.value = JSON.parse(text);\n } catch (err) {\n console.error(err);\n error.value = t.value('json.load_failed');\n } finally {\n loading.value = false;\n }\n};\n\nwatch(() => props.url, loadJson, { immediate: true });\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 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 <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 <div v-else class=\"vfp-w-full vfp-h-full vfp-overflow-auto vfp-bg-code-bg vfp-py-3 vfp-pr-4\">\n <JsonNode :value=\"data\" :depth=\"0\" :default-expanded=\"true\" />\n </div>\n</template>\n\n<!-- 递归 JSON 节点组件 -->\n<script lang=\"ts\">\nimport { defineComponent, h, inject, computed, type PropType } from 'vue';\nimport { ChevronRight, ChevronDown } from 'lucide-vue-next';\nimport { createTranslator, type Translator } from '@eternalheart/file-preview-core';\nimport { LOCALE_KEY } from '../../i18n/localeKey';\nimport { useResolvedTheme, type ResolvedTheme } from '../../composables/useResolvedTheme';\n\nexport default defineComponent({ name: 'JsonRenderer' });\n\ninterface JsonColors {\n key: string;\n string: string;\n number: string;\n keyword: string;\n bracket: string; // { } [ ]\n colon: string; // :\n collapsed: string; // \"N items / N keys\" 折叠提示\n arrow: string; // 折叠箭头\n}\n\n// VSCode Dark Plus / GitHub Light 两套配色,与 shiki 的 dark-plus / github-light 主题保持一致\nconst DARK_COLORS: JsonColors = {\n key: '#9cdcfe',\n string: '#ce9178',\n number: '#b5cea8',\n keyword: '#569cd6',\n bracket: '#d4d4d4',\n colon: 'rgb(255 255 255 / 0.6)',\n collapsed: 'rgb(255 255 255 / 0.4)',\n arrow: 'rgb(255 255 255 / 0.5)',\n};\n\nconst LIGHT_COLORS: JsonColors = {\n key: '#005cc5',\n string: '#032f62',\n number: '#005cc5',\n keyword: '#d73a49',\n bracket: '#24292e',\n colon: 'rgb(23 23 23 / 0.6)',\n collapsed: 'rgb(23 23 23 / 0.45)',\n arrow: 'rgb(23 23 23 / 0.55)',\n};\n\nfunction pickColors(theme: ResolvedTheme): JsonColors {\n return theme === 'light' ? LIGHT_COLORS : DARK_COLORS;\n}\n\nfunction renderValue(value: unknown, colors: JsonColors) {\n if (value === null) return h('span', { class: 'json-null', style: { color: colors.keyword } }, 'null');\n if (value === undefined) return h('span', { class: 'json-null', style: { color: colors.keyword } }, 'undefined');\n if (typeof value === 'boolean') return h('span', { style: { color: colors.keyword } }, String(value));\n if (typeof value === 'number') return h('span', { style: { color: colors.number } }, String(value));\n if (typeof value === 'string') return h('span', { style: { color: colors.string } }, `\"${value}\"`);\n return h('span', { style: { color: colors.bracket } }, String(value));\n}\n\nfunction renderPrimitiveLine(\n keyName: string | undefined,\n value: unknown,\n indent: number,\n colors: JsonColors,\n override?: string,\n) {\n return h('div', { class: 'json-row', style: { paddingLeft: `${indent}px` } }, [\n h('span', { class: 'json-arrow-placeholder' }),\n keyName !== undefined\n ? h('span', { class: 'json-key', style: { color: colors.key } }, [\n `\"${keyName}\"`,\n h('span', { style: { color: colors.colon } }, ': '),\n ])\n : null,\n override\n ? h('span', { style: { color: colors.bracket } }, override)\n : renderValue(value, colors),\n ]);\n}\n\nconst JsonNode = defineComponent({\n name: 'JsonNode',\n props: {\n keyName: { type: String, default: undefined },\n value: { type: null as unknown as PropType<unknown>, required: true },\n depth: { type: Number, required: true },\n defaultExpanded: { type: Boolean, default: false },\n },\n setup(props) {\n const expanded = ref(props.defaultExpanded);\n const toggle = () => { expanded.value = !expanded.value; };\n const injected = inject(LOCALE_KEY, null);\n const tFunc = computed<Translator>(() => injected?.t.value ?? createTranslator({ locale: 'zh-CN' }));\n const resolvedTheme = useResolvedTheme();\n const colors = computed<JsonColors>(() => pickColors(resolvedTheme.value));\n return { expanded, toggle, tFunc, colors };\n },\n render() {\n const { keyName, value, depth, expanded, toggle, tFunc, colors } = this;\n const indent = depth * 20;\n\n // 基本类型\n if (value === null || value === undefined || typeof value !== 'object') {\n return renderPrimitiveLine(keyName, value, indent, colors);\n }\n\n const isArr = Array.isArray(value);\n const entries = isArr ? (value as unknown[]) : Object.entries(value as Record<string, unknown>);\n const count = entries.length;\n const open = isArr ? '[' : '{';\n const close = isArr ? ']' : '}';\n\n // 空对象/数组\n if (count === 0) {\n return renderPrimitiveLine(keyName, null, indent, colors, `${open}${close}`);\n }\n\n const children = [];\n\n // 折叠行\n children.push(\n h('div', {\n class: 'json-row json-toggle',\n style: { paddingLeft: `${indent}px` },\n onClick: toggle,\n }, [\n h('span', { class: 'json-arrow', style: { color: colors.arrow } }, [\n h(expanded ? ChevronDown : ChevronRight, { class: 'vfp-w-3.5 vfp-h-3.5' }),\n ]),\n keyName !== undefined\n ? h('span', { class: 'json-key', style: { color: colors.key } }, [\n `\"${keyName}\"`,\n h('span', { style: { color: colors.colon } }, ': '),\n ])\n : null,\n h('span', { style: { color: colors.bracket } }, open),\n !expanded\n ? h('span', { class: 'json-collapsed', style: { color: colors.collapsed } }, [\n isArr ? `${count} ${tFunc('json.items')}` : `${count} ${tFunc('json.keys')}`,\n h('span', { style: { color: colors.bracket } }, ` ${close}`),\n ])\n : null,\n ])\n );\n\n // 子节点\n if (expanded) {\n if (isArr) {\n (value as unknown[]).forEach((item, i) => {\n children.push(\n h(JsonNode, { key: i, value: item, depth: depth + 1, defaultExpanded: depth < 1 })\n );\n });\n } else {\n Object.entries(value as Record<string, unknown>).forEach(([k, v]) => {\n children.push(\n h(JsonNode, { key: k, keyName: k, value: v, depth: depth + 1, defaultExpanded: depth < 1 })\n );\n });\n }\n children.push(\n h('div', { class: 'json-row', style: { paddingLeft: `${indent + 20}px` } }, [\n h('span', { style: { color: colors.bracket } }, close),\n ])\n );\n }\n\n return h('div', null, children);\n },\n});\n</script>\n\n<style>\n.vfp-root .json-row {\n display: flex;\n align-items: flex-start;\n padding-top: 1px;\n padding-bottom: 1px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.875rem;\n line-height: 1.4;\n}\n.vfp-root .json-toggle {\n cursor: pointer;\n user-select: none;\n}\n.vfp-root .json-toggle:hover {\n background: var(--fp-surface-1);\n}\n.vfp-root .json-arrow {\n width: 16px;\n height: 20px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.vfp-root .json-arrow-placeholder {\n width: 16px;\n height: 20px;\n flex-shrink: 0;\n}\n.vfp-root .json-key {\n flex-shrink: 0;\n}\n.vfp-root .json-collapsed {\n margin-left: 4px;\n}\n.vfp-root .json-null {\n font-style: italic;\n}\n</style>\n"],"names":["__default__","defineComponent","DARK_COLORS","LIGHT_COLORS","pickColors","theme","renderValue","value","colors","h","renderPrimitiveLine","keyName","indent","override","JsonNode","props","expanded","ref","toggle","injected","inject","LOCALE_KEY","tFunc","computed","createTranslator","resolvedTheme","useResolvedTheme","depth","isArr","count","open","close","children","ChevronDown","ChevronRight","item","i","k","v","__props","t","useTranslator","data","loading","error","watch","text","fetchTextUtf8","err","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_createVNode","_unref"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { defineComponent as $, computed as G, ref as c, watch as _, nextTick as
2
2
  import P from "markdown-it";
3
3
  import D from "@traptitech/markdown-it-katex";
4
4
  import { codeToHtml as E } from "shiki";
5
- import { u as K, b as O, h as R, _ as N } from "./index-DpAxU2JM.mjs";
5
+ import { u as K, b as O, h as R, _ as N } from "./index-C324a7kV.mjs";
6
6
  import "katex/dist/katex.min.css";
7
7
  const Y = {
8
8
  key: 0,
@@ -133,4 +133,4 @@ const Y = {
133
133
  export {
134
134
  ie as default
135
135
  };
136
- //# sourceMappingURL=index-Doy0FvQW.mjs.map
136
+ //# sourceMappingURL=index-CTsscgqY.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-Doy0FvQW.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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"}
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":";;;;;;;;;;;;;;;;;;;;;;qFAkGMA,IAAc,0TACdC,IAAc,0TACdC,KAAe,0NACfC,KAAe;;;;;;;AA3FrB,UAAMC,IAAQC,GAKR,EAAE,GAAAC,EAAA,IAAMC,EAAA,GACRC,IAAgBC,EAAA,GAChBC,IAAaC,EAAS,MAAOH,EAAc,UAAU,UAAU,iBAAiB,aAAc,GAE9FI,IAAUC,EAAI,EAAE,GAChBC,IAAOD,EAAI,EAAE,GACbE,IAAoBF,EAAI,EAAE,GAC1BG,IAAUH,EAAI,EAAI,GAClBI,IAAQJ,EAAmB,IAAI,GAC/BK,IAAeL,EAA2B,IAAI,GAG9CM,IAAK,IAAIC,EAAW;AAAA,MACxB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,MACb,QAAQ;AAAA,IAAA,CACT;AACD,IAAAD,EAAG,IAAIE,CAAe,GAGtBF,EAAG,SAAS,MAAM,QAAQ,CAACG,GAAQC,MAAQ;AACzC,YAAMC,IAAQF,EAAOC,CAAG,GAClBE,IAAOD,EAAM,OAAOA,EAAM,KAAK,SAAS,IACxCE,IAAOF,EAAM;AAEnB,aAAKC,IAME;AAAA;AAAA,cAEKA,CAAI;AAAA;AAAA,6CAE2BA,CAAI,WAAWN,EAAG,MAAM,WAAWO,CAAI,CAAC;AAAA,YAT1E;AAAA,qCAC0BP,EAAG,MAAM,WAAWO,CAAI,CAAC;AAAA;AAAA,IAU9D,GAGAP,EAAG,SAAS,MAAM,aAAa,CAACG,GAAQC,MAAQ;AAC9C,YAAMG,IAAOJ,EAAOC,CAAG,EAAE;AACzB,aAAO;AAAA,qCAC4BJ,EAAG,MAAM,WAAWO,CAAI,CAAC;AAAA;AAAA,IAE9D;AAGA,UAAMC,IACJR,EAAG,SAAS,MAAM,eACjB,CAACG,GAAQC,GAAKK,GAASC,GAAMC,MAASA,EAAK,YAAYR,GAAQC,GAAKK,CAAO;AAC9E,IAAAT,EAAG,SAAS,MAAM,aAAa,CAACG,GAAQC,GAAKK,GAASG,GAAKD,MAClD,gCAAgCH,EAAiBL,GAAQC,GAAKK,GAASG,GAAKD,CAAI;AAEzF,UAAME,IACJb,EAAG,SAAS,MAAM,gBACjB,CAACG,GAAQC,GAAKK,GAASC,GAAMC,MAASA,EAAK,YAAYR,GAAQC,GAAKK,CAAO;AAC9E,IAAAT,EAAG,SAAS,MAAM,cAAc,CAACG,GAAQC,GAAKK,GAASG,GAAKD,MACnDE,EAAkBV,GAAQC,GAAKK,GAASG,GAAKD,CAAI,IAAI;AAG9D,UAAMG,IAAe,YAAY;AAC/B,MAAAjB,EAAQ,QAAQ,IAChBC,EAAM,QAAQ;AACd,UAAI;AACF,cAAMiB,IAAO,MAAMC,EAAc/B,EAAM,GAAG;AAC1C,QAAAQ,EAAQ,QAAQsB,GAChBpB,EAAK,QAAQK,EAAG,OAAOe,CAAI,GAC3BlB,EAAQ,QAAQ;AAEhB,YAAI;AACF,UAAAD,EAAkB,QAAQ,MAAMqB,EAAWF,GAAM,EAAE,MAAM,YAAY,OAAOxB,EAAW,OAAO;AAAA,QAChG,QAAQ;AACN,UAAAK,EAAkB,QAAQ;AAAA,QAC5B;AAAA,MACF,SAASsB,GAAK;AACZ,gBAAQ,MAAMA,CAAG,GACjBpB,EAAM,QAAQX,EAAE,MAAM,sBAAsB,GAC5CU,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,GAOMsB,IAAmB,CAACZ,GAAca,MAAuC;AAC7E,YAAMC,IAAM,SAAS,cAAc,QAAQ;AAC3C,aAAAA,EAAI,OAAO,UACXA,EAAI,YAAYD,IAAS,kBAAkB,iCAC3CC,EAAI,QAAQlC,EAAE,MAAM,oBAAoB,GACxCkC,EAAI,YAAYD,IAASvC,IAAcC,GACvCuC,EAAI,iBAAiB,SAAS,OAAOC,MAAM;AACzC,QAAAA,EAAE,gBAAA;AACF,YAAI;AACF,gBAAM,UAAU,UAAU,UAAUf,CAAI;AAAA,QAC1C,QAAQ;AACN,gBAAMgB,IAAK,SAAS,cAAc,UAAU;AAC5C,UAAAA,EAAG,QAAQhB,GACX,SAAS,KAAK,YAAYgB,CAAE,GAC5BA,EAAG,OAAA,GACH,SAAS,YAAY,MAAM,GAC3B,SAAS,KAAK,YAAYA,CAAE;AAAA,QAC9B;AACA,QAAAF,EAAI,YAAYD,IAASrC,KAAeC,IACxCqC,EAAI,QAAQlC,EAAE,MAAM,iBAAiB,GACrC,WAAW,MAAM;AACf,UAAAkC,EAAI,YAAYD,IAASvC,IAAcC,GACvCuC,EAAI,QAAQlC,EAAE,MAAM,oBAAoB;AAAA,QAC1C,GAAG,GAAI;AAAA,MACT,CAAC,GACMkC;AAAA,IACT,GAEMG,IAAgC,YAAY;;AAChD,UAAI,CAACzB,EAAa,MAAO;AAGzB,YAAM0B,IAAU1B,EAAa,MAAM,iBAAiC,6BAA6B;AACjG,iBAAW2B,KAAOD,GAAS;AACzB,cAAME,IAAOD,EAAI,aAAa,WAAW,KAAK,QACxCnB,MAAOqB,IAAAF,EAAI,cAAc,MAAM,MAAxB,gBAAAE,EAA2B,gBAAe;AACvD,YAAI;AACF,gBAAMC,IAAc,MAAMZ,EAAWV,GAAM,EAAE,MAAAoB,GAAM,OAAOpC,EAAW,OAAO,GACtEuC,IAAM,SAAS,cAAc,KAAK;AACxC,UAAAA,EAAI,YAAYD;AAChB,gBAAME,IAASD,EAAI;AACnB,UAAIC,KAAQL,EAAI,YAAYK,CAAM;AAAA,QACpC,QAAQ;AACN,UAAAL,EAAI,MAAM,kBAAkB,qBAC5BA,EAAI,gBAAgB,oBAAoB;AAAA,QAC1C;AAAA,MACF;AAGA,YAAMM,IAAWjC,EAAa,MAAM,iBAA8B,qBAAqB;AACvF,iBAAWkC,KAAWD,GAAU;AAC9B,YAAIC,EAAQ,cAAc,gBAAgB,EAAG;AAC7C,cAAMC,IAASD,EAAQ,cAAc,oBAAoB,GACnDP,IAAMO,EAAQ,cAAc,KAAK,GACjC1B,MAAO4B,IAAAT,KAAA,gBAAAA,EAAK,cAAc,YAAnB,gBAAAS,EAA4B,iBAAeT,KAAA,gBAAAA,EAAK,gBAAe;AAC5E,QAAIQ,IAEFA,EAAO,YAAYf,EAAiBZ,GAAM,EAAI,CAAC,IAG/C0B,EAAQ,YAAYd,EAAiBZ,GAAM,EAAK,CAAC;AAAA,MAErD;AAAA,IACF;AAEA,WAAA6B,EAAM,MAAMnD,EAAM,KAAK6B,GAAc,EAAE,WAAW,IAAM,GAExDsB,EAAMzC,GAAM,YAAY;AACtB,MAAKA,EAAK,UACV,MAAM0C,EAAA,GACNb,EAAA;AAAA,IACF,CAAC,GAGDY,EAAM7C,GAAY,MAAM;AACtB,MAAIE,EAAQ,SAAOqB,EAAA;AAAA,IACrB,CAAC,aAIYjB,EAAA,SAAXyC,EAAA,GAAAC,EAIM,OAJNC,GAIM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,MAHJC,EAEE,OAAA,EADA,OAAM,oHAAA,GAAmH,MAAA,EAAA;AAAA,IAAA,QAI7G5C,EAAA,SAAhBwC,EAAA,GAAAC,EAIM,OAJNI,GAIM;AAAA,MAHJD,EAEM,OAFNE,GAEM;AAAA,QADJF,EAAsC,KAAtCG,GAAsCC,EAAZhD,EAAA,KAAK,GAAA,CAAA;AAAA,MAAA;UAKnBZ,EAAA,aAAQ,YAAxBoD,EAAA,GAAAC,EAOM,OAPNQ,GAOM;AAAA,MALKnD,EAAA,cAIT2C,EAA+D,OAAA;AAAA;QAAnD,OAAM;AAAA,QAAgB,WAAQ3C,EAAA;AAAA,MAAA,wBAL1C2C,EAIC,OAJDS,GAICF,EADKrD,EAAA,KAAO,GAAA,CAAA;AAAA,WAMf6C,EAAA,GAAAC,EAIM,OAJNU,GAIM;AAAA,MAHJP,EAEM,OAFNQ,GAEM;AAAA,QADJR,EAA8D,OAAA;AAAA,mBAArD;AAAA,UAAJ,KAAI3C;AAAA,UAAe,OAAM;AAAA,UAAgB,WAAQJ,EAAA;AAAA,QAAA;;;;;"}
@@ -1,5 +1,5 @@
1
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-DpAxU2JM.mjs";
2
+ import { u as S, c as V, x as d, h as z, _ as A } from "./index-C324a7kV.mjs";
3
3
  const D = {
4
4
  key: 0,
5
5
  class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-bg-[#0f0f12]"
@@ -113,4 +113,4 @@ const D = {
113
113
  export {
114
114
  lt as default
115
115
  };
116
- //# sourceMappingURL=index-CBCQs1ZC.mjs.map
116
+ //# sourceMappingURL=index-Ch7AEfnk.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-CBCQs1ZC.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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"}
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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"}
@@ -1,7 +1,7 @@
1
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
2
  import ae from "@likecoin/epub-ts";
3
3
  import { X as ne } from "lucide-vue-next";
4
- import { u as le } from "./index-DpAxU2JM.mjs";
4
+ import { u as le } from "./index-C324a7kV.mjs";
5
5
  const se = {
6
6
  class: "vfp-relative vfp-w-full vfp-h-full vfp-flex vfp-justify-center vfp-overflow-hidden",
7
7
  style: { background: "#f5f5f0" }
@@ -246,4 +246,4 @@ const se = {
246
246
  export {
247
247
  we as default
248
248
  };
249
- //# sourceMappingURL=index-ClxBxmPR.mjs.map
249
+ //# sourceMappingURL=index-D9wf6m37.mjs.map
@@ -1 +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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"}
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":";;;;;;;;;;;;;;;;;;;yHAsCMA,KAAW;;;;;;;AAEjB,UAAMC,IAAQC,GAER,EAAE,GAAAC,EAAA,IAAMC,GAAA,GAERC,IAAOC,GAKPC,IAAYC,EAA2B,IAAI,GAC3CC,IAAUD,EAAI,EAAI,GAClBE,IAAQF,EAAmB,IAAI,GAC/BG,IAAcH,EAAI,EAAK,GACvBI,IAAMJ,EAAe,EAAE,GACvBK,IAAUL,EAAI,EAAK,GACnBM,IAAgBN,EAAI,EAAE;AAE5B,QAAIO,IAAwB,MACxBC,IAAkC,MAClCC,IAAiB,GACjBC,IAAyB;AAE7B,UAAMC,IAAU,MAAM;;AACpB,UAAI;AAAE,SAAAC,IAAAJ,KAAA,gBAAAA,EAAW,YAAX,QAAAI,EAAA,KAAAJ;AAAA,MAAwB,QAAQ;AAAA,MAAe;AACrD,UAAI;AAAE,QAAAD,KAAA,QAAAA,EAAM;AAAA,MAAW,QAAQ;AAAA,MAAe;AAC9C,MAAAC,IAAY,MACZD,IAAO,MACPE,IAAiB,GACjBC,IAAU;AAAA,IACZ,GAEMG,IAAW,MAAM;AAAE,MAAAL,KAAA,QAAAA,EAAW;AAAA,IAAQ,GACtCM,IAAW,MAAM;AAAE,MAAAN,KAAA,QAAAA,EAAW;AAAA,IAAQ,GACtCO,IAAkB,MAAM;AAC5B,MAAAZ,EAAY,QAAQ,CAACA,EAAY,OACjCN,EAAK,mBAAmBM,EAAY,KAAK,GACzC,WAAW,MAAM;AACf,QAAIJ,EAAU,SAASS,MACrBA,EAAU,OAAOT,EAAU,MAAM,aAAaA,EAAU,MAAM,YAAY,GACtEW,KACFF,EAAU,QAAQE,CAAO,GAG3BM,EAAA;AAAA,MAEJ,GAAG,GAAG;AAAA,IACR,GACMC,IAAY,MAAM;AAAE,MAAAZ,EAAQ,QAAQ,CAACA,EAAQ;AAAA,IAAO,GACpDa,IAAiB,CAACC,MAAiB;AACvC,MAAAb,EAAc,QAAQa,GACtBX,KAAA,QAAAA,EAAW,QAAQW,IACnBd,EAAQ,QAAQ;AAAA,IAClB,GAEMe,IAAW,CAACD,MACTA,MAASb,EAAc;AAGhC,IAAAe,EAAa,EAAE,UAAAR,GAAU,UAAAC,GAAU,iBAAAC,GAAiB,WAAAE,GAAW;AAE/D,UAAMK,IAAW,YAAY;AAC3B,UAAKvB,EAAU,OAEf;AAAA,QAAAE,EAAQ,QAAQ,IAChBC,EAAM,QAAQ,MACdE,EAAI,QAAQ,CAAA,GACZC,EAAQ,QAAQ,IAChBN,EAAU,MAAM,YAAY,IAC5BY,EAAA;AAEA,YAAI;AACF,cAAIY,IAAkC9B,EAAM;AAC5C,UAAIA,EAAM,IAAI,WAAW,OAAO,MAE9B8B,IAAY,OADC,MAAM,MAAM9B,EAAM,GAAG,GACX,YAAA,IAGzBc,IAAOiB,GAAKD,CAAS,GAErBf,IAAYD,EAAK,SAASR,EAAU,OAAO;AAAA,YACzC,SAAS;AAAA,YACT,MAAM;AAAA,YACN,OAAO;AAAA,YACP,QAAQ;AAAA,UAAA,CACT,GAEDS,EAAU,OAAO,SAAS,WAAW;AAAA,YACnC,MAAM;AAAA,cACJ,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,eAAe;AAAA,cACf,aAAa;AAAA,cACb,eAAe;AAAA,cACf,SAAS;AAAA,cACT,aAAa;AAAA,cACb,cAAc;AAAA,cACd,cAAc;AAAA,cACd,iBAAiB;AAAA,YAAA;AAAA,YAEnB,GAAG,EAAE,eAAe,kBAAkB,QAAQ,qBAAA;AAAA,YAC9C,IAAI,EAAE,cAAc,qBAAqB,QAAQ,yBAAA;AAAA,YACjD,IAAI,EAAE,QAAQ,2BAAA;AAAA,YACd,IAAI,EAAE,QAAQ,yBAAA;AAAA,YACd,KAAK,EAAE,aAAa,mBAAmB,QAAQ,kBAAA;AAAA,YAC/C,GAAG,EAAE,OAAO,sBAAsB,mBAAmB,kBAAA;AAAA,UAAkB,CACxE,GACDA,EAAU,OAAO,OAAO,SAAS,GAEjC,MAAMD,EAAK,OAGXA,EAAK,UAAU,SAAS,IAAI,EAAE,KAAK,MAAM;;AACvC,gBAAI,CAACA,EAAM;AACX,YAAAE,IAAiBF,EAAK,UAAU,OAAA;AAChC,kBAAMkB,IAAMjB,KAAA,gBAAAA,EAAW,mBACjBkB,MAAMd,IAAAa,KAAA,gBAAAA,EAAK,UAAL,gBAAAb,EAAY,aAAY;AACpC,YAAAf,EAAK,iBAAiB6B,IAAM,GAAGjB,CAAc;AAAA,UAC/C,CAAC,EAAE,MAAM,MAAM;AAAA,UAAe,CAAC;AAE/B,gBAAMkB,IAAM,MAAMpB,EAAK,OAAO;AAC9B,UAAI,MAAM,QAAQoB,KAAA,gBAAAA,EAAK,GAAG,MACxBvB,EAAI,QAAQuB,EAAI,MAGlB,MAAMnB,EAAU,QAAA,GAEhBP,EAAQ,QAAQ,IAChBJ,EAAK,iBAAiB,GAAGY,KAAkB,CAAC,GAE5CD,EAAU,GAAG,aAAa,CAACoB,MAAsB;;AAC/C,kBAAMH,IAAMG;AAIZ,iBAHIhB,IAAAa,KAAA,gBAAAA,EAAK,UAAL,QAAAb,EAAY,QACdF,IAAUe,EAAI,MAAM,OAElBI,IAAAJ,KAAA,gBAAAA,EAAK,UAAL,QAAAI,EAAY,MAAM;AAEpB,oBAAMC,IAAYL,EAAI,MAAM,MACtBM,IAAoB,CAAA,GACpBC,IAAU,CAACC,MAAqB;AACpC,2BAAWC,KAAQD,GAAO;AACxB,wBAAME,IAAOD,EAAK,KAAK,MAAM,GAAG,EAAE,CAAC;AACnC,kBAAIC,MAASL,MAAcK,KAAQL,EAAU,SAAS,MAAMK,CAAI,KAAKL,EAAU,SAASK,CAAI,MAC1FJ,EAAQ,KAAKG,EAAK,IAAI,GAEpBA,EAAK,YAAUF,EAAQE,EAAK,QAAQ;AAAA,gBAC1C;AAAA,cACF;AACA,cAAAF,EAAQ5B,EAAI,KAAK,GACb2B,EAAQ,WAAW,MACrBzB,EAAc,QAAQyB,EAAQ,CAAC;AAAA,YAGnC;AACA,kBAAML,KAAMU,IAAAX,KAAA,gBAAAA,EAAK,UAAL,gBAAAW,EAAY;AACxB,YAAI,OAAOV,KAAQ,YAAYjB,IAAiB,KAC9CZ,EAAK,iBAAiB6B,IAAM,GAAGjB,CAAc;AAAA,UAEjD,CAAC;AAAA,QACH,SAAS4B,GAAK;AACZ,kBAAQ,MAAM,cAAcA,CAAG,GAC/BnC,EAAM,QAAQP,EAAE,MAAM,kBAAkB,GACxCM,EAAQ,QAAQ;AAAA,QAClB;AAAA;AAAA,IACF,GAEMqC,IAAW,MAAM;AACrB,MAAI,CAACvC,EAAU,SAAS,CAACS,KACzBA,EAAU,OAAOT,EAAU,MAAM,aAAaA,EAAU,MAAM,YAAY;AAAA,IAC5E;AAGA,QAAIwC,IAAkC;AACtC,UAAMC,IAAoB,MAAM;;AAC9B,UAAI,CAACD,EAAiB;AACtB,YAAME,IAAKF;AACX,UAAIE,EAAG,YAAYA,EAAG,gBAAgBA,EAAG,eAAe;AACtD,YAAI;AACF,gBAAMC,IAAOlC,KAAA,gBAAAA,EAAiG;AAE9G,WAAAI,IAAA8B,KAAA,gBAAAA,EAAK,UAAL,QAAA9B,EAAA,KAAA8B,GAAa,KAAK;AAAA,QACpB,QAAQ;AAAA,QAAe;AAAA,IAE3B,GAEM1B,IAAyB,MAAM;AAEnC,MAAIuB,MACFA,EAAgB,oBAAoB,UAAUC,CAAiB,GAC/DD,IAAkB;AAEpB,YAAMI,IAAY,MAAM;;AACtB,QAAAJ,MAAkB3B,IAAAb,EAAU,UAAV,gBAAAa,EAAiB,cAAc,uBAAsB,MACnE2B,IACFA,EAAgB,iBAAiB,UAAUC,GAAmB,EAAE,SAAS,IAAM,IAE/E,sBAAsBG,CAAS;AAAA,MAEnC;AACA,4BAAsBA,CAAS;AAAA,IACjC;AAEA,WAAAC,GAAU,MAAM;AACd,MAAAtB,EAAA,GACA,OAAO,iBAAiB,UAAUgB,CAAQ,GAC1CtB,EAAA;AAAA,IACF,CAAC,GAED6B,GAAM,MAAMpD,EAAM,KAAK,MAAM6B,GAAU,GAEvCwB,GAAgB,MAAM;AACpB,aAAO,oBAAoB,UAAUR,CAAQ,GAC7CC,KAAA,QAAAA,EAAiB,oBAAoB,UAAUC,IAC/C7B,EAAA;AAAA,IACF,CAAC,cAICoC,EAAA,GAAAC,EAkGM,OAlGNC,IAkGM;AAAA,MAjGO/C,EAAA,SAAX6C,EAAA,GAAAC,EAEM,OAFNE,IAEM;AAAA,QADJC,EAAsC,KAAtCC,IAAsCC,EAAZnD,EAAA,KAAK,GAAA,CAAA;AAAA,MAAA;MAIzBD,EAAA,UAAYC,EAAA,SADpB6C,KAAAC,EAKM,OALNM,IAKM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,QADJJ,EAAiI,OAAA,EAA5H,OAAM,oHAAA,GAAmH,MAAA,EAAA;AAAA,MAAA;MAKxH/C,EAAA,MAAI,SAAM,UADlB4C,EAuEM,OAAA;AAAA;QArEJ,OAAM;AAAA,QACL,OAAKQ,EAAA,EAAA,SAAanD,EAAA,QAAO,IAAA,GAAA,eAAyBA,EAAA,QAAO,SAAA,QAAA,YAAA,gBAAA;AAAA,MAAA;QAE1D8C,EA4DM,OAAA;AAAA,UA3DJ,OAAM;AAAA,UACL,OAAKK,EAAA;AAAA;;;;;uBAA0PnD,EAAA,QAAO,kBAAA;AAAA;;;UAUvQ8C,EAKM,OALNM,IAKM;AAAA,YAJJN,EAA2F,QAA3FO,IAA2FL,EAA1BM,EAAAhE,CAAA,EAAC,aAAA,CAAA,GAAA,CAAA;AAAA,YAClEwD,EAES,UAAA;AAAA,cAFD,OAAA,EAAA,OAAA,yBAAA,YAAA,QAAA,QAAA,QAAA,QAAA,WAAA,SAAA,MAAA;AAAA,cAAqG,gCAAO9C,EAAA,QAAO;AAAA,YAAA;cACzHuD,GAAuCD,EAAAE,EAAA,GAAA,EAApC,OAAA,EAAA,OAAA,QAAA,QAAA,SAAA,CAAiC;AAAA,YAAA;;UAGxCV,EAyCM,OAzCNW,IAyCM;AAAA,aAxCJf,EAAA,EAAA,GAAAC,EAuCWe,GAAA,MAAAC,EAvCmB5D,EAAA,OAAG,CAAf8B,GAAM+B;sBAAoB/B,EAAK,IAAI,IAAI+B,CAAC;AAAA,YAAA;cACxDd,EAgBS,UAAA;AAAA,gBAfN,OAAKK,EAAA;AAAA;;;;yBAAoHpC,EAASc,EAAK,IAAI,IAAA,UAAA;AAAA,8BAAmEd,EAASc,EAAK,IAAI,IAAA,QAAA;AAAA,8BAA+Cd,EAASc,EAAK,IAAI,IAAA,2BAAA;AAAA;;;;;;;;;gBASjS,OAAOA,EAAK;AAAA,gBACZ,SAAK,CAAAgC,MAAEhD,EAAegB,EAAK,IAAI;AAAA,gBAC/B,cAAU,CAAAgC,MAAA,CAAG9C,EAASc,EAAK,IAAI,MAAOgC,EAAO,OAAuB,MAAM,aAAU;AAAA,gBACpF,cAAU,CAAAA,MAAA,CAAG9C,EAASc,EAAK,IAAI,MAAOgC,EAAO,OAAuB,MAAM,aAAU;AAAA,cAAA,KAElFhC,EAAK,MAAM,MAAI,GAAA,IAAAiC,EAAA;AAAA,cAEJjC,EAAK,YAAYA,EAAK,SAAS,SAAM,KACnDa,EAAA,EAAA,GAAAC,EAkBSe,iBAjBY7B,EAAK,UAAQ,CAAxBkC,GAAKC,YADfrB,EAkBS,UAAA;AAAA,gBAhBN,KAAG,GAAKoB,EAAI,IAAI,IAAIC,CAAC;AAAA,gBACrB,OAAKb,EAAA;AAAA;;;;yBAAiIpC,EAASgD,EAAI,IAAI,IAAA,UAAA;AAAA,8BAAqEhD,EAASgD,EAAI,IAAI,IAAA,QAAA;AAAA,8BAAiDhD,EAASgD,EAAI,IAAI,IAAA,2BAAA;AAAA;;;;;;;;;gBAS/S,OAAOA,EAAI;AAAA,gBACX,SAAK,CAAAF,MAAEhD,EAAekD,EAAI,IAAI;AAAA,gBAC9B,cAAU,CAAAF,MAAA,CAAG9C,EAASgD,EAAI,IAAI,MAAOF,EAAO,OAAuB,MAAM,aAAU;AAAA,gBACnF,cAAU,CAAAA,MAAA,CAAG9C,EAASgD,EAAI,IAAI,MAAOF,EAAO,OAAuB,MAAM,aAAU;AAAA,cAAA,KAEjFE,EAAI,MAAM,MAAI,GAAA,IAAAE,EAAA;;;;QAM3BnB,EAIE,OAAA;AAAA,UAHA,OAAM;AAAA,UACL,uBAAqB9C,EAAA,QAAO,oBAAA,eAAA,YAAA,mBAAA;AAAA,UAC5B,gCAAOA,EAAA,QAAO;AAAA,QAAA;;MAKVH,EAAA,0BADT8C,EAWE,OAAA;AAAA;iBATI;AAAA,QAAJ,KAAIjD;AAAA,QACJ,OAAM;AAAA,QACL,OAAKyD,EAAA;AAAA,UAAmB,OAAArD,EAAA,oBAA0BX,EAAQ;AAAA;;;;;;;;;"}
@@ -2,7 +2,7 @@ import { defineComponent as T, ref as x, onMounted as D, watch as z, onBeforeUnm
2
2
  import { FileSpreadsheet as C } from "lucide-vue-next";
3
3
  import H from "x-data-spreadsheet";
4
4
  /* empty css */
5
- import { u as R, h as V, g as W, m as j, k as B } from "./index-DpAxU2JM.mjs";
5
+ import { u as R, h as V, g as W, m as j, k as B } from "./index-C324a7kV.mjs";
6
6
  const E = { class: "vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full" }, F = {
7
7
  key: 0,
8
8
  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"
@@ -108,4 +108,4 @@ const E = { class: "vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-fu
108
108
  export {
109
109
  Y as default
110
110
  };
111
- //# sourceMappingURL=index-BW61ZRev.mjs.map
111
+ //# sourceMappingURL=index-DAEQe-RI.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BW61ZRev.mjs","sources":["../../src/renderers/Csv/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { FileSpreadsheet } from 'lucide-vue-next';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport {\n parseCsv,\n guessCsvDelimiter,\n fetchTextUtf8,\n convertCsvToSpreadsheetData,\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 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 loadCsv = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n try {\n const text = await fetchTextUtf8(props.url);\n const parsed = parseCsv(text, { delimiter: guessCsvDelimiter(props.fileName) });\n const data = convertCsvToSpreadsheetData(parsed.header, parsed.rows, props.fileName);\n\n sheetData = data as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n loading.value = false;\n } catch (err) {\n console.error('CSV 解析错误:', err);\n error.value = t.value('csv.load_failed');\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(() => loadCsv());\n }, 100);\n});\n\nwatch(\n () => props.url,\n () => {\n loadCsv();\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('csv.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('csv.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 </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","loadCsv","text","fetchTextUtf8","parsed","parseCsv","guessCsvDelimiter","convertCsvToSpreadsheetData","err","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"],"mappings":"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"}
1
+ {"version":3,"file":"index-DAEQe-RI.mjs","sources":["../../src/renderers/Csv/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { FileSpreadsheet } from 'lucide-vue-next';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport {\n parseCsv,\n guessCsvDelimiter,\n fetchTextUtf8,\n convertCsvToSpreadsheetData,\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 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 loadCsv = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n try {\n const text = await fetchTextUtf8(props.url);\n const parsed = parseCsv(text, { delimiter: guessCsvDelimiter(props.fileName) });\n const data = convertCsvToSpreadsheetData(parsed.header, parsed.rows, props.fileName);\n\n sheetData = data as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n loading.value = false;\n } catch (err) {\n console.error('CSV 解析错误:', err);\n error.value = t.value('csv.load_failed');\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(() => loadCsv());\n }, 100);\n});\n\nwatch(\n () => props.url,\n () => {\n loadCsv();\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('csv.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('csv.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 </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","loadCsv","text","fetchTextUtf8","parsed","parseCsv","guessCsvDelimiter","convertCsvToSpreadsheetData","err","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"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { defineComponent as G, ref as a, watch as y, nextTick as P, openBlock as i, createElementBlock as f, createElementVNode as s, toDisplayString as D, normalizeStyle as S, Fragment as L, renderList as M } from "vue";
2
2
  import N from "mammoth";
3
- import { u as $ } from "./index-DpAxU2JM.mjs";
3
+ import { u as $ } from "./index-C324a7kV.mjs";
4
4
  const B = {
5
5
  key: 0,
6
6
  class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full"
@@ -100,4 +100,4 @@ const B = {
100
100
  export {
101
101
  W as default
102
102
  };
103
- //# sourceMappingURL=index-DsznjwsH.mjs.map
103
+ //# sourceMappingURL=index-DAo-7spn.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-DsznjwsH.mjs","sources":["../../src/renderers/Docx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, nextTick } from 'vue';\nimport mammoth from 'mammoth';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst PAGE_HEIGHT = 1123;\nconst PAGE_PADDING_Y = 60;\nconst PAGE_PADDING_X = 50;\nconst PAGE_CONTENT_HEIGHT = PAGE_HEIGHT - PAGE_PADDING_Y * 2;\nconst PAGE_GAP = 24;\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst html = ref('');\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst pages = ref<string[]>([]);\nconst measureRef = ref<HTMLDivElement | null>(null);\n\nconst loadDocx = async () => {\n loading.value = true;\n error.value = null;\n html.value = '';\n pages.value = [];\n\n try {\n const response = await fetch(props.url);\n if (!response.ok) throw new Error('文件加载失败');\n const arrayBuffer = await response.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer });\n html.value = result.value;\n } catch (err) {\n console.error('Docx 解析错误:', err);\n error.value = t.value('docx.parse_failed');\n } finally {\n loading.value = false;\n }\n};\n\nconst paginate = () => {\n const container = measureRef.value;\n if (!container || !html.value) return;\n\n const children = Array.from(container.children) as HTMLElement[];\n if (children.length === 0) {\n pages.value = [html.value];\n return;\n }\n\n const result: string[][] = [[]];\n let currentPageUsed = 0;\n\n for (const child of children) {\n const h = child.offsetHeight;\n\n if (currentPageUsed > 0 && currentPageUsed + h > PAGE_CONTENT_HEIGHT) {\n result.push([]);\n currentPageUsed = 0;\n }\n\n result[result.length - 1].push(child.outerHTML);\n currentPageUsed += h;\n }\n\n if (result.length === 0) result.push([]);\n\n pages.value = result.map((blocks) => blocks.join(''));\n};\n\nwatch(() => props.url, loadDocx, { immediate: true });\n\nwatch(html, async () => {\n if (!html.value) return;\n await nextTick();\n requestAnimationFrame(() => paginate());\n});\n\nconst contentStyle = {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n lineHeight: '1.8',\n color: '#333',\n};\n\nconst measureStyle = {\n ...contentStyle,\n position: 'absolute' as const,\n visibility: 'hidden' as const,\n width: `${794 - PAGE_PADDING_X * 2}px`,\n pointerEvents: 'none' as const,\n};\n\nconst pageStyle = {\n width: '100%',\n maxWidth: '794px',\n minHeight: `${PAGE_HEIGHT}px`,\n background: 'white',\n boxShadow: '0 2px 12px rgba(0, 0, 0, 0.15)',\n flexShrink: 0,\n padding: `${PAGE_PADDING_Y}px ${PAGE_PADDING_X}px`,\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 <div v-else class=\"vfp-w-full vfp-h-full vfp-overflow-auto\" style=\"background: rgba(0, 0, 0, 0.15)\">\n <!-- 隐藏测量区 -->\n <div ref=\"measureRef\" :style=\"measureStyle\" v-html=\"html\" />\n\n <!-- 实际页面 -->\n <div\n class=\"vfp-py-6 md:vfp-py-10 vfp-flex vfp-flex-col vfp-items-center\"\n :style=\"{ gap: `${PAGE_GAP}px` }\"\n >\n <div v-for=\"(pageHtml, i) in pages.length > 0 ? pages : ['']\" :key=\"i\" :style=\"pageStyle\">\n <div :style=\"contentStyle\" v-html=\"pageHtml\" />\n </div>\n </div>\n </div>\n</template>\n"],"names":["PAGE_HEIGHT","PAGE_PADDING_Y","PAGE_PADDING_X","PAGE_GAP","PAGE_CONTENT_HEIGHT","props","__props","t","useTranslator","html","ref","loading","error","pages","measureRef","loadDocx","response","arrayBuffer","result","mammoth","err","paginate","container","children","currentPageUsed","child","h","blocks","watch","nextTick","contentStyle","measureStyle","pageStyle","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_Fragment","_renderList","pageHtml","i"],"mappings":"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"}
1
+ {"version":3,"file":"index-DAo-7spn.mjs","sources":["../../src/renderers/Docx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, nextTick } from 'vue';\nimport mammoth from 'mammoth';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst PAGE_HEIGHT = 1123;\nconst PAGE_PADDING_Y = 60;\nconst PAGE_PADDING_X = 50;\nconst PAGE_CONTENT_HEIGHT = PAGE_HEIGHT - PAGE_PADDING_Y * 2;\nconst PAGE_GAP = 24;\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst html = ref('');\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst pages = ref<string[]>([]);\nconst measureRef = ref<HTMLDivElement | null>(null);\n\nconst loadDocx = async () => {\n loading.value = true;\n error.value = null;\n html.value = '';\n pages.value = [];\n\n try {\n const response = await fetch(props.url);\n if (!response.ok) throw new Error('文件加载失败');\n const arrayBuffer = await response.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer });\n html.value = result.value;\n } catch (err) {\n console.error('Docx 解析错误:', err);\n error.value = t.value('docx.parse_failed');\n } finally {\n loading.value = false;\n }\n};\n\nconst paginate = () => {\n const container = measureRef.value;\n if (!container || !html.value) return;\n\n const children = Array.from(container.children) as HTMLElement[];\n if (children.length === 0) {\n pages.value = [html.value];\n return;\n }\n\n const result: string[][] = [[]];\n let currentPageUsed = 0;\n\n for (const child of children) {\n const h = child.offsetHeight;\n\n if (currentPageUsed > 0 && currentPageUsed + h > PAGE_CONTENT_HEIGHT) {\n result.push([]);\n currentPageUsed = 0;\n }\n\n result[result.length - 1].push(child.outerHTML);\n currentPageUsed += h;\n }\n\n if (result.length === 0) result.push([]);\n\n pages.value = result.map((blocks) => blocks.join(''));\n};\n\nwatch(() => props.url, loadDocx, { immediate: true });\n\nwatch(html, async () => {\n if (!html.value) return;\n await nextTick();\n requestAnimationFrame(() => paginate());\n});\n\nconst contentStyle = {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n lineHeight: '1.8',\n color: '#333',\n};\n\nconst measureStyle = {\n ...contentStyle,\n position: 'absolute' as const,\n visibility: 'hidden' as const,\n width: `${794 - PAGE_PADDING_X * 2}px`,\n pointerEvents: 'none' as const,\n};\n\nconst pageStyle = {\n width: '100%',\n maxWidth: '794px',\n minHeight: `${PAGE_HEIGHT}px`,\n background: 'white',\n boxShadow: '0 2px 12px rgba(0, 0, 0, 0.15)',\n flexShrink: 0,\n padding: `${PAGE_PADDING_Y}px ${PAGE_PADDING_X}px`,\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 <div v-else class=\"vfp-w-full vfp-h-full vfp-overflow-auto\" style=\"background: rgba(0, 0, 0, 0.15)\">\n <!-- 隐藏测量区 -->\n <div ref=\"measureRef\" :style=\"measureStyle\" v-html=\"html\" />\n\n <!-- 实际页面 -->\n <div\n class=\"vfp-py-6 md:vfp-py-10 vfp-flex vfp-flex-col vfp-items-center\"\n :style=\"{ gap: `${PAGE_GAP}px` }\"\n >\n <div v-for=\"(pageHtml, i) in pages.length > 0 ? pages : ['']\" :key=\"i\" :style=\"pageStyle\">\n <div :style=\"contentStyle\" v-html=\"pageHtml\" />\n </div>\n </div>\n </div>\n</template>\n"],"names":["PAGE_HEIGHT","PAGE_PADDING_Y","PAGE_PADDING_X","PAGE_GAP","PAGE_CONTENT_HEIGHT","props","__props","t","useTranslator","html","ref","loading","error","pages","measureRef","loadDocx","response","arrayBuffer","result","mammoth","err","paginate","container","children","currentPageUsed","child","h","blocks","watch","nextTick","contentStyle","measureStyle","pageStyle","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_Fragment","_renderList","pageHtml","i"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { defineComponent as x, ref as p, onMounted as g, watch as k, onBeforeUnmount as b, openBlock as a, createElementBlock as d, createElementVNode as t, toDisplayString as c, unref as m, createCommentVNode as w } from "vue";
2
2
  import j from "video.js";
3
- import { u as T, a as h } from "./index-DpAxU2JM.mjs";
3
+ import { u as T, a as h } from "./index-C324a7kV.mjs";
4
4
  const C = {
5
5
  key: 0,
6
6
  class: "vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full"
@@ -110,4 +110,4 @@ const C = {
110
110
  export {
111
111
  A as default
112
112
  };
113
- //# sourceMappingURL=index-C8ZF84WX.mjs.map
113
+ //# sourceMappingURL=index-DXlcF1Dk.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-C8ZF84WX.mjs","sources":["../../src/renderers/Video/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, onMounted, onBeforeUnmount, watch } from 'vue';\nimport videojs from 'video.js';\nimport 'video.js/dist/video-js.css';\nimport { getVideoMimeType } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\n\ntype VideoJsPlayer = ReturnType<typeof videojs>;\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst error = ref<string | null>(null);\nconst isLoading = ref(true);\nconst videoContainerRef = ref<HTMLDivElement | null>(null);\nlet player: VideoJsPlayer | null = null;\n\nconst initPlayer = () => {\n if (!videoContainerRef.value || player) return;\n\n const videoElement = document.createElement('video-js');\n videoElement.classList.add('vjs-big-play-centered', 'vjs-theme-apple');\n videoContainerRef.value.appendChild(videoElement);\n\n const videoType = getVideoMimeType(props.url);\n\n const sources =\n videoType === 'video/quicktime'\n ? [\n { src: props.url, type: 'video/quicktime' },\n { src: props.url, type: 'video/mp4' },\n ]\n : [{ src: props.url, type: videoType }];\n\n player = videojs(videoElement, {\n controls: true,\n fill: true,\n preload: 'auto',\n controlBar: {\n children: [\n 'playToggle',\n 'volumePanel',\n 'currentTimeDisplay',\n 'timeDivider',\n 'durationDisplay',\n 'progressControl',\n 'remainingTimeDisplay',\n 'fullscreenToggle',\n ],\n volumePanel: {\n inline: false,\n },\n },\n html5: {\n vhs: {\n overrideNative: true,\n },\n nativeVideoTracks: false,\n nativeAudioTracks: false,\n nativeTextTracks: false,\n },\n sources,\n });\n\n const videoEl = player.el().querySelector('video');\n if (videoEl) {\n (videoEl as HTMLVideoElement).style.objectFit = 'contain';\n }\n\n player.on('loadeddata', () => {\n isLoading.value = false;\n });\n\n player.on('error', () => {\n const err = player?.error();\n console.error('Video.js error:', err);\n error.value = t.value('video.load_failed_with_error', { error: err?.message || t.value('common.unknown_error') });\n isLoading.value = false;\n });\n};\n\nonMounted(initPlayer);\n\nwatch(\n () => props.url,\n () => {\n if (player && !player.isDisposed()) {\n player.src({ src: props.url, type: getVideoMimeType(props.url) });\n }\n }\n);\n\nonBeforeUnmount(() => {\n if (player && !player.isDisposed()) {\n player.dispose();\n player = null;\n }\n});\n</script>\n\n<template>\n <div v-if=\"error\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-16 vfp-h-16 vfp-mx-auto vfp-mb-4 vfp-rounded-full vfp-bg-red-500/10 vfp-flex vfp-items-center vfp-justify-center\"\n >\n <svg\n class=\"vfp-w-8 vfp-h-8 vfp-text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <p class=\"vfp-text-lg vfp-font-medium vfp-text-fg-primary vfp-mb-2\">{{ t('video.load_failed') }}</p>\n <p class=\"vfp-text-sm vfp-text-fg-tertiary\">{{ error }}</p>\n </div>\n </div>\n\n <div v-else class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div class=\"vfp-w-full vfp-h-full vfp-relative\">\n <div\n v-if=\"isLoading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-3 vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-12 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-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('video.loading') }}</p>\n </div>\n </div>\n\n <div\n ref=\"videoContainerRef\"\n class=\"vfp-overflow-hidden vfp-w-full vfp-h-full\"\n style=\"box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05)\"\n />\n </div>\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","error","ref","isLoading","videoContainerRef","player","onMounted","videoElement","videoType","getVideoMimeType","sources","videojs","videoEl","err","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","_unref","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9"],"mappings":"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"}
1
+ {"version":3,"file":"index-DXlcF1Dk.mjs","sources":["../../src/renderers/Video/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, onMounted, onBeforeUnmount, watch } from 'vue';\nimport videojs from 'video.js';\nimport 'video.js/dist/video-js.css';\nimport { getVideoMimeType } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\n\ntype VideoJsPlayer = ReturnType<typeof videojs>;\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst error = ref<string | null>(null);\nconst isLoading = ref(true);\nconst videoContainerRef = ref<HTMLDivElement | null>(null);\nlet player: VideoJsPlayer | null = null;\n\nconst initPlayer = () => {\n if (!videoContainerRef.value || player) return;\n\n const videoElement = document.createElement('video-js');\n videoElement.classList.add('vjs-big-play-centered', 'vjs-theme-apple');\n videoContainerRef.value.appendChild(videoElement);\n\n const videoType = getVideoMimeType(props.url);\n\n const sources =\n videoType === 'video/quicktime'\n ? [\n { src: props.url, type: 'video/quicktime' },\n { src: props.url, type: 'video/mp4' },\n ]\n : [{ src: props.url, type: videoType }];\n\n player = videojs(videoElement, {\n controls: true,\n fill: true,\n preload: 'auto',\n controlBar: {\n children: [\n 'playToggle',\n 'volumePanel',\n 'currentTimeDisplay',\n 'timeDivider',\n 'durationDisplay',\n 'progressControl',\n 'remainingTimeDisplay',\n 'fullscreenToggle',\n ],\n volumePanel: {\n inline: false,\n },\n },\n html5: {\n vhs: {\n overrideNative: true,\n },\n nativeVideoTracks: false,\n nativeAudioTracks: false,\n nativeTextTracks: false,\n },\n sources,\n });\n\n const videoEl = player.el().querySelector('video');\n if (videoEl) {\n (videoEl as HTMLVideoElement).style.objectFit = 'contain';\n }\n\n player.on('loadeddata', () => {\n isLoading.value = false;\n });\n\n player.on('error', () => {\n const err = player?.error();\n console.error('Video.js error:', err);\n error.value = t.value('video.load_failed_with_error', { error: err?.message || t.value('common.unknown_error') });\n isLoading.value = false;\n });\n};\n\nonMounted(initPlayer);\n\nwatch(\n () => props.url,\n () => {\n if (player && !player.isDisposed()) {\n player.src({ src: props.url, type: getVideoMimeType(props.url) });\n }\n }\n);\n\nonBeforeUnmount(() => {\n if (player && !player.isDisposed()) {\n player.dispose();\n player = null;\n }\n});\n</script>\n\n<template>\n <div v-if=\"error\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-16 vfp-h-16 vfp-mx-auto vfp-mb-4 vfp-rounded-full vfp-bg-red-500/10 vfp-flex vfp-items-center vfp-justify-center\"\n >\n <svg\n class=\"vfp-w-8 vfp-h-8 vfp-text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <p class=\"vfp-text-lg vfp-font-medium vfp-text-fg-primary vfp-mb-2\">{{ t('video.load_failed') }}</p>\n <p class=\"vfp-text-sm vfp-text-fg-tertiary\">{{ error }}</p>\n </div>\n </div>\n\n <div v-else class=\"vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full\">\n <div class=\"vfp-w-full vfp-h-full vfp-relative\">\n <div\n v-if=\"isLoading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-3 vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-12 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-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('video.loading') }}</p>\n </div>\n </div>\n\n <div\n ref=\"videoContainerRef\"\n class=\"vfp-overflow-hidden vfp-w-full vfp-h-full\"\n style=\"box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.05)\"\n />\n </div>\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","error","ref","isLoading","videoContainerRef","player","onMounted","videoElement","videoType","getVideoMimeType","sources","videojs","videoEl","err","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","_unref","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9"],"mappings":"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"}