@brftech/filex-core 0.1.56

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/dist/ArchiveViewer-CJdaw5x3.js +99 -0
  4. package/dist/ArchiveViewer-CJdaw5x3.js.map +1 -0
  5. package/dist/CsvViewer-QYx_tePQ.js +132 -0
  6. package/dist/CsvViewer-QYx_tePQ.js.map +1 -0
  7. package/dist/DrawioViewer-GWt0TyB7.js +141 -0
  8. package/dist/DrawioViewer-GWt0TyB7.js.map +1 -0
  9. package/dist/EpubViewer-Je0ywklQ.js +146 -0
  10. package/dist/EpubViewer-Je0ywklQ.js.map +1 -0
  11. package/dist/IpynbViewer-TsB4gqP-.js +175 -0
  12. package/dist/IpynbViewer-TsB4gqP-.js.map +1 -0
  13. package/dist/MermaidViewer-CXfeDS-7.js +128 -0
  14. package/dist/MermaidViewer-CXfeDS-7.js.map +1 -0
  15. package/dist/PsdViewer-VtPpxKVe.js +113 -0
  16. package/dist/PsdViewer-VtPpxKVe.js.map +1 -0
  17. package/dist/TiffViewer-OINn9bbb.js +133 -0
  18. package/dist/TiffViewer-OINn9bbb.js.map +1 -0
  19. package/dist/UTIF-Cjsrlm0l.js +3104 -0
  20. package/dist/UTIF-Cjsrlm0l.js.map +1 -0
  21. package/dist/Viewer3D-xvvyiWHd.js +61 -0
  22. package/dist/Viewer3D-xvvyiWHd.js.map +1 -0
  23. package/dist/_commonjsHelpers-DaMA6jEr.js +9 -0
  24. package/dist/_commonjsHelpers-DaMA6jEr.js.map +1 -0
  25. package/dist/filex-core.js +26 -0
  26. package/dist/filex-core.js.map +1 -0
  27. package/dist/filex-core.umd.cjs +285 -0
  28. package/dist/filex-core.umd.cjs.map +1 -0
  29. package/dist/index-CmSYzt6L.js +5404 -0
  30. package/dist/index-CmSYzt6L.js.map +1 -0
  31. package/dist/index-UFULWo35.js +10736 -0
  32. package/dist/index-UFULWo35.js.map +1 -0
  33. package/dist/index.d.ts +1089 -0
  34. package/dist/katex-yuB6V-q6.js +11616 -0
  35. package/dist/katex-yuB6V-q6.js.map +1 -0
  36. package/dist/papaparse.min-VB1HBwYX.js +441 -0
  37. package/dist/papaparse.min-VB1HBwYX.js.map +1 -0
  38. package/dist/style.css +1 -0
  39. package/dist/useViewerFetch-czqbd2Lj.js +25 -0
  40. package/dist/useViewerFetch-czqbd2Lj.js.map +1 -0
  41. package/package.json +113 -0
  42. package/src/FileExplorer.vue +1872 -0
  43. package/src/components/Breadcrumb.vue +282 -0
  44. package/src/components/ContextMenu.vue +152 -0
  45. package/src/components/GridView.vue +166 -0
  46. package/src/components/ListView.vue +212 -0
  47. package/src/components/PendingOpsTray.vue +91 -0
  48. package/src/components/RecentlyOpened.vue +155 -0
  49. package/src/components/StarButton.vue +101 -0
  50. package/src/components/TagPicker.vue +184 -0
  51. package/src/components/Toolbar.vue +220 -0
  52. package/src/components/UploadProgress.vue +78 -0
  53. package/src/composables/useFileApi.ts +692 -0
  54. package/src/composables/useKeyboardShortcuts.ts +144 -0
  55. package/src/composables/useLocale.ts +60 -0
  56. package/src/composables/useMonacoLoader.ts +98 -0
  57. package/src/composables/usePendingOps.ts +200 -0
  58. package/src/composables/useSelection.ts +81 -0
  59. package/src/composables/useUploadChunked.ts +250 -0
  60. package/src/composables/useViewerFetch.ts +58 -0
  61. package/src/index.ts +80 -0
  62. package/src/locales/en.ts +122 -0
  63. package/src/locales/index.ts +12 -0
  64. package/src/locales/tr.ts +122 -0
  65. package/src/modals/ConvertModal.vue +254 -0
  66. package/src/modals/DeleteConfirmModal.vue +32 -0
  67. package/src/modals/Modal.vue +104 -0
  68. package/src/modals/NewFolderModal.vue +64 -0
  69. package/src/modals/PermissionsModal.vue +815 -0
  70. package/src/modals/PreviewModal.vue +1070 -0
  71. package/src/modals/RenameModal.vue +58 -0
  72. package/src/modals/ShareModal.vue +135 -0
  73. package/src/styles/base.css +1224 -0
  74. package/src/styles/variables.css +90 -0
  75. package/src/types/ExplorerConfig.ts +282 -0
  76. package/src/types/FileNode.ts +136 -0
  77. package/src/types/index.ts +27 -0
  78. package/src/types/peers.d.ts +45 -0
  79. package/src/viewers/ArchiveViewer.vue +186 -0
  80. package/src/viewers/CsvViewer.vue +319 -0
  81. package/src/viewers/DrawioViewer.vue +243 -0
  82. package/src/viewers/EpubViewer.vue +307 -0
  83. package/src/viewers/IpynbViewer.vue +365 -0
  84. package/src/viewers/MermaidViewer.vue +259 -0
  85. package/src/viewers/PdfViewer.vue +562 -0
  86. package/src/viewers/PsdViewer.vue +264 -0
  87. package/src/viewers/TiffViewer.vue +273 -0
  88. package/src/viewers/Viewer3D.vue +120 -0
