@brftech/filex-core 0.13.1 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ArchiveViewer-Brzg_0Xj.js → ArchiveViewer-CxdOyBhs.js} +35 -36
- package/dist/ArchiveViewer-CxdOyBhs.js.map +1 -0
- package/dist/{CsvViewer-T7W9mqZB.js → CsvViewer-JG3nzTgf.js} +52 -53
- package/dist/CsvViewer-JG3nzTgf.js.map +1 -0
- package/dist/{DrawioViewer-DReOOHRc.js → DrawioViewer-BEYLdtPG.js} +22 -23
- package/dist/{DrawioViewer-DReOOHRc.js.map → DrawioViewer-BEYLdtPG.js.map} +1 -1
- package/dist/{EpubViewer-yf9zJXXg.js → EpubViewer-BwUDmJm4.js} +31 -32
- package/dist/EpubViewer-BwUDmJm4.js.map +1 -0
- package/dist/{IpynbViewer-Dt_l00CD.js → IpynbViewer-CuHQoAHU.js} +35 -35
- package/dist/IpynbViewer-CuHQoAHU.js.map +1 -0
- package/dist/{MermaidViewer-Nbv27ana.js → MermaidViewer-DLmijDXo.js} +47 -48
- package/dist/MermaidViewer-DLmijDXo.js.map +1 -0
- package/dist/{PsdViewer-1nRpsuvz.js → PsdViewer-D-FM4eNi.js} +38 -39
- package/dist/PsdViewer-D-FM4eNi.js.map +1 -0
- package/dist/{TiffViewer-Djawe0Rq.js → TiffViewer-DOw4z_dO.js} +36 -37
- package/dist/TiffViewer-DOw4z_dO.js.map +1 -0
- package/dist/{Viewer3D-D7EtANiH.js → Viewer3D-CJJJgkuv.js} +15 -16
- package/dist/{Viewer3D-D7EtANiH.js.map → Viewer3D-CJJJgkuv.js.map} +1 -1
- package/dist/filex-core.js +11942 -66
- package/dist/filex-core.js.map +1 -1
- package/dist/filex-core.umd.cjs +29 -29
- package/dist/filex-core.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/PresenceBar.vue +13 -5
- package/src/components/RecentlyOpened.vue +9 -1
- package/src/components/StarButton.vue +9 -1
- package/src/components/TagPicker.vue +9 -1
- package/src/modals/ConvertModal.vue +10 -2
- package/src/modals/PermissionsModal.vue +9 -1
- package/src/viewers/ArchiveViewer.vue +9 -1
- package/src/viewers/CsvViewer.vue +9 -1
- package/src/viewers/DrawioViewer.vue +9 -1
- package/src/viewers/EpubViewer.vue +9 -1
- package/src/viewers/IpynbViewer.vue +9 -1
- package/src/viewers/MermaidViewer.vue +10 -2
- package/src/viewers/PdfViewer.vue +9 -1
- package/src/viewers/PsdViewer.vue +9 -1
- package/src/viewers/TiffViewer.vue +9 -1
- package/src/viewers/Viewer3D.vue +10 -2
- package/dist/ArchiveViewer-Brzg_0Xj.js.map +0 -1
- package/dist/CsvViewer-T7W9mqZB.js.map +0 -1
- package/dist/EpubViewer-yf9zJXXg.js.map +0 -1
- package/dist/IpynbViewer-Dt_l00CD.js.map +0 -1
- package/dist/MermaidViewer-Nbv27ana.js.map +0 -1
- package/dist/PsdViewer-1nRpsuvz.js.map +0 -1
- package/dist/TiffViewer-Djawe0Rq.js.map +0 -1
- package/dist/index-DeVgQCwW.js +0 -11951
- package/dist/index-DeVgQCwW.js.map +0 -1
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { defineComponent as U, ref as
|
|
2
|
-
import { _ as R } from "./index-DeVgQCwW.js";
|
|
1
|
+
import { defineComponent as U, ref as r, onMounted as L, onBeforeUnmount as F, watch as H, openBlock as u, createElementBlock as i, createElementVNode as c, toDisplayString as g, Fragment as R, createCommentVNode as b } from "vue";
|
|
3
2
|
const S = {
|
|
4
3
|
key: 0,
|
|
5
4
|
class: "filex-viewer-fallback"
|
|
6
|
-
},
|
|
5
|
+
}, V = {
|
|
7
6
|
key: 0,
|
|
8
7
|
class: "filex-viewer-epub__nav"
|
|
9
|
-
},
|
|
8
|
+
}, z = ["disabled"], A = ["disabled"], D = {
|
|
10
9
|
key: 1,
|
|
11
10
|
class: "filex-viewer-epub__loading"
|
|
12
11
|
}, T = /* @__PURE__ */ U({
|
|
@@ -20,11 +19,11 @@ const S = {
|
|
|
20
19
|
authCredentials: {}
|
|
21
20
|
},
|
|
22
21
|
setup(k) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const B =
|
|
22
|
+
const n = k, x = r(null), v = r(null), o = r(null), E = r([]);
|
|
23
|
+
r(!1);
|
|
24
|
+
const B = r(100), s = r(!1), f = r(!0);
|
|
26
25
|
let a = null, e = null;
|
|
27
|
-
async function
|
|
26
|
+
async function y() {
|
|
28
27
|
f.value = !0, s.value = !1, o.value = null;
|
|
29
28
|
let t = null;
|
|
30
29
|
try {
|
|
@@ -33,16 +32,16 @@ const S = {
|
|
|
33
32
|
"epubjs"
|
|
34
33
|
);
|
|
35
34
|
} catch {
|
|
36
|
-
o.value =
|
|
35
|
+
o.value = n.t ? n.t("viewer.peer_not_installed") : "EPUB viewer requires `epubjs` — install or use download.", f.value = !1;
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
try {
|
|
40
39
|
const l = t.default ?? t;
|
|
41
|
-
let m =
|
|
42
|
-
if (
|
|
43
|
-
const P =
|
|
40
|
+
let m = n.url;
|
|
41
|
+
if (n.authHeaders) {
|
|
42
|
+
const P = n.authHeaders(), d = await fetch(n.url, {
|
|
44
43
|
headers: P,
|
|
45
|
-
credentials:
|
|
44
|
+
credentials: n.authCredentials || "same-origin"
|
|
46
45
|
});
|
|
47
46
|
if (!d.ok) throw new Error(`${d.status} ${d.statusText}`);
|
|
48
47
|
m = await d.arrayBuffer();
|
|
@@ -63,7 +62,7 @@ const S = {
|
|
|
63
62
|
f.value = !1;
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
|
-
function
|
|
65
|
+
function p() {
|
|
67
66
|
var t;
|
|
68
67
|
(t = e == null ? void 0 : e.next) == null || t.call(e);
|
|
69
68
|
}
|
|
@@ -72,11 +71,11 @@ const S = {
|
|
|
72
71
|
(t = e == null ? void 0 : e.prev) == null || t.call(e);
|
|
73
72
|
}
|
|
74
73
|
function h(t) {
|
|
75
|
-
t.key === "ArrowRight" || t.key === "PageDown" ?
|
|
74
|
+
t.key === "ArrowRight" || t.key === "PageDown" ? p() : (t.key === "ArrowLeft" || t.key === "PageUp") && _();
|
|
76
75
|
}
|
|
77
76
|
L(() => {
|
|
78
|
-
|
|
79
|
-
}),
|
|
77
|
+
y(), window.addEventListener("keydown", h);
|
|
78
|
+
}), F(() => {
|
|
80
79
|
var t, l;
|
|
81
80
|
window.removeEventListener("keydown", h);
|
|
82
81
|
try {
|
|
@@ -88,8 +87,8 @@ const S = {
|
|
|
88
87
|
} catch {
|
|
89
88
|
}
|
|
90
89
|
e = null, a = null;
|
|
91
|
-
}),
|
|
92
|
-
() =>
|
|
90
|
+
}), H(
|
|
91
|
+
() => n.url,
|
|
93
92
|
() => {
|
|
94
93
|
if (e)
|
|
95
94
|
try {
|
|
@@ -101,11 +100,11 @@ const S = {
|
|
|
101
100
|
a.destroy();
|
|
102
101
|
} catch {
|
|
103
102
|
}
|
|
104
|
-
a = null, e = null,
|
|
103
|
+
a = null, e = null, y();
|
|
105
104
|
}
|
|
106
105
|
);
|
|
107
106
|
function C(t, l) {
|
|
108
|
-
return
|
|
107
|
+
return n.t ? n.t(t) : l;
|
|
109
108
|
}
|
|
110
109
|
return (t, l) => (u(), i("div", {
|
|
111
110
|
ref_key: "root",
|
|
@@ -114,33 +113,33 @@ const S = {
|
|
|
114
113
|
}, [
|
|
115
114
|
o.value ? (u(), i("div", S, [
|
|
116
115
|
l[0] || (l[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📖", -1)),
|
|
117
|
-
c("p", null,
|
|
118
|
-
])) : (u(), i(
|
|
116
|
+
c("p", null, g(o.value), 1)
|
|
117
|
+
])) : (u(), i(R, { key: 1 }, [
|
|
119
118
|
c("div", {
|
|
120
119
|
ref_key: "containerRef",
|
|
121
120
|
ref: v,
|
|
122
121
|
class: "filex-viewer-epub__rendition"
|
|
123
122
|
}, null, 512),
|
|
124
|
-
s.value ? (u(), i("div",
|
|
123
|
+
s.value ? (u(), i("div", V, [
|
|
125
124
|
c("button", {
|
|
126
125
|
type: "button",
|
|
127
126
|
class: "filex-viewer-btn",
|
|
128
127
|
onClick: _,
|
|
129
128
|
disabled: !s.value
|
|
130
|
-
}, "‹", 8,
|
|
129
|
+
}, "‹", 8, z),
|
|
131
130
|
c("button", {
|
|
132
131
|
type: "button",
|
|
133
132
|
class: "filex-viewer-btn",
|
|
134
|
-
onClick:
|
|
133
|
+
onClick: p,
|
|
135
134
|
disabled: !s.value
|
|
136
|
-
}, "›", 8,
|
|
137
|
-
])) :
|
|
138
|
-
f.value ? (u(), i("div",
|
|
135
|
+
}, "›", 8, A)
|
|
136
|
+
])) : b("", !0),
|
|
137
|
+
f.value ? (u(), i("div", D, g(C("viewer.loading", "Loading…")), 1)) : b("", !0)
|
|
139
138
|
], 64))
|
|
140
139
|
], 512));
|
|
141
140
|
}
|
|
142
|
-
})
|
|
141
|
+
});
|
|
143
142
|
export {
|
|
144
|
-
|
|
143
|
+
T as default
|
|
145
144
|
};
|
|
146
|
-
//# sourceMappingURL=EpubViewer-
|
|
145
|
+
//# sourceMappingURL=EpubViewer-BwUDmJm4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EpubViewer-BwUDmJm4.js","sources":["../src/viewers/EpubViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * EpubViewer — flowable EPUB reader via `epubjs`.\n *\n * Lazy-imports `epubjs` (~80 KB gzipped). epub.js renders the publication\n * inside an iframe (default `flow: 'paginated'`), but we use it in\n * scrolled-doc mode only when the user toggles the \"fit-width\" flag — by\n * default we keep paginated since that matches reader-app expectations.\n *\n * UX:\n * - prev/next page buttons (also keyboard arrow keys via composable)\n * - collapsible TOC sidebar (built from `book.loaded.navigation`)\n * - font size +/- (Themes API)\n * - graceful fallback if peer not installed\n */\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\n\nconst props = defineProps<{\n url: string;\n mime?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface TocNode {\n href: string;\n label: string;\n subitems?: TocNode[];\n}\n\nconst root = ref<HTMLDivElement | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nconst error = ref<string | null>(null);\nconst toc = ref<TocNode[]>([]);\nconst tocOpen = ref(false);\nconst fontSize = ref(100);\nconst ready = ref(false);\nconst loading = ref(true);\n\nlet book: any = null;\nlet rendition: any = null;\n\nasync function load(): Promise<void> {\n loading.value = true;\n ready.value = false;\n error.value = null;\n let mod: any = null;\n try {\n mod = await import(/* @vite-ignore */ 'epubjs');\n } catch {\n error.value = props.t\n ? props.t('viewer.peer_not_installed')\n : 'EPUB viewer requires `epubjs` — install or use download.';\n loading.value = false;\n return;\n }\n try {\n const Epub = mod.default ?? mod;\n // epub.js wants a URL (it then fetches with XHR). When the host\n // site requires auth headers we have to load the file ourselves\n // and pass an ArrayBuffer instead.\n let source: string | ArrayBuffer = props.url;\n if (props.authHeaders) {\n const headers = props.authHeaders();\n const res = await fetch(props.url, {\n headers,\n credentials: props.authCredentials || 'same-origin',\n });\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n source = await res.arrayBuffer();\n }\n book = Epub(source);\n if (!containerRef.value) {\n throw new Error('EPUB mount target missing');\n }\n rendition = book.renderTo(containerRef.value, {\n width: '100%',\n height: '100%',\n flow: 'paginated',\n manager: 'default',\n });\n await rendition.display();\n rendition.themes.fontSize(fontSize.value + '%');\n const nav = await book.loaded.navigation;\n toc.value = (nav?.toc ?? []) as TocNode[];\n ready.value = true;\n } catch (err) {\n error.value =\n err instanceof Error ? err.message : 'EPUB load failed';\n } finally {\n loading.value = false;\n }\n}\n\nfunction next(): void {\n rendition?.next?.();\n}\nfunction prev(): void {\n rendition?.prev?.();\n}\nfunction gotoHref(href: string): void {\n rendition?.display?.(href);\n tocOpen.value = false;\n}\nfunction bigger(): void {\n fontSize.value = Math.min(200, fontSize.value + 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\nfunction smaller(): void {\n fontSize.value = Math.max(60, fontSize.value - 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\n\nfunction onKey(ev: KeyboardEvent): void {\n if (ev.key === 'ArrowRight' || ev.key === 'PageDown') next();\n else if (ev.key === 'ArrowLeft' || ev.key === 'PageUp') prev();\n}\n\nonMounted(() => {\n load();\n window.addEventListener('keydown', onKey);\n});\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', onKey);\n try {\n rendition?.destroy?.();\n } catch {\n /* ignore */\n }\n try {\n book?.destroy?.();\n } catch {\n /* ignore */\n }\n rendition = null;\n book = null;\n});\n\nwatch(\n () => props.url,\n () => {\n if (rendition) {\n try {\n rendition.destroy();\n } catch {\n /* ignore */\n }\n }\n if (book) {\n try {\n book.destroy();\n } catch {\n /* ignore */\n }\n }\n book = null;\n rendition = null;\n load();\n },\n);\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div ref=\"root\" class=\"filex-viewer-epub\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">📖</span>\n <p>{{ error }}</p>\n </div>\n <template v-else>\n <div ref=\"containerRef\" class=\"filex-viewer-epub__rendition\" />\n <div v-if=\"ready\" class=\"filex-viewer-epub__nav\">\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"prev\" :disabled=\"!ready\">‹</button>\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"next\" :disabled=\"!ready\">›</button>\n </div>\n <div v-if=\"loading\" class=\"filex-viewer-epub__loading\">\n {{ tt('viewer.loading', 'Loading…') }}\n </div>\n </template>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-epub__nav {\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n gap: 8px;\n padding: 4px 8px;\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n backdrop-filter: blur(4px);\n}\n.filex-viewer-epub {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n position: relative;\n}\n.filex-viewer-epub__bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 13px;\n}\n.filex-viewer-spacer { flex: 1; }\n.filex-viewer-epub__fs {\n display: inline-block;\n min-width: 40px;\n text-align: center;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-epub__main {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n.filex-viewer-epub__rendition {\n flex: 1;\n min-height: 0;\n}\n.filex-viewer-epub__toc {\n width: 260px;\n border-right: 1px solid var(--fe-border, #e2e6ed);\n overflow-y: auto;\n padding: 12px 0;\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-epub__toc ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.filex-viewer-epub__toc-link {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: 0;\n padding: 6px 14px;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n.filex-viewer-epub__toc-link:hover {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-epub__toc-link.is-child {\n padding-left: 28px;\n color: var(--fe-text-muted, #5a6475);\n font-size: 12px;\n}\n.filex-viewer-epub__loading {\n position: absolute;\n inset: auto 0 0 0;\n text-align: center;\n padding: 6px;\n background: rgba(0, 0, 0, 0.05);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n.filex-viewer-btn {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-btn:hover:not(:disabled) {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n</style>\n"],"names":["props","__props","root","ref","containerRef","error","toc","fontSize","ready","loading","book","rendition","load","mod","Epub","source","headers","res","nav","err","next","_a","prev","onKey","ev","onMounted","onBeforeUnmount","_b","watch","tt","key","fallback","_createElementBlock","_openBlock","_hoisted_1","_cache","_createElementVNode","_Fragment","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_toDisplayString"],"mappings":"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"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { defineComponent as J, ref as _, onMounted as R, onBeforeUnmount as U, watch as D, computed as q, openBlock as a, createElementBlock as r, createElementVNode as d, toDisplayString as p, Fragment as h, renderList as E, createCommentVNode as
|
|
1
|
+
import { defineComponent as J, ref as _, onMounted as R, onBeforeUnmount as U, watch as D, computed as q, openBlock as a, createElementBlock as r, createElementVNode as d, toDisplayString as p, Fragment as h, renderList as E, createCommentVNode as B } from "vue";
|
|
2
2
|
import { f as z } from "./useViewerFetch-czqbd2Lj.js";
|
|
3
|
-
import {
|
|
4
|
-
const
|
|
3
|
+
import { ensureHighlight as G } from "./filex-core.js";
|
|
4
|
+
const K = { class: "filex-viewer-ipynb" }, P = { class: "filex-viewer-ipynb__pane" }, Q = {
|
|
5
5
|
key: 0,
|
|
6
6
|
class: "filex-viewer-fallback"
|
|
7
|
-
},
|
|
7
|
+
}, W = {
|
|
8
8
|
key: 1,
|
|
9
9
|
class: "filex-viewer-fallback"
|
|
10
|
-
},
|
|
10
|
+
}, X = { key: 2 }, Y = ["data-type"], Z = { class: "filex-viewer-ipynb__exec" }, ee = { class: "filex-viewer-ipynb__src hljs" }, te = ["innerHTML"], ne = { key: 1 }, ae = {
|
|
11
11
|
key: 0,
|
|
12
12
|
class: "filex-viewer-ipynb__outputs"
|
|
13
|
-
},
|
|
13
|
+
}, re = ["src", "alt"], le = ["innerHTML"], ie = ["data-type"], se = ["innerHTML"], ue = {
|
|
14
14
|
key: 1,
|
|
15
15
|
class: "filex-viewer-ipynb__md-raw"
|
|
16
|
-
},
|
|
16
|
+
}, oe = {
|
|
17
17
|
key: 2,
|
|
18
18
|
class: "filex-viewer-ipynb__src"
|
|
19
|
-
},
|
|
19
|
+
}, _e = /* @__PURE__ */ J({
|
|
20
20
|
__name: "IpynbViewer",
|
|
21
21
|
props: {
|
|
22
22
|
url: {},
|
|
@@ -25,10 +25,10 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
25
25
|
authHeaders: { type: Function },
|
|
26
26
|
authCredentials: {}
|
|
27
27
|
},
|
|
28
|
-
setup(
|
|
29
|
-
const u =
|
|
28
|
+
setup(N) {
|
|
29
|
+
const u = N, o = _([]), M = _("python"), f = _(null), y = _(!0), w = _(/* @__PURE__ */ new Map()), k = _(/* @__PURE__ */ new Map());
|
|
30
30
|
let v = 0, x = null, g = null;
|
|
31
|
-
async function
|
|
31
|
+
async function V() {
|
|
32
32
|
if (g !== null) return g || null;
|
|
33
33
|
try {
|
|
34
34
|
const e = await import(
|
|
@@ -44,7 +44,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
44
44
|
return Array.isArray(e) ? e.join("") : e ?? "";
|
|
45
45
|
}
|
|
46
46
|
async function H() {
|
|
47
|
-
var i, m,
|
|
47
|
+
var i, m, I, S;
|
|
48
48
|
y.value = !0, f.value = null, o.value = [], w.value = /* @__PURE__ */ new Map(), k.value = /* @__PURE__ */ new Map();
|
|
49
49
|
const e = ++v;
|
|
50
50
|
let t;
|
|
@@ -66,7 +66,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
66
66
|
f.value = "Invalid notebook JSON", y.value = !1;
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
-
if (o.value = Array.isArray(n.cells) ? n.cells : [], M.value = ((
|
|
69
|
+
if (o.value = Array.isArray(n.cells) ? n.cells : [], M.value = ((I = (m = n.metadata) == null ? void 0 : m.kernelspec) == null ? void 0 : I.language) || "python", x = await G(), e !== v) return;
|
|
70
70
|
if (x) {
|
|
71
71
|
const l = x.default ?? x, b = (S = l.getLanguage) != null && S.call(l, M.value) ? M.value : null;
|
|
72
72
|
o.value.forEach((j, F) => {
|
|
@@ -80,7 +80,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
const c = await
|
|
83
|
+
const c = await V();
|
|
84
84
|
e === v && (c && o.value.forEach((l, b) => {
|
|
85
85
|
if (l.cell_type === "markdown")
|
|
86
86
|
try {
|
|
@@ -104,7 +104,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
104
104
|
}
|
|
105
105
|
return null;
|
|
106
106
|
}
|
|
107
|
-
function
|
|
107
|
+
function C(e) {
|
|
108
108
|
return e != null && e.data && e.data["text/html"] ? s(e.data["text/html"]).replace(/<script[\s\S]*?<\/script>/gi, "") : null;
|
|
109
109
|
}
|
|
110
110
|
R(H), U(() => {
|
|
@@ -116,60 +116,60 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
|
|
|
116
116
|
function $(e, t) {
|
|
117
117
|
return u.t ? u.t(e) : t;
|
|
118
118
|
}
|
|
119
|
-
return (e, t) => (a(), r("div",
|
|
120
|
-
d("div",
|
|
121
|
-
f.value ? (a(), r("div",
|
|
119
|
+
return (e, t) => (a(), r("div", K, [
|
|
120
|
+
d("div", P, [
|
|
121
|
+
f.value ? (a(), r("div", Q, [
|
|
122
122
|
t[0] || (t[0] = d("span", { class: "filex-viewer-fallback__icon" }, "📓", -1)),
|
|
123
123
|
d("p", null, p(f.value), 1)
|
|
124
|
-
])) : y.value ? (a(), r("div",
|
|
124
|
+
])) : y.value ? (a(), r("div", W, [
|
|
125
125
|
t[1] || (t[1] = d("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
|
|
126
126
|
d("p", null, p($("viewer.loading", "Loading…")), 1)
|
|
127
|
-
])) : (a(), r("div",
|
|
127
|
+
])) : (a(), r("div", X, [
|
|
128
128
|
(a(!0), r(h, null, E(o.value, (n, c) => (a(), r("div", {
|
|
129
129
|
key: c,
|
|
130
130
|
class: "filex-viewer-ipynb__cell",
|
|
131
131
|
"data-type": n.cell_type
|
|
132
132
|
}, [
|
|
133
133
|
n.cell_type === "code" ? (a(), r(h, { key: 0 }, [
|
|
134
|
-
d("div",
|
|
135
|
-
d("pre",
|
|
134
|
+
d("div", Z, " In [" + p(n.execution_count ?? " ") + "]: ", 1),
|
|
135
|
+
d("pre", ee, [
|
|
136
136
|
w.value.get(c) ? (a(), r("code", {
|
|
137
137
|
key: 0,
|
|
138
138
|
innerHTML: w.value.get(c)
|
|
139
|
-
}, null, 8,
|
|
139
|
+
}, null, 8, te)) : (a(), r("code", ne, p(s(n.source)), 1))
|
|
140
140
|
]),
|
|
141
|
-
n.outputs && n.outputs.length ? (a(), r("div",
|
|
141
|
+
n.outputs && n.outputs.length ? (a(), r("div", ae, [
|
|
142
142
|
(a(!0), r(h, null, E(n.outputs, (i, m) => (a(), r(h, { key: m }, [
|
|
143
143
|
L(i) ? (a(), r("img", {
|
|
144
144
|
key: 0,
|
|
145
145
|
src: L(i) || "",
|
|
146
146
|
class: "filex-viewer-ipynb__img",
|
|
147
147
|
alt: `output ${m}`
|
|
148
|
-
}, null, 8,
|
|
148
|
+
}, null, 8, re)) : C(i) ? (a(), r("div", {
|
|
149
149
|
key: 1,
|
|
150
150
|
class: "filex-viewer-ipynb__html",
|
|
151
|
-
innerHTML:
|
|
152
|
-
}, null, 8,
|
|
151
|
+
innerHTML: C(i)
|
|
152
|
+
}, null, 8, le)) : T(i) ? (a(), r("pre", {
|
|
153
153
|
key: 2,
|
|
154
154
|
class: "filex-viewer-ipynb__out",
|
|
155
155
|
"data-type": i.output_type
|
|
156
|
-
}, p(T(i)), 9,
|
|
156
|
+
}, p(T(i)), 9, ie)) : B("", !0)
|
|
157
157
|
], 64))), 128))
|
|
158
|
-
])) :
|
|
158
|
+
])) : B("", !0)
|
|
159
159
|
], 64)) : n.cell_type === "markdown" ? (a(), r(h, { key: 1 }, [
|
|
160
160
|
k.value.get(c) ? (a(), r("div", {
|
|
161
161
|
key: 0,
|
|
162
162
|
class: "filex-viewer-ipynb__md",
|
|
163
163
|
innerHTML: k.value.get(c)
|
|
164
|
-
}, null, 8,
|
|
165
|
-
], 64)) : (a(), r("pre",
|
|
166
|
-
], 8,
|
|
164
|
+
}, null, 8, se)) : (a(), r("pre", ue, p(s(n.source)), 1))
|
|
165
|
+
], 64)) : (a(), r("pre", oe, p(s(n.source)), 1))
|
|
166
|
+
], 8, Y))), 128))
|
|
167
167
|
]))
|
|
168
168
|
])
|
|
169
169
|
]));
|
|
170
170
|
}
|
|
171
|
-
})
|
|
171
|
+
});
|
|
172
172
|
export {
|
|
173
|
-
|
|
173
|
+
_e as default
|
|
174
174
|
};
|
|
175
|
-
//# sourceMappingURL=IpynbViewer-
|
|
175
|
+
//# sourceMappingURL=IpynbViewer-CuHQoAHU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpynbViewer-CuHQoAHU.js","sources":["../src/viewers/IpynbViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.\n *\n * Pure-JS render — no peer dependency required:\n * - code cells → `<pre><code>` (highlight.js when available)\n * - markdown cells → markdown-it when available, plain `<pre>` otherwise\n * - output cells → text (stream / display_data 'text/plain'),\n * images (display_data 'image/png' base64),\n * HTML (display_data 'text/html', sanitized via\n * element-only insertion — no script tags)\n *\n * Source list / output count counters at the top so a 200-cell\n * notebook doesn't surprise the user.\n */\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { fetchViewerText } from '../composables/useViewerFetch';\nimport { ensureHighlight } from '../composables/useMonacoLoader';\n\nconst props = defineProps<{\n url: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface Cell {\n cell_type: 'code' | 'markdown' | 'raw' | string;\n source: string | string[];\n outputs?: any[];\n execution_count?: number | null;\n metadata?: Record<string, unknown>;\n}\n\ninterface Notebook {\n cells: Cell[];\n metadata?: { kernelspec?: { language?: string; name?: string } };\n}\n\nconst cells = ref<Cell[]>([]);\nconst language = ref<string>('python');\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst renderedSources = ref<Map<number, string>>(new Map());\nconst renderedMarkdown = ref<Map<number, string>>(new Map());\n\nlet renderToken = 0;\nlet highlight: any = null;\nlet mdRenderer: any = null;\n\nasync function ensureMd(): Promise<any | null> {\n if (mdRenderer !== null) return mdRenderer || null;\n try {\n const mod = await import(/* @vite-ignore */ 'markdown-it');\n const Md = (mod as any).default ?? mod;\n mdRenderer = new Md({ html: false, linkify: true, breaks: true });\n return mdRenderer;\n } catch {\n mdRenderer = false;\n return null;\n }\n}\n\nfunction joinSource(source: string | string[]): string {\n return Array.isArray(source) ? source.join('') : (source ?? '');\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n cells.value = [];\n renderedSources.value = new Map();\n renderedMarkdown.value = new Map();\n const myToken = ++renderToken;\n\n let raw: string;\n try {\n raw = await fetchViewerText({\n url: props.url,\n headers: props.authHeaders?.() ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'fetch failed';\n loading.value = false;\n return;\n }\n\n if (myToken !== renderToken) return;\n\n let nb: Notebook;\n try {\n nb = JSON.parse(raw);\n } catch (err) {\n error.value = 'Invalid notebook JSON';\n loading.value = false;\n return;\n }\n cells.value = Array.isArray(nb.cells) ? nb.cells : [];\n language.value = nb.metadata?.kernelspec?.language || 'python';\n\n // Best-effort hljs highlight per code cell.\n highlight = (await ensureHighlight()) as any;\n if (myToken !== renderToken) return;\n if (highlight) {\n const hljs = highlight.default ?? highlight;\n const langOk = hljs.getLanguage?.(language.value) ? language.value : null;\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'code') {\n const text = joinSource(cell.source);\n try {\n const result = langOk\n ? hljs.highlight(text, { language: langOk, ignoreIllegals: true })\n : hljs.highlightAuto(text);\n renderedSources.value.set(idx, result.value);\n } catch {\n /* leave unrendered */\n }\n }\n });\n }\n\n const md = await ensureMd();\n if (myToken !== renderToken) return;\n if (md) {\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'markdown') {\n try {\n renderedMarkdown.value.set(idx, md.render(joinSource(cell.source)));\n } catch {\n /* leave plain */\n }\n }\n });\n }\n\n loading.value = false;\n}\n\nfunction outputText(out: any): string | null {\n if (!out) return null;\n if (out.output_type === 'stream') {\n return joinSource(out.text);\n }\n if (out.output_type === 'error') {\n return [out.ename, out.evalue, ...(out.traceback || [])]\n .filter(Boolean)\n .join('\\n');\n }\n if (out.output_type === 'execute_result' || out.output_type === 'display_data') {\n if (out.data?.['text/plain']) {\n return joinSource(out.data['text/plain']);\n }\n }\n return null;\n}\n\nfunction outputImage(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['image/png']) return `data:image/png;base64,${out.data['image/png']}`;\n if (out.data['image/jpeg']) return `data:image/jpeg;base64,${out.data['image/jpeg']}`;\n if (out.data['image/svg+xml']) {\n const svg = joinSource(out.data['image/svg+xml']);\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;\n }\n return null;\n}\n\nfunction outputHtml(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['text/html']) {\n const html = joinSource(out.data['text/html']);\n // Strip <script> for safety — outputs from arbitrary notebooks.\n return html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\n }\n return null;\n}\n\nonMounted(load);\nonBeforeUnmount(() => {\n renderToken++;\n});\nwatch(() => props.url, load);\n\nconst stats = computed(() => {\n const codeCount = cells.value.filter((c) => c.cell_type === 'code').length;\n const mdCount = cells.value.filter((c) => c.cell_type === 'markdown').length;\n return { code: codeCount, md: mdCount, total: cells.value.length };\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-ipynb\">\n <div class=\"filex-viewer-ipynb__pane\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">📓</span>\n <p>{{ error }}</p>\n </div>\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div v-else>\n <div\n v-for=\"(cell, idx) in cells\"\n :key=\"idx\"\n class=\"filex-viewer-ipynb__cell\"\n :data-type=\"cell.cell_type\"\n >\n <template v-if=\"cell.cell_type === 'code'\">\n <div class=\"filex-viewer-ipynb__exec\">\n In [{{ cell.execution_count ?? ' ' }}]:\n </div>\n <pre class=\"filex-viewer-ipynb__src hljs\"><code\n v-if=\"renderedSources.get(idx)\"\n v-html=\"renderedSources.get(idx)\"\n /><code v-else>{{ joinSource(cell.source) }}</code></pre>\n <div v-if=\"cell.outputs && cell.outputs.length\" class=\"filex-viewer-ipynb__outputs\">\n <template v-for=\"(out, j) in cell.outputs\" :key=\"j\">\n <img\n v-if=\"outputImage(out)\"\n :src=\"outputImage(out) || ''\"\n class=\"filex-viewer-ipynb__img\"\n :alt=\"`output ${j}`\"\n />\n <div\n v-else-if=\"outputHtml(out)\"\n class=\"filex-viewer-ipynb__html\"\n v-html=\"outputHtml(out)\"\n />\n <pre\n v-else-if=\"outputText(out)\"\n class=\"filex-viewer-ipynb__out\"\n :data-type=\"out.output_type\"\n >{{ outputText(out) }}</pre>\n </template>\n </div>\n </template>\n\n <template v-else-if=\"cell.cell_type === 'markdown'\">\n <div\n v-if=\"renderedMarkdown.get(idx)\"\n class=\"filex-viewer-ipynb__md\"\n v-html=\"renderedMarkdown.get(idx)\"\n />\n <pre v-else class=\"filex-viewer-ipynb__md-raw\">{{ joinSource(cell.source) }}</pre>\n </template>\n\n <template v-else>\n <pre class=\"filex-viewer-ipynb__src\">{{ joinSource(cell.source) }}</pre>\n </template>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-ipynb {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n}\n.filex-viewer-ipynb__bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-ipynb__lang {\n font-family: var(--fe-font-mono, monospace);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n.filex-viewer-ipynb__pane {\n flex: 1;\n overflow: auto;\n padding: 16px 24px;\n}\n.filex-viewer-ipynb__cell {\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n margin-bottom: 16px;\n overflow: hidden;\n}\n.filex-viewer-ipynb__cell[data-type=\"code\"] {\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-ipynb__exec {\n padding: 4px 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 11px;\n color: var(--fe-text-muted, #5a6475);\n background: rgba(0, 0, 0, 0.04);\n}\n.filex-viewer-ipynb__src {\n margin: 0;\n padding: 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n overflow-x: auto;\n}\n.filex-viewer-ipynb__outputs {\n border-top: 1px dashed var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n padding: 8px 12px;\n}\n.filex-viewer-ipynb__out {\n margin: 0;\n padding: 4px 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n.filex-viewer-ipynb__out[data-type=\"error\"] {\n color: var(--fe-danger, #dc2626);\n}\n.filex-viewer-ipynb__img {\n display: block;\n max-width: 100%;\n height: auto;\n margin: 8px 0;\n}\n.filex-viewer-ipynb__html {\n font-size: 13px;\n}\n.filex-viewer-ipynb__md {\n padding: 12px 16px;\n font-size: 14px;\n line-height: 1.6;\n}\n.filex-viewer-ipynb__md-raw {\n padding: 12px;\n margin: 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n</style>\n"],"names":["props","__props","cells","ref","language","error","loading","renderedSources","renderedMarkdown","renderToken","highlight","mdRenderer","ensureMd","mod","Md","joinSource","source","load","myToken","raw","fetchViewerText","_a","err","nb","_c","_b","ensureHighlight","hljs","langOk","_d","cell","idx","text","result","md","outputText","out","outputImage","svg","outputHtml","onMounted","onBeforeUnmount","watch","computed","codeCount","c","mdCount","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_hoisted_5","_Fragment","_renderList","_hoisted_7","_hoisted_8","_hoisted_10","_toDisplayString","_hoisted_11","j","_hoisted_14","_hoisted_16","_hoisted_17"],"mappings":"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"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { defineComponent as
|
|
1
|
+
import { defineComponent as T, ref as u, onMounted as V, onBeforeUnmount as $, openBlock as h, createElementBlock as x, createElementVNode as c, toDisplayString as k, createCommentVNode as B, withDirectives as H, normalizeStyle as Y, vShow as q } from "vue";
|
|
2
2
|
import { f as z } from "./useViewerFetch-czqbd2Lj.js";
|
|
3
|
-
|
|
4
|
-
const I = { class: "filex-viewer-mermaid" }, K = {
|
|
3
|
+
const F = { class: "filex-viewer-mermaid" }, K = {
|
|
5
4
|
key: 0,
|
|
6
5
|
class: "filex-viewer-fallback"
|
|
7
6
|
}, N = {
|
|
8
7
|
key: 1,
|
|
9
8
|
class: "filex-viewer-fallback"
|
|
10
|
-
},
|
|
9
|
+
}, X = /* @__PURE__ */ T({
|
|
11
10
|
__name: "MermaidViewer",
|
|
12
11
|
props: {
|
|
13
12
|
url: {},
|
|
@@ -18,17 +17,17 @@ const I = { class: "filex-viewer-mermaid" }, K = {
|
|
|
18
17
|
authCredentials: {}
|
|
19
18
|
},
|
|
20
19
|
setup(M) {
|
|
21
|
-
const
|
|
22
|
-
let
|
|
20
|
+
const r = M, d = u(null), a = u(null), s = u(!0), m = u(1), v = u(0), y = u(0);
|
|
21
|
+
let p = !1, l = null, f = 0, i = null;
|
|
23
22
|
async function P() {
|
|
24
23
|
var e, t;
|
|
25
24
|
if (i) return i;
|
|
26
25
|
try {
|
|
27
|
-
const
|
|
26
|
+
const n = await import(
|
|
28
27
|
/* @vite-ignore */
|
|
29
28
|
"mermaid"
|
|
30
29
|
);
|
|
31
|
-
return i =
|
|
30
|
+
return i = n.default ?? n, (t = i.initialize) == null || t.call(i, {
|
|
32
31
|
startOnLoad: !1,
|
|
33
32
|
securityLevel: "strict",
|
|
34
33
|
theme: (e = window.matchMedia) != null && e.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "default"
|
|
@@ -37,92 +36,92 @@ const I = { class: "filex-viewer-mermaid" }, K = {
|
|
|
37
36
|
return null;
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
|
-
async function
|
|
39
|
+
async function C() {
|
|
41
40
|
var g;
|
|
42
|
-
s.value = !0,
|
|
41
|
+
s.value = !0, a.value = null;
|
|
43
42
|
const e = ++f, t = await P();
|
|
44
43
|
if (e !== f) return;
|
|
45
44
|
if (!t) {
|
|
46
|
-
|
|
45
|
+
a.value = r.t ? r.t("viewer.peer_not_installed") : "Mermaid viewer requires `mermaid` — install or use download.", s.value = !1;
|
|
47
46
|
return;
|
|
48
47
|
}
|
|
49
|
-
let
|
|
48
|
+
let n;
|
|
50
49
|
try {
|
|
51
|
-
|
|
52
|
-
url:
|
|
53
|
-
headers: ((g =
|
|
54
|
-
credentials:
|
|
50
|
+
n = await z({
|
|
51
|
+
url: r.url,
|
|
52
|
+
headers: ((g = r.authHeaders) == null ? void 0 : g.call(r)) ?? {},
|
|
53
|
+
credentials: r.authCredentials
|
|
55
54
|
});
|
|
56
55
|
} catch (o) {
|
|
57
|
-
|
|
56
|
+
a.value = o instanceof Error ? o.message : "fetch failed", s.value = !1;
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
if (e === f)
|
|
61
60
|
try {
|
|
62
|
-
const o = `filex-mermaid-${Date.now()}`, { svg:
|
|
61
|
+
const o = `filex-mermaid-${Date.now()}`, { svg: L } = await t.render(o, n);
|
|
63
62
|
if (e !== f) return;
|
|
64
63
|
if (d.value) {
|
|
65
|
-
d.value.innerHTML =
|
|
64
|
+
d.value.innerHTML = L;
|
|
66
65
|
const w = d.value.querySelector("svg");
|
|
67
66
|
w && (w.style.maxWidth = "100%", w.style.height = "auto");
|
|
68
67
|
}
|
|
69
68
|
} catch (o) {
|
|
70
|
-
|
|
69
|
+
a.value = o instanceof Error ? o.message : "render failed";
|
|
71
70
|
} finally {
|
|
72
71
|
s.value = !1;
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
|
-
function
|
|
74
|
+
function D(e) {
|
|
76
75
|
if (!e.ctrlKey && !e.metaKey) return;
|
|
77
76
|
e.preventDefault();
|
|
78
|
-
const
|
|
79
|
-
m.value = Math.max(0.2, Math.min(8, m.value *
|
|
80
|
-
}
|
|
81
|
-
function D(e) {
|
|
82
|
-
var t, r;
|
|
83
|
-
y = !0, l = { x: e.clientX, y: e.clientY, tx: v.value, ty: p.value }, (r = (t = e.target).setPointerCapture) == null || r.call(t, e.pointerId);
|
|
77
|
+
const n = -e.deltaY > 0 ? 1.1 : 1 / 1.1;
|
|
78
|
+
m.value = Math.max(0.2, Math.min(8, m.value * n));
|
|
84
79
|
}
|
|
85
80
|
function E(e) {
|
|
86
|
-
|
|
81
|
+
var t, n;
|
|
82
|
+
p = !0, l = { x: e.clientX, y: e.clientY, tx: v.value, ty: y.value }, (n = (t = e.target).setPointerCapture) == null || n.call(t, e.pointerId);
|
|
83
|
+
}
|
|
84
|
+
function S(e) {
|
|
85
|
+
!p || !l || (v.value = l.tx + (e.clientX - l.x), y.value = l.ty + (e.clientY - l.y));
|
|
87
86
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
87
|
+
function _() {
|
|
88
|
+
p = !1, l = null;
|
|
90
89
|
}
|
|
91
|
-
|
|
90
|
+
V(C), $(() => {
|
|
92
91
|
f++;
|
|
93
92
|
});
|
|
94
|
-
function
|
|
95
|
-
return
|
|
93
|
+
function b(e, t) {
|
|
94
|
+
return r.t ? r.t(e) : t;
|
|
96
95
|
}
|
|
97
|
-
return (e, t) => (
|
|
96
|
+
return (e, t) => (h(), x("div", F, [
|
|
98
97
|
c("div", {
|
|
99
98
|
class: "filex-viewer-mermaid__pane",
|
|
100
|
-
onWheel:
|
|
101
|
-
onPointerdown:
|
|
102
|
-
onPointermove:
|
|
103
|
-
onPointerup:
|
|
104
|
-
onPointercancel:
|
|
99
|
+
onWheel: D,
|
|
100
|
+
onPointerdown: E,
|
|
101
|
+
onPointermove: S,
|
|
102
|
+
onPointerup: _,
|
|
103
|
+
onPointercancel: _
|
|
105
104
|
}, [
|
|
106
|
-
|
|
105
|
+
a.value ? (h(), x("div", K, [
|
|
107
106
|
t[0] || (t[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📊", -1)),
|
|
108
|
-
c("p", null, k(
|
|
109
|
-
])) : s.value ? (
|
|
107
|
+
c("p", null, k(a.value), 1)
|
|
108
|
+
])) : s.value ? (h(), x("div", N, [
|
|
110
109
|
t[1] || (t[1] = c("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
|
|
111
|
-
c("p", null, k(
|
|
110
|
+
c("p", null, k(b("viewer.loading", "Loading…")), 1)
|
|
112
111
|
])) : B("", !0),
|
|
113
112
|
H(c("div", {
|
|
114
113
|
ref_key: "surface",
|
|
115
114
|
ref: d,
|
|
116
115
|
class: "filex-viewer-mermaid__surface",
|
|
117
|
-
style: Y({ transform: `translate(${v.value}px, ${
|
|
116
|
+
style: Y({ transform: `translate(${v.value}px, ${y.value}px) scale(${m.value})` })
|
|
118
117
|
}, null, 4), [
|
|
119
|
-
[q, !s.value && !
|
|
118
|
+
[q, !s.value && !a.value]
|
|
120
119
|
])
|
|
121
120
|
], 32)
|
|
122
121
|
]));
|
|
123
122
|
}
|
|
124
|
-
})
|
|
123
|
+
});
|
|
125
124
|
export {
|
|
126
|
-
|
|
125
|
+
X as default
|
|
127
126
|
};
|
|
128
|
-
//# sourceMappingURL=MermaidViewer-
|
|
127
|
+
//# sourceMappingURL=MermaidViewer-DLmijDXo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MermaidViewer-DLmijDXo.js","sources":["../src/viewers/MermaidViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * MermaidViewer — render a `.mmd` / `.mermaid` source file.\n *\n * Lazy-imports the `mermaid` library (~150 KB gzipped). Source text is\n * fetched from `props.url` (with the auth headers from PreviewModal),\n * then rendered to SVG via `mermaid.render('id', src)`. The resulting\n * SVG node is inserted into a wrapper that supports pan + scale via\n * pure CSS transforms (no extra panzoom dep).\n */\nimport { onBeforeUnmount, onMounted, ref } from 'vue';\nimport { fetchViewerText } from '../composables/useViewerFetch';\n\nconst props = defineProps<{\n url: string;\n mime?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\nconst surface = ref<HTMLDivElement | null>(null);\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst scale = ref(1);\nconst tx = ref(0);\nconst ty = ref(0);\n\nlet dragging = false;\nlet dragStart: { x: number; y: number; tx: number; ty: number } | null = null;\nlet renderToken = 0;\n\nlet cachedMermaid: any = null;\nasync function ensureMermaid(): Promise<any | null> {\n if (cachedMermaid) return cachedMermaid;\n try {\n const mod = await import(/* @vite-ignore */ 'mermaid');\n cachedMermaid = mod.default ?? mod;\n cachedMermaid.initialize?.({\n startOnLoad: false,\n securityLevel: 'strict',\n theme: window.matchMedia?.('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'default',\n });\n return cachedMermaid;\n } catch {\n return null;\n }\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n const myToken = ++renderToken;\n\n const mermaid = await ensureMermaid();\n if (myToken !== renderToken) return;\n if (!mermaid) {\n error.value = props.t\n ? props.t('viewer.peer_not_installed')\n : 'Mermaid viewer requires `mermaid` — install or use download.';\n loading.value = false;\n return;\n }\n\n let src: string;\n try {\n src = await fetchViewerText({\n url: props.url,\n headers: props.authHeaders?.() ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'fetch failed';\n loading.value = false;\n return;\n }\n\n if (myToken !== renderToken) return;\n\n try {\n const id = `filex-mermaid-${Date.now()}`;\n const { svg } = await mermaid.render(id, src);\n if (myToken !== renderToken) return;\n if (surface.value) {\n surface.value.innerHTML = svg;\n const svgEl = surface.value.querySelector('svg');\n if (svgEl) {\n svgEl.style.maxWidth = '100%';\n svgEl.style.height = 'auto';\n }\n }\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'render failed';\n } finally {\n loading.value = false;\n }\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(8, scale.value * 1.25);\n}\nfunction zoomOut(): void {\n scale.value = Math.max(0.2, scale.value / 1.25);\n}\nfunction reset(): void {\n scale.value = 1;\n tx.value = 0;\n ty.value = 0;\n}\n\nfunction onWheel(ev: WheelEvent): void {\n if (!ev.ctrlKey && !ev.metaKey) return;\n ev.preventDefault();\n const delta = -ev.deltaY;\n const factor = delta > 0 ? 1.1 : 1 / 1.1;\n scale.value = Math.max(0.2, Math.min(8, scale.value * factor));\n}\n\nfunction onPointerDown(ev: PointerEvent): void {\n dragging = true;\n dragStart = { x: ev.clientX, y: ev.clientY, tx: tx.value, ty: ty.value };\n (ev.target as HTMLElement).setPointerCapture?.(ev.pointerId);\n}\nfunction onPointerMove(ev: PointerEvent): void {\n if (!dragging || !dragStart) return;\n tx.value = dragStart.tx + (ev.clientX - dragStart.x);\n ty.value = dragStart.ty + (ev.clientY - dragStart.y);\n}\nfunction onPointerUp(): void {\n dragging = false;\n dragStart = null;\n}\n\nonMounted(load);\nonBeforeUnmount(() => {\n renderToken++;\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-mermaid\">\n <div\n class=\"filex-viewer-mermaid__pane\"\n @wheel=\"onWheel\"\n @pointerdown=\"onPointerDown\"\n @pointermove=\"onPointerMove\"\n @pointerup=\"onPointerUp\"\n @pointercancel=\"onPointerUp\"\n >\n <div\n v-if=\"error\"\n class=\"filex-viewer-fallback\"\n >\n <span class=\"filex-viewer-fallback__icon\">📊</span>\n <p>{{ error }}</p>\n </div>\n <div\n v-else-if=\"loading\"\n class=\"filex-viewer-fallback\"\n >\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div\n v-show=\"!loading && !error\"\n ref=\"surface\"\n class=\"filex-viewer-mermaid__surface\"\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\n />\n </div>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-mermaid {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n}\n.filex-viewer-mermaid__bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 13px;\n}\n.filex-viewer-mermaid__zoom {\n min-width: 50px;\n text-align: center;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n}\n.filex-viewer-mermaid__pane {\n flex: 1;\n overflow: hidden;\n position: relative;\n cursor: grab;\n background: var(--fe-bg-elev, #f7f8fa);\n touch-action: none;\n}\n.filex-viewer-mermaid__pane:active {\n cursor: grabbing;\n}\n.filex-viewer-mermaid__surface {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n transform-origin: center center;\n transition: transform 0.05s linear;\n user-select: none;\n}\n.filex-viewer-mermaid__surface svg {\n max-width: 90%;\n max-height: 90%;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n.filex-viewer-btn {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-btn:hover:not(:disabled) {\n background: var(--fe-bg-hover, #edf0f5);\n}\n</style>\n"],"names":["props","__props","surface","ref","error","loading","scale","tx","ty","dragging","dragStart","renderToken","cachedMermaid","ensureMermaid","mod","_b","_a","load","myToken","mermaid","src","fetchViewerText","err","id","svg","svgEl","onWheel","ev","factor","onPointerDown","onPointerMove","onPointerUp","onMounted","onBeforeUnmount","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_hoisted_3","_normalizeStyle","_vShow"],"mappings":"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"}
|