@@ -0,0 +1,146 @@
1
+ import { defineComponent as U, ref as n, onMounted as L, onBeforeUnmount as V, watch as F, openBlock as u, createElementBlock as i, createElementVNode as c, toDisplayString as b, Fragment as H, createCommentVNode as g } from "vue";
2
+ import { _ as R } from "./index-CmSYzt6L.js";
3
+ const S = {
4
+ key: 0,
5
+ class: "filex-viewer-fallback"
6
+ }, z = {
7
+ key: 0,
8
+ class: "filex-viewer-epub__nav"
9
+ }, A = ["disabled"], D = ["disabled"], N = {
10
+ key: 1,
11
+ class: "filex-viewer-epub__loading"
12
+ }, T = /* @__PURE__ */ U({
13
+ __name: "EpubViewer",
14
+ props: {
15
+ url: {},
16
+ mime: {},
17
+ ext: {},
18
+ t: { type: Function },
19
+ authHeaders: { type: Function },
20
+ authCredentials: {}
21
+ },
22
+ setup(k) {
23
+ const r = k, x = n(null), v = n(null), o = n(null), E = n([]);
24
+ n(!1);
25
+ const B = n(100), s = n(!1), f = n(!0);
26
+ let a = null, e = null;
27
+ async function p() {
28
+ f.value = !0, s.value = !1, o.value = null;
29
+ let t = null;
30
+ try {
31
+ t = await import(
32
+ /* @vite-ignore */
33
+ "epubjs"
34
+ );
35
+ } catch {
36
+ o.value = r.t ? r.t("viewer.peer_not_installed") : "EPUB viewer requires `epubjs` — install or use download.", f.value = !1;
37
+ return;
38
+ }
39
+ try {
40
+ const l = t.default ?? t;
41
+ let m = r.url;
42
+ if (r.authHeaders) {
43
+ const P = r.authHeaders(), d = await fetch(r.url, {
44
+ headers: P,
45
+ credentials: r.authCredentials || "same-origin"
46
+ });
47
+ if (!d.ok) throw new Error(`${d.status} ${d.statusText}`);
48
+ m = await d.arrayBuffer();
49
+ }
50
+ if (a = l(m), !v.value)
51
+ throw new Error("EPUB mount target missing");
52
+ e = a.renderTo(v.value, {
53
+ width: "100%",
54
+ height: "100%",
55
+ flow: "paginated",
56
+ manager: "default"
57
+ }), await e.display(), e.themes.fontSize(B.value + "%");
58
+ const w = await a.loaded.navigation;
59
+ E.value = (w == null ? void 0 : w.toc) ?? [], s.value = !0;
60
+ } catch (l) {
61
+ o.value = l instanceof Error ? l.message : "EPUB load failed";
62
+ } finally {
63
+ f.value = !1;
64
+ }
65
+ }
66
+ function y() {
67
+ var t;
68
+ (t = e == null ? void 0 : e.next) == null || t.call(e);
69
+ }
70
+ function _() {
71
+ var t;
72
+ (t = e == null ? void 0 : e.prev) == null || t.call(e);
73
+ }
74
+ function h(t) {
75
+ t.key === "ArrowRight" || t.key === "PageDown" ? y() : (t.key === "ArrowLeft" || t.key === "PageUp") && _();
76
+ }
77
+ L(() => {
78
+ p(), window.addEventListener("keydown", h);
79
+ }), V(() => {
80
+ var t, l;
81
+ window.removeEventListener("keydown", h);
82
+ try {
83
+ (t = e == null ? void 0 : e.destroy) == null || t.call(e);
84
+ } catch {
85
+ }
86
+ try {
87
+ (l = a == null ? void 0 : a.destroy) == null || l.call(a);
88
+ } catch {
89
+ }
90
+ e = null, a = null;
91
+ }), F(
92
+ () => r.url,
93
+ () => {
94
+ if (e)
95
+ try {
96
+ e.destroy();
97
+ } catch {
98
+ }
99
+ if (a)
100
+ try {
101
+ a.destroy();
102
+ } catch {
103
+ }
104
+ a = null, e = null, p();
105
+ }
106
+ );
107
+ function C(t, l) {
108
+ return r.t ? r.t(t) : l;
109
+ }
110
+ return (t, l) => (u(), i("div", {
111
+ ref_key: "root",
112
+ ref: x,
113
+ class: "filex-viewer-epub"
114
+ }, [
115
+ o.value ? (u(), i("div", S, [
116
+ l[0] || (l[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📖", -1)),
117
+ c("p", null, b(o.value), 1)
118
+ ])) : (u(), i(H, { key: 1 }, [
119
+ c("div", {
120
+ ref_key: "containerRef",
121
+ ref: v,
122
+ class: "filex-viewer-epub__rendition"
123
+ }, null, 512),
124
+ s.value ? (u(), i("div", z, [
125
+ c("button", {
126
+ type: "button",
127
+ class: "filex-viewer-btn",
128
+ onClick: _,
129
+ disabled: !s.value
130
+ }, "‹", 8, A),
131
+ c("button", {
132
+ type: "button",
133
+ class: "filex-viewer-btn",
134
+ onClick: y,
135
+ disabled: !s.value
136
+ }, "›", 8, D)
137
+ ])) : g("", !0),
138
+ f.value ? (u(), i("div", N, b(C("viewer.loading", "Loading…")), 1)) : g("", !0)
139
+ ], 64))
140
+ ], 512));
141
+ }
142
+ }), q = /* @__PURE__ */ R(T, [["__scopeId", "data-v-f9b72a2c"]]);
143
+ export {
144
+ q as default
145
+ };
146
+ //# sourceMappingURL=EpubViewer-Je0ywklQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EpubViewer-Je0ywklQ.js","sources":["../src/viewers/EpubViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * EpubViewer — flowable EPUB reader via `epubjs`.\r\n *\r\n * Lazy-imports `epubjs` (~80 KB gzipped). epub.js renders the publication\r\n * inside an iframe (default `flow: 'paginated'`), but we use it in\r\n * scrolled-doc mode only when the user toggles the \"fit-width\" flag — by\r\n * default we keep paginated since that matches reader-app expectations.\r\n *\r\n * UX:\r\n * - prev/next page buttons (also keyboard arrow keys via composable)\r\n * - collapsible TOC sidebar (built from `book.loaded.navigation`)\r\n * - font size +/- (Themes API)\r\n * - graceful fallback if peer not installed\r\n */\r\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\ninterface TocNode {\r\n href: string;\r\n label: string;\r\n subitems?: TocNode[];\r\n}\r\n\r\nconst root = ref<HTMLDivElement | null>(null);\r\nconst containerRef = ref<HTMLDivElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst toc = ref<TocNode[]>([]);\r\nconst tocOpen = ref(false);\r\nconst fontSize = ref(100);\r\nconst ready = ref(false);\r\nconst loading = ref(true);\r\n\r\nlet book: any = null;\r\nlet rendition: any = null;\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n ready.value = false;\r\n error.value = null;\r\n let mod: any = null;\r\n try {\r\n mod = await import(/* @vite-ignore */ 'epubjs');\r\n } catch {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'EPUB viewer requires `epubjs` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n try {\r\n const Epub = mod.default ?? mod;\r\n // epub.js wants a URL (it then fetches with XHR). When the host\r\n // site requires auth headers we have to load the file ourselves\r\n // and pass an ArrayBuffer instead.\r\n let source: string | ArrayBuffer = props.url;\r\n if (props.authHeaders) {\r\n const headers = props.authHeaders();\r\n const res = await fetch(props.url, {\r\n headers,\r\n credentials: props.authCredentials || 'same-origin',\r\n });\r\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\r\n source = await res.arrayBuffer();\r\n }\r\n book = Epub(source);\r\n if (!containerRef.value) {\r\n throw new Error('EPUB mount target missing');\r\n }\r\n rendition = book.renderTo(containerRef.value, {\r\n width: '100%',\r\n height: '100%',\r\n flow: 'paginated',\r\n manager: 'default',\r\n });\r\n await rendition.display();\r\n rendition.themes.fontSize(fontSize.value + '%');\r\n const nav = await book.loaded.navigation;\r\n toc.value = (nav?.toc ?? []) as TocNode[];\r\n ready.value = true;\r\n } catch (err) {\r\n error.value =\r\n err instanceof Error ? err.message : 'EPUB load failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction next(): void {\r\n rendition?.next?.();\r\n}\r\nfunction prev(): void {\r\n rendition?.prev?.();\r\n}\r\nfunction gotoHref(href: string): void {\r\n rendition?.display?.(href);\r\n tocOpen.value = false;\r\n}\r\nfunction bigger(): void {\r\n fontSize.value = Math.min(200, fontSize.value + 10);\r\n rendition?.themes?.fontSize(fontSize.value + '%');\r\n}\r\nfunction smaller(): void {\r\n fontSize.value = Math.max(60, fontSize.value - 10);\r\n rendition?.themes?.fontSize(fontSize.value + '%');\r\n}\r\n\r\nfunction onKey(ev: KeyboardEvent): void {\r\n if (ev.key === 'ArrowRight' || ev.key === 'PageDown') next();\r\n else if (ev.key === 'ArrowLeft' || ev.key === 'PageUp') prev();\r\n}\r\n\r\nonMounted(() => {\r\n load();\r\n window.addEventListener('keydown', onKey);\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n window.removeEventListener('keydown', onKey);\r\n try {\r\n rendition?.destroy?.();\r\n } catch {\r\n /* ignore */\r\n }\r\n try {\r\n book?.destroy?.();\r\n } catch {\r\n /* ignore */\r\n }\r\n rendition = null;\r\n book = null;\r\n});\r\n\r\nwatch(\r\n () => props.url,\r\n () => {\r\n if (rendition) {\r\n try {\r\n rendition.destroy();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n if (book) {\r\n try {\r\n book.destroy();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n book = null;\r\n rendition = null;\r\n load();\r\n },\r\n);\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div ref=\"root\" class=\"filex-viewer-epub\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📖</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <template v-else>\r\n <div ref=\"containerRef\" class=\"filex-viewer-epub__rendition\" />\r\n <div v-if=\"ready\" class=\"filex-viewer-epub__nav\">\r\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"prev\" :disabled=\"!ready\">‹</button>\r\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"next\" :disabled=\"!ready\">›</button>\r\n </div>\r\n <div v-if=\"loading\" class=\"filex-viewer-epub__loading\">\r\n {{ tt('viewer.loading', 'Loading…') }}\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-epub__nav {\r\n position: absolute;\r\n bottom: 12px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n display: flex;\r\n gap: 8px;\r\n padding: 4px 8px;\r\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n border-radius: 6px;\r\n backdrop-filter: blur(4px);\r\n}\r\n.filex-viewer-epub {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n position: relative;\r\n}\r\n.filex-viewer-epub__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-spacer { flex: 1; }\r\n.filex-viewer-epub__fs {\r\n display: inline-block;\r\n min-width: 40px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-epub__main {\r\n flex: 1;\r\n min-height: 0;\r\n display: flex;\r\n}\r\n.filex-viewer-epub__rendition {\r\n flex: 1;\r\n min-height: 0;\r\n}\r\n.filex-viewer-epub__toc {\r\n width: 260px;\r\n border-right: 1px solid var(--fe-border, #e2e6ed);\r\n overflow-y: auto;\r\n padding: 12px 0;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n}\r\n.filex-viewer-epub__toc ul {\r\n list-style: none;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n.filex-viewer-epub__toc-link {\r\n display: block;\r\n width: 100%;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n padding: 6px 14px;\r\n font: inherit;\r\n color: inherit;\r\n cursor: pointer;\r\n}\r\n.filex-viewer-epub__toc-link:hover {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-epub__toc-link.is-child {\r\n padding-left: 28px;\r\n color: var(--fe-text-muted, #5a6475);\r\n font-size: 12px;\r\n}\r\n.filex-viewer-epub__loading {\r\n position: absolute;\r\n inset: auto 0 0 0;\r\n text-align: center;\r\n padding: 6px;\r\n background: rgba(0, 0, 0, 0.05);\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-btn:disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n}\r\n</style>\r\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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"}
@@ -0,0 +1,175 @@
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 V } from "vue";
2
+ import { f as z } from "./useViewerFetch-czqbd2Lj.js";
3
+ import { e as G, _ as K } from "./index-CmSYzt6L.js";
4
+ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pane" }, W = {
5
+ key: 0,
6
+ class: "filex-viewer-fallback"
7
+ }, X = {
8
+ key: 1,
9
+ class: "filex-viewer-fallback"
10
+ }, Y = { key: 2 }, Z = ["data-type"], ee = { class: "filex-viewer-ipynb__exec" }, te = { class: "filex-viewer-ipynb__src hljs" }, ne = ["innerHTML"], ae = { key: 1 }, re = {
11
+ key: 0,
12
+ class: "filex-viewer-ipynb__outputs"
13
+ }, le = ["src", "alt"], ie = ["innerHTML"], se = ["data-type"], ue = ["innerHTML"], oe = {
14
+ key: 1,
15
+ class: "filex-viewer-ipynb__md-raw"
16
+ }, ce = {
17
+ key: 2,
18
+ class: "filex-viewer-ipynb__src"
19
+ }, de = /* @__PURE__ */ J({
20
+ __name: "IpynbViewer",
21
+ props: {
22
+ url: {},
23
+ ext: {},
24
+ t: { type: Function },
25
+ authHeaders: { type: Function },
26
+ authCredentials: {}
27
+ },
28
+ setup(B) {
29
+ const u = B, o = _([]), M = _("python"), f = _(null), y = _(!0), w = _(/* @__PURE__ */ new Map()), k = _(/* @__PURE__ */ new Map());
30
+ let v = 0, x = null, g = null;
31
+ async function N() {
32
+ if (g !== null) return g || null;
33
+ try {
34
+ const e = await import(
35
+ /* @vite-ignore */
36
+ "markdown-it"
37
+ ), t = e.default ?? e;
38
+ return g = new t({ html: !1, linkify: !0, breaks: !0 }), g;
39
+ } catch {
40
+ return g = !1, null;
41
+ }
42
+ }
43
+ function s(e) {
44
+ return Array.isArray(e) ? e.join("") : e ?? "";
45
+ }
46
+ async function H() {
47
+ var i, m, C, S;
48
+ y.value = !0, f.value = null, o.value = [], w.value = /* @__PURE__ */ new Map(), k.value = /* @__PURE__ */ new Map();
49
+ const e = ++v;
50
+ let t;
51
+ try {
52
+ t = await z({
53
+ url: u.url,
54
+ headers: ((i = u.authHeaders) == null ? void 0 : i.call(u)) ?? {},
55
+ credentials: u.authCredentials
56
+ });
57
+ } catch (l) {
58
+ f.value = l instanceof Error ? l.message : "fetch failed", y.value = !1;
59
+ return;
60
+ }
61
+ if (e !== v) return;
62
+ let n;
63
+ try {
64
+ n = JSON.parse(t);
65
+ } catch {
66
+ f.value = "Invalid notebook JSON", y.value = !1;
67
+ return;
68
+ }
69
+ if (o.value = Array.isArray(n.cells) ? n.cells : [], M.value = ((C = (m = n.metadata) == null ? void 0 : m.kernelspec) == null ? void 0 : C.language) || "python", x = await G(), e !== v) return;
70
+ if (x) {
71
+ const l = x.default ?? x, b = (S = l.getLanguage) != null && S.call(l, M.value) ? M.value : null;
72
+ o.value.forEach((j, F) => {
73
+ if (j.cell_type === "code") {
74
+ const A = s(j.source);
75
+ try {
76
+ const O = b ? l.highlight(A, { language: b, ignoreIllegals: !0 }) : l.highlightAuto(A);
77
+ w.value.set(F, O.value);
78
+ } catch {
79
+ }
80
+ }
81
+ });
82
+ }
83
+ const c = await N();
84
+ e === v && (c && o.value.forEach((l, b) => {
85
+ if (l.cell_type === "markdown")
86
+ try {
87
+ k.value.set(b, c.render(s(l.source)));
88
+ } catch {
89
+ }
90
+ }), y.value = !1);
91
+ }
92
+ function T(e) {
93
+ var t;
94
+ return e ? e.output_type === "stream" ? s(e.text) : e.output_type === "error" ? [e.ename, e.evalue, ...e.traceback || []].filter(Boolean).join(`
95
+ `) : (e.output_type === "execute_result" || e.output_type === "display_data") && (t = e.data) != null && t["text/plain"] ? s(e.data["text/plain"]) : null : null;
96
+ }
97
+ function L(e) {
98
+ if (!(e != null && e.data)) return null;
99
+ if (e.data["image/png"]) return `data:image/png;base64,${e.data["image/png"]}`;
100
+ if (e.data["image/jpeg"]) return `data:image/jpeg;base64,${e.data["image/jpeg"]}`;
101
+ if (e.data["image/svg+xml"]) {
102
+ const t = s(e.data["image/svg+xml"]);
103
+ return `data:image/svg+xml;utf8,${encodeURIComponent(t)}`;
104
+ }
105
+ return null;
106
+ }
107
+ function I(e) {
108
+ return e != null && e.data && e.data["text/html"] ? s(e.data["text/html"]).replace(/<script[\s\S]*?<\/script>/gi, "") : null;
109
+ }
110
+ R(H), U(() => {
111
+ v++;
112
+ }), D(() => u.url, H), q(() => {
113
+ const e = o.value.filter((n) => n.cell_type === "code").length, t = o.value.filter((n) => n.cell_type === "markdown").length;
114
+ return { code: e, md: t, total: o.value.length };
115
+ });
116
+ function $(e, t) {
117
+ return u.t ? u.t(e) : t;
118
+ }
119
+ return (e, t) => (a(), r("div", P, [
120
+ d("div", Q, [
121
+ f.value ? (a(), r("div", W, [
122
+ t[0] || (t[0] = d("span", { class: "filex-viewer-fallback__icon" }, "📓", -1)),
123
+ d("p", null, p(f.value), 1)
124
+ ])) : y.value ? (a(), r("div", X, [
125
+ t[1] || (t[1] = d("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
126
+ d("p", null, p($("viewer.loading", "Loading…")), 1)
127
+ ])) : (a(), r("div", Y, [
128
+ (a(!0), r(h, null, E(o.value, (n, c) => (a(), r("div", {
129
+ key: c,
130
+ class: "filex-viewer-ipynb__cell",
131
+ "data-type": n.cell_type
132
+ }, [
133
+ n.cell_type === "code" ? (a(), r(h, { key: 0 }, [
134
+ d("div", ee, " In [" + p(n.execution_count ?? " ") + "]: ", 1),
135
+ d("pre", te, [
136
+ w.value.get(c) ? (a(), r("code", {
137
+ key: 0,
138
+ innerHTML: w.value.get(c)
139
+ }, null, 8, ne)) : (a(), r("code", ae, p(s(n.source)), 1))
140
+ ]),
141
+ n.outputs && n.outputs.length ? (a(), r("div", re, [
142
+ (a(!0), r(h, null, E(n.outputs, (i, m) => (a(), r(h, { key: m }, [
143
+ L(i) ? (a(), r("img", {
144
+ key: 0,
145
+ src: L(i) || "",
146
+ class: "filex-viewer-ipynb__img",
147
+ alt: `output ${m}`
148
+ }, null, 8, le)) : I(i) ? (a(), r("div", {
149
+ key: 1,
150
+ class: "filex-viewer-ipynb__html",
151
+ innerHTML: I(i)
152
+ }, null, 8, ie)) : T(i) ? (a(), r("pre", {
153
+ key: 2,
154
+ class: "filex-viewer-ipynb__out",
155
+ "data-type": i.output_type
156
+ }, p(T(i)), 9, se)) : V("", !0)
157
+ ], 64))), 128))
158
+ ])) : V("", !0)
159
+ ], 64)) : n.cell_type === "markdown" ? (a(), r(h, { key: 1 }, [
160
+ k.value.get(c) ? (a(), r("div", {
161
+ key: 0,
162
+ class: "filex-viewer-ipynb__md",
163
+ innerHTML: k.value.get(c)
164
+ }, null, 8, ue)) : (a(), r("pre", oe, p(s(n.source)), 1))
165
+ ], 64)) : (a(), r("pre", ce, p(s(n.source)), 1))
166
+ ], 8, Z))), 128))
167
+ ]))
168
+ ])
169
+ ]));
170
+ }
171
+ }), ye = /* @__PURE__ */ K(de, [["__scopeId", "data-v-631b8223"]]);
172
+ export {
173
+ ye as default
174
+ };
175
+ //# sourceMappingURL=IpynbViewer-TsB4gqP-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IpynbViewer-TsB4gqP-.js","sources":["../src/viewers/IpynbViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.\r\n *\r\n * Pure-JS render — no peer dependency required:\r\n * - code cells → `<pre><code>` (highlight.js when available)\r\n * - markdown cells → markdown-it when available, plain `<pre>` otherwise\r\n * - output cells → text (stream / display_data 'text/plain'),\r\n * images (display_data 'image/png' base64),\r\n * HTML (display_data 'text/html', sanitized via\r\n * element-only insertion — no script tags)\r\n *\r\n * Source list / output count counters at the top so a 200-cell\r\n * notebook doesn't surprise the user.\r\n */\r\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\nimport { ensureHighlight } from '../composables/useMonacoLoader';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\ninterface Cell {\r\n cell_type: 'code' | 'markdown' | 'raw' | string;\r\n source: string | string[];\r\n outputs?: any[];\r\n execution_count?: number | null;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\ninterface Notebook {\r\n cells: Cell[];\r\n metadata?: { kernelspec?: { language?: string; name?: string } };\r\n}\r\n\r\nconst cells = ref<Cell[]>([]);\r\nconst language = ref<string>('python');\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst renderedSources = ref<Map<number, string>>(new Map());\r\nconst renderedMarkdown = ref<Map<number, string>>(new Map());\r\n\r\nlet renderToken = 0;\r\nlet highlight: any = null;\r\nlet mdRenderer: any = null;\r\n\r\nasync function ensureMd(): Promise<any | null> {\r\n if (mdRenderer !== null) return mdRenderer || null;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'markdown-it');\r\n const Md = (mod as any).default ?? mod;\r\n mdRenderer = new Md({ html: false, linkify: true, breaks: true });\r\n return mdRenderer;\r\n } catch {\r\n mdRenderer = false;\r\n return null;\r\n }\r\n}\r\n\r\nfunction joinSource(source: string | string[]): string {\r\n return Array.isArray(source) ? source.join('') : (source ?? '');\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n cells.value = [];\r\n renderedSources.value = new Map();\r\n renderedMarkdown.value = new Map();\r\n const myToken = ++renderToken;\r\n\r\n let raw: string;\r\n try {\r\n raw = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n if (myToken !== renderToken) return;\r\n\r\n let nb: Notebook;\r\n try {\r\n nb = JSON.parse(raw);\r\n } catch (err) {\r\n error.value = 'Invalid notebook JSON';\r\n loading.value = false;\r\n return;\r\n }\r\n cells.value = Array.isArray(nb.cells) ? nb.cells : [];\r\n language.value = nb.metadata?.kernelspec?.language || 'python';\r\n\r\n // Best-effort hljs highlight per code cell.\r\n highlight = (await ensureHighlight()) as any;\r\n if (myToken !== renderToken) return;\r\n if (highlight) {\r\n const hljs = highlight.default ?? highlight;\r\n const langOk = hljs.getLanguage?.(language.value) ? language.value : null;\r\n cells.value.forEach((cell, idx) => {\r\n if (cell.cell_type === 'code') {\r\n const text = joinSource(cell.source);\r\n try {\r\n const result = langOk\r\n ? hljs.highlight(text, { language: langOk, ignoreIllegals: true })\r\n : hljs.highlightAuto(text);\r\n renderedSources.value.set(idx, result.value);\r\n } catch {\r\n /* leave unrendered */\r\n }\r\n }\r\n });\r\n }\r\n\r\n const md = await ensureMd();\r\n if (myToken !== renderToken) return;\r\n if (md) {\r\n cells.value.forEach((cell, idx) => {\r\n if (cell.cell_type === 'markdown') {\r\n try {\r\n renderedMarkdown.value.set(idx, md.render(joinSource(cell.source)));\r\n } catch {\r\n /* leave plain */\r\n }\r\n }\r\n });\r\n }\r\n\r\n loading.value = false;\r\n}\r\n\r\nfunction outputText(out: any): string | null {\r\n if (!out) return null;\r\n if (out.output_type === 'stream') {\r\n return joinSource(out.text);\r\n }\r\n if (out.output_type === 'error') {\r\n return [out.ename, out.evalue, ...(out.traceback || [])]\r\n .filter(Boolean)\r\n .join('\\n');\r\n }\r\n if (out.output_type === 'execute_result' || out.output_type === 'display_data') {\r\n if (out.data?.['text/plain']) {\r\n return joinSource(out.data['text/plain']);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction outputImage(out: any): string | null {\r\n if (!out?.data) return null;\r\n if (out.data['image/png']) return `data:image/png;base64,${out.data['image/png']}`;\r\n if (out.data['image/jpeg']) return `data:image/jpeg;base64,${out.data['image/jpeg']}`;\r\n if (out.data['image/svg+xml']) {\r\n const svg = joinSource(out.data['image/svg+xml']);\r\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;\r\n }\r\n return null;\r\n}\r\n\r\nfunction outputHtml(out: any): string | null {\r\n if (!out?.data) return null;\r\n if (out.data['text/html']) {\r\n const html = joinSource(out.data['text/html']);\r\n // Strip <script> for safety — outputs from arbitrary notebooks.\r\n return html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\r\n }\r\n return null;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n});\r\nwatch(() => props.url, load);\r\n\r\nconst stats = computed(() => {\r\n const codeCount = cells.value.filter((c) => c.cell_type === 'code').length;\r\n const mdCount = cells.value.filter((c) => c.cell_type === 'markdown').length;\r\n return { code: codeCount, md: mdCount, total: cells.value.length };\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-ipynb\">\r\n <div class=\"filex-viewer-ipynb__pane\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📓</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <div v-else>\r\n <div\r\n v-for=\"(cell, idx) in cells\"\r\n :key=\"idx\"\r\n class=\"filex-viewer-ipynb__cell\"\r\n :data-type=\"cell.cell_type\"\r\n >\r\n <template v-if=\"cell.cell_type === 'code'\">\r\n <div class=\"filex-viewer-ipynb__exec\">\r\n In [{{ cell.execution_count ?? ' ' }}]:\r\n </div>\r\n <pre class=\"filex-viewer-ipynb__src hljs\"><code\r\n v-if=\"renderedSources.get(idx)\"\r\n v-html=\"renderedSources.get(idx)\"\r\n /><code v-else>{{ joinSource(cell.source) }}</code></pre>\r\n <div v-if=\"cell.outputs && cell.outputs.length\" class=\"filex-viewer-ipynb__outputs\">\r\n <template v-for=\"(out, j) in cell.outputs\" :key=\"j\">\r\n <img\r\n v-if=\"outputImage(out)\"\r\n :src=\"outputImage(out) || ''\"\r\n class=\"filex-viewer-ipynb__img\"\r\n :alt=\"`output ${j}`\"\r\n />\r\n <div\r\n v-else-if=\"outputHtml(out)\"\r\n class=\"filex-viewer-ipynb__html\"\r\n v-html=\"outputHtml(out)\"\r\n />\r\n <pre\r\n v-else-if=\"outputText(out)\"\r\n class=\"filex-viewer-ipynb__out\"\r\n :data-type=\"out.output_type\"\r\n >{{ outputText(out) }}</pre>\r\n </template>\r\n </div>\r\n </template>\r\n\r\n <template v-else-if=\"cell.cell_type === 'markdown'\">\r\n <div\r\n v-if=\"renderedMarkdown.get(idx)\"\r\n class=\"filex-viewer-ipynb__md\"\r\n v-html=\"renderedMarkdown.get(idx)\"\r\n />\r\n <pre v-else class=\"filex-viewer-ipynb__md-raw\">{{ joinSource(cell.source) }}</pre>\r\n </template>\r\n\r\n <template v-else>\r\n <pre class=\"filex-viewer-ipynb__src\">{{ joinSource(cell.source) }}</pre>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-ipynb {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-ipynb__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-ipynb__lang {\r\n font-family: var(--fe-font-mono, monospace);\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n}\r\n.filex-viewer-ipynb__pane {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 16px 24px;\r\n}\r\n.filex-viewer-ipynb__cell {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n border-radius: 6px;\r\n margin-bottom: 16px;\r\n overflow: hidden;\r\n}\r\n.filex-viewer-ipynb__cell[data-type=\"code\"] {\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n}\r\n.filex-viewer-ipynb__exec {\r\n padding: 4px 12px;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 11px;\r\n color: var(--fe-text-muted, #5a6475);\r\n background: rgba(0, 0, 0, 0.04);\r\n}\r\n.filex-viewer-ipynb__src {\r\n margin: 0;\r\n padding: 12px;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n line-height: 1.5;\r\n white-space: pre;\r\n overflow-x: auto;\r\n}\r\n.filex-viewer-ipynb__outputs {\r\n border-top: 1px dashed var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n padding: 8px 12px;\r\n}\r\n.filex-viewer-ipynb__out {\r\n margin: 0;\r\n padding: 4px 0;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n white-space: pre-wrap;\r\n word-wrap: break-word;\r\n}\r\n.filex-viewer-ipynb__out[data-type=\"error\"] {\r\n color: var(--fe-danger, #dc2626);\r\n}\r\n.filex-viewer-ipynb__img {\r\n display: block;\r\n max-width: 100%;\r\n height: auto;\r\n margin: 8px 0;\r\n}\r\n.filex-viewer-ipynb__html {\r\n font-size: 13px;\r\n}\r\n.filex-viewer-ipynb__md {\r\n padding: 12px 16px;\r\n font-size: 14px;\r\n line-height: 1.6;\r\n}\r\n.filex-viewer-ipynb__md-raw {\r\n padding: 12px;\r\n margin: 0;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n white-space: pre-wrap;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n</style>\r\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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"}
@@ -0,0 +1,128 @@
1
+ import { defineComponent as L, ref as u, onMounted as T, onBeforeUnmount as $, openBlock as _, createElementBlock as x, createElementVNode as c, toDisplayString as k, createCommentVNode as B, withDirectives as H, normalizeStyle as Y, vShow as q } from "vue";
2
+ import { f as z } from "./useViewerFetch-czqbd2Lj.js";
3
+ import { _ as F } from "./index-CmSYzt6L.js";
4
+ const I = { class: "filex-viewer-mermaid" }, K = {
5
+ key: 0,
6
+ class: "filex-viewer-fallback"
7
+ }, N = {
8
+ key: 1,
9
+ class: "filex-viewer-fallback"
10
+ }, U = /* @__PURE__ */ L({
11
+ __name: "MermaidViewer",
12
+ props: {
13
+ url: {},
14
+ mime: {},
15
+ ext: {},
16
+ t: { type: Function },
17
+ authHeaders: { type: Function },
18
+ authCredentials: {}
19
+ },
20
+ setup(M) {
21
+ const a = M, d = u(null), n = u(null), s = u(!0), m = u(1), v = u(0), p = u(0);
22
+ let y = !1, l = null, f = 0, i = null;
23
+ async function P() {
24
+ var e, t;
25
+ if (i) return i;
26
+ try {
27
+ const r = await import(
28
+ /* @vite-ignore */
29
+ "mermaid"
30
+ );
31
+ return i = r.default ?? r, (t = i.initialize) == null || t.call(i, {
32
+ startOnLoad: !1,
33
+ securityLevel: "strict",
34
+ theme: (e = window.matchMedia) != null && e.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "default"
35
+ }), i;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ async function b() {
41
+ var g;
42
+ s.value = !0, n.value = null;
43
+ const e = ++f, t = await P();
44
+ if (e !== f) return;
45
+ if (!t) {
46
+ n.value = a.t ? a.t("viewer.peer_not_installed") : "Mermaid viewer requires `mermaid` — install or use download.", s.value = !1;
47
+ return;
48
+ }
49
+ let r;
50
+ try {
51
+ r = await z({
52
+ url: a.url,
53
+ headers: ((g = a.authHeaders) == null ? void 0 : g.call(a)) ?? {},
54
+ credentials: a.authCredentials
55
+ });
56
+ } catch (o) {
57
+ n.value = o instanceof Error ? o.message : "fetch failed", s.value = !1;
58
+ return;
59
+ }
60
+ if (e === f)
61
+ try {
62
+ const o = `filex-mermaid-${Date.now()}`, { svg: V } = await t.render(o, r);
63
+ if (e !== f) return;
64
+ if (d.value) {
65
+ d.value.innerHTML = V;
66
+ const w = d.value.querySelector("svg");
67
+ w && (w.style.maxWidth = "100%", w.style.height = "auto");
68
+ }
69
+ } catch (o) {
70
+ n.value = o instanceof Error ? o.message : "render failed";
71
+ } finally {
72
+ s.value = !1;
73
+ }
74
+ }
75
+ function C(e) {
76
+ if (!e.ctrlKey && !e.metaKey) return;
77
+ e.preventDefault();
78
+ const r = -e.deltaY > 0 ? 1.1 : 1 / 1.1;
79
+ m.value = Math.max(0.2, Math.min(8, m.value * r));
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);
84
+ }
85
+ function E(e) {
86
+ !y || !l || (v.value = l.tx + (e.clientX - l.x), p.value = l.ty + (e.clientY - l.y));
87
+ }
88
+ function h() {
89
+ y = !1, l = null;
90
+ }
91
+ T(b), $(() => {
92
+ f++;
93
+ });
94
+ function S(e, t) {
95
+ return a.t ? a.t(e) : t;
96
+ }
97
+ return (e, t) => (_(), x("div", I, [
98
+ c("div", {
99
+ class: "filex-viewer-mermaid__pane",
100
+ onWheel: C,
101
+ onPointerdown: D,
102
+ onPointermove: E,
103
+ onPointerup: h,
104
+ onPointercancel: h
105
+ }, [
106
+ n.value ? (_(), x("div", K, [
107
+ t[0] || (t[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📊", -1)),
108
+ c("p", null, k(n.value), 1)
109
+ ])) : s.value ? (_(), x("div", N, [
110
+ t[1] || (t[1] = c("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
111
+ c("p", null, k(S("viewer.loading", "Loading…")), 1)
112
+ ])) : B("", !0),
113
+ H(c("div", {
114
+ ref_key: "surface",
115
+ ref: d,
116
+ class: "filex-viewer-mermaid__surface",
117
+ style: Y({ transform: `translate(${v.value}px, ${p.value}px) scale(${m.value})` })
118
+ }, null, 4), [
119
+ [q, !s.value && !n.value]
120
+ ])
121
+ ], 32)
122
+ ]));
123
+ }
124
+ }), j = /* @__PURE__ */ F(U, [["__scopeId", "data-v-fe0bf99e"]]);
125
+ export {
126
+ j as default
127
+ };
128
+ //# sourceMappingURL=MermaidViewer-CXfeDS-7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MermaidViewer-CXfeDS-7.js","sources":["../src/viewers/MermaidViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * MermaidViewer — render a `.mmd` / `.mermaid` source file.\r\n *\r\n * Lazy-imports the `mermaid` library (~150 KB gzipped). Source text is\r\n * fetched from `props.url` (with the auth headers from PreviewModal),\r\n * then rendered to SVG via `mermaid.render('id', src)`. The resulting\r\n * SVG node is inserted into a wrapper that supports pan + scale via\r\n * pure CSS transforms (no extra panzoom dep).\r\n */\r\nimport { onBeforeUnmount, onMounted, ref } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst surface = ref<HTMLDivElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst scale = ref(1);\r\nconst tx = ref(0);\r\nconst ty = ref(0);\r\n\r\nlet dragging = false;\r\nlet dragStart: { x: number; y: number; tx: number; ty: number } | null = null;\r\nlet renderToken = 0;\r\n\r\nlet cachedMermaid: any = null;\r\nasync function ensureMermaid(): Promise<any | null> {\r\n if (cachedMermaid) return cachedMermaid;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'mermaid');\r\n cachedMermaid = mod.default ?? mod;\r\n cachedMermaid.initialize?.({\r\n startOnLoad: false,\r\n securityLevel: 'strict',\r\n theme: window.matchMedia?.('(prefers-color-scheme: dark)').matches\r\n ? 'dark'\r\n : 'default',\r\n });\r\n return cachedMermaid;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n const myToken = ++renderToken;\r\n\r\n const mermaid = await ensureMermaid();\r\n if (myToken !== renderToken) return;\r\n if (!mermaid) {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'Mermaid viewer requires `mermaid` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n let src: string;\r\n try {\r\n src = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n if (myToken !== renderToken) return;\r\n\r\n try {\r\n const id = `filex-mermaid-${Date.now()}`;\r\n const { svg } = await mermaid.render(id, src);\r\n if (myToken !== renderToken) return;\r\n if (surface.value) {\r\n surface.value.innerHTML = svg;\r\n const svgEl = surface.value.querySelector('svg');\r\n if (svgEl) {\r\n svgEl.style.maxWidth = '100%';\r\n svgEl.style.height = 'auto';\r\n }\r\n }\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'render failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction zoomIn(): void {\r\n scale.value = Math.min(8, scale.value * 1.25);\r\n}\r\nfunction zoomOut(): void {\r\n scale.value = Math.max(0.2, scale.value / 1.25);\r\n}\r\nfunction reset(): void {\r\n scale.value = 1;\r\n tx.value = 0;\r\n ty.value = 0;\r\n}\r\n\r\nfunction onWheel(ev: WheelEvent): void {\r\n if (!ev.ctrlKey && !ev.metaKey) return;\r\n ev.preventDefault();\r\n const delta = -ev.deltaY;\r\n const factor = delta > 0 ? 1.1 : 1 / 1.1;\r\n scale.value = Math.max(0.2, Math.min(8, scale.value * factor));\r\n}\r\n\r\nfunction onPointerDown(ev: PointerEvent): void {\r\n dragging = true;\r\n dragStart = { x: ev.clientX, y: ev.clientY, tx: tx.value, ty: ty.value };\r\n (ev.target as HTMLElement).setPointerCapture?.(ev.pointerId);\r\n}\r\nfunction onPointerMove(ev: PointerEvent): void {\r\n if (!dragging || !dragStart) return;\r\n tx.value = dragStart.tx + (ev.clientX - dragStart.x);\r\n ty.value = dragStart.ty + (ev.clientY - dragStart.y);\r\n}\r\nfunction onPointerUp(): void {\r\n dragging = false;\r\n dragStart = null;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-mermaid\">\r\n <div\r\n class=\"filex-viewer-mermaid__pane\"\r\n @wheel=\"onWheel\"\r\n @pointerdown=\"onPointerDown\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerup=\"onPointerUp\"\r\n @pointercancel=\"onPointerUp\"\r\n >\r\n <div\r\n v-if=\"error\"\r\n class=\"filex-viewer-fallback\"\r\n >\r\n <span class=\"filex-viewer-fallback__icon\">📊</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div\r\n v-else-if=\"loading\"\r\n class=\"filex-viewer-fallback\"\r\n >\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <div\r\n v-show=\"!loading && !error\"\r\n ref=\"surface\"\r\n class=\"filex-viewer-mermaid__surface\"\r\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-mermaid {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-mermaid__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-mermaid__zoom {\r\n min-width: 50px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-mermaid__pane {\r\n flex: 1;\r\n overflow: hidden;\r\n position: relative;\r\n cursor: grab;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n touch-action: none;\r\n}\r\n.filex-viewer-mermaid__pane:active {\r\n cursor: grabbing;\r\n}\r\n.filex-viewer-mermaid__surface {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transform-origin: center center;\r\n transition: transform 0.05s linear;\r\n user-select: none;\r\n}\r\n.filex-viewer-mermaid__surface :deep(svg) {\r\n max-width: 90%;\r\n max-height: 90%;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n</style>\r\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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"}
@@ -0,0 +1,113 @@
1
+ import { defineComponent as E, ref as r, onMounted as I, onBeforeUnmount as S, watch as V, openBlock as m, createElementBlock as p, createElementVNode as l, toDisplayString as x, createCommentVNode as A, withDirectives as B, vShow as L } from "vue";
2
+ import { a as T } from "./useViewerFetch-czqbd2Lj.js";
3
+ import { _ as F } from "./index-CmSYzt6L.js";
4
+ const H = { class: "filex-viewer-psd" }, N = { class: "filex-viewer-psd__pane" }, q = {
5
+ key: 0,
6
+ class: "filex-viewer-fallback"
7
+ }, M = {
8
+ key: 1,
9
+ class: "filex-viewer-fallback"
10
+ }, U = /* @__PURE__ */ E({
11
+ __name: "PsdViewer",
12
+ props: {
13
+ url: {},
14
+ mime: {},
15
+ ext: {},
16
+ t: { type: Function },
17
+ authHeaders: { type: Function },
18
+ authCredentials: {}
19
+ },
20
+ setup(D) {
21
+ const t = D, f = r(null), w = r([]), i = r(null), o = r(!0);
22
+ r(!1);
23
+ const P = r({ width: 0, height: 0 });
24
+ r(1);
25
+ let c = 0, u = null;
26
+ async function b() {
27
+ if (u) return u;
28
+ try {
29
+ return u = await import(
30
+ /* @vite-ignore */
31
+ "./index-UFULWo35.js"
32
+ ), u;
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+ function _(a, e) {
38
+ if (a && Array.isArray(a.children))
39
+ for (const n of a.children)
40
+ e.push({
41
+ index: e.length,
42
+ name: n.name ?? "(unnamed)",
43
+ hidden: !!n.hidden
44
+ }), n.children && _(n, e);
45
+ }
46
+ async function g() {
47
+ var n;
48
+ o.value = !0, i.value = null, w.value = [];
49
+ const a = ++c, e = await b();
50
+ if (a === c) {
51
+ if (!e) {
52
+ i.value = t.t ? t.t("viewer.peer_not_installed") : "PSD viewer requires `ag-psd` — install or use download.", o.value = !1;
53
+ return;
54
+ }
55
+ try {
56
+ const d = await T({
57
+ url: t.url,
58
+ headers: ((n = t.authHeaders) == null ? void 0 : n.call(t)) ?? {},
59
+ credentials: t.authCredentials
60
+ });
61
+ if (a !== c) return;
62
+ const s = e.readPsd(d, {
63
+ skipLayerImageData: !1,
64
+ skipCompositeImageData: !1,
65
+ skipThumbnail: !0
66
+ });
67
+ P.value = { width: s.width, height: s.height };
68
+ const y = s.canvas;
69
+ if (y && f.value) {
70
+ const h = f.value;
71
+ h.width = s.width, h.height = s.height;
72
+ const v = h.getContext("2d");
73
+ v == null || v.drawImage(y, 0, 0);
74
+ } else
75
+ throw new Error("PSD has no composite image (skipCompositeImageData?)");
76
+ const k = [];
77
+ _(s, k), w.value = k;
78
+ } catch (d) {
79
+ i.value = d instanceof Error ? d.message : "PSD decode failed";
80
+ } finally {
81
+ o.value = !1;
82
+ }
83
+ }
84
+ }
85
+ I(g), S(() => {
86
+ c++;
87
+ }), V(() => t.url, g);
88
+ function C(a, e) {
89
+ return t.t ? t.t(a) : e;
90
+ }
91
+ return (a, e) => (m(), p("div", H, [
92
+ l("div", N, [
93
+ i.value ? (m(), p("div", q, [
94
+ e[0] || (e[0] = l("span", { class: "filex-viewer-fallback__icon" }, "🎨", -1)),
95
+ l("p", null, x(i.value), 1)
96
+ ])) : o.value ? (m(), p("div", M, [
97
+ e[1] || (e[1] = l("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
98
+ l("p", null, x(C("viewer.loading", "Loading…")), 1)
99
+ ])) : A("", !0),
100
+ B(l("canvas", {
101
+ ref_key: "canvasEl",
102
+ ref: f
103
+ }, null, 512), [
104
+ [L, !o.value && !i.value]
105
+ ])
106
+ ])
107
+ ]));
108
+ }
109
+ }), J = /* @__PURE__ */ F(U, [["__scopeId", "data-v-d23e4974"]]);
110
+ export {
111
+ J as default
112
+ };
113
+ //# sourceMappingURL=PsdViewer-VtPpxKVe.js.map