@brftech/filex-core 0.34.2 → 0.36.0

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.
@@ -1,4 +1,4 @@
1
- import { defineComponent as y, ref as d, onMounted as k, watch as b, computed as p, openBlock as s, createElementBlock as n, createElementVNode as t, toDisplayString as a, Fragment as g, renderList as z, createTextVNode as C } from "vue";
1
+ import { defineComponent as y, ref as d, onMounted as k, watch as b, computed as p, openBlock as s, createElementBlock as n, createElementVNode as i, toDisplayString as a, Fragment as g, renderList as z, createTextVNode as C } from "vue";
2
2
  const S = { class: "filex-viewer-archive" }, B = {
3
3
  key: 0,
4
4
  class: "filex-viewer-fallback"
@@ -11,7 +11,7 @@ const S = { class: "filex-viewer-archive" }, B = {
11
11
  }, P = {
12
12
  key: 3,
13
13
  class: "filex-viewer-archive__pane"
14
- }, E = { class: "filex-viewer-archive__summary" }, N = { class: "filex-viewer-archive__table" }, T = { class: "filex-viewer-archive__size" }, H = ["data-dir"], V = { class: "filex-viewer-archive__icon" }, j = { class: "filex-viewer-archive__size" }, L = /* @__PURE__ */ y({
14
+ }, E = { class: "filex-viewer-archive__summary" }, L = { class: "filex-viewer-archive__table" }, N = { class: "filex-viewer-archive__size" }, T = ["data-dir"], H = { class: "filex-viewer-archive__icon" }, V = { class: "filex-viewer-archive__size" }, A = /* @__PURE__ */ y({
15
15
  __name: "ArchiveViewer",
16
16
  props: {
17
17
  url: {},
@@ -19,23 +19,24 @@ const S = { class: "filex-viewer-archive" }, B = {
19
19
  ext: {},
20
20
  t: { type: Function },
21
21
  authHeaders: { type: Function },
22
- authCredentials: {}
22
+ authCredentials: {},
23
+ archiveListUrl: {}
23
24
  },
24
25
  setup(w) {
25
26
  const r = w, o = d([]), v = d(!0), c = d(null);
26
- function l(e, i) {
27
- return r.t ? r.t(e) : i;
27
+ function l(e, t) {
28
+ return r.t ? r.t(e) : t;
28
29
  }
29
30
  function f(e) {
30
31
  return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : e < 1024 * 1024 * 1024 ? `${(e / (1024 * 1024)).toFixed(1)} MB` : `${(e / (1024 * 1024 * 1024)).toFixed(2)} GB`;
31
32
  }
32
- async function _() {
33
+ async function h() {
33
34
  if (v.value = !0, c.value = null, o.value = [], !r.filePath) {
34
35
  c.value = l("viewer.archive.error", "Could not read archive contents."), v.value = !1;
35
36
  return;
36
37
  }
37
38
  try {
38
- const e = await fetch("/api/files/archive/list", {
39
+ const e = await fetch(r.archiveListUrl || "/api/files/archive/list", {
39
40
  method: "POST",
40
41
  credentials: r.authCredentials || "same-origin",
41
42
  headers: {
@@ -46,46 +47,46 @@ const S = { class: "filex-viewer-archive" }, B = {
46
47
  });
47
48
  if (!e.ok)
48
49
  throw new Error(`${e.status} ${e.statusText}`);
49
- const i = await e.json();
50
- o.value = i.entries ?? [];
50
+ const t = await e.json();
51
+ o.value = t.entries ?? [];
51
52
  } catch (e) {
52
53
  c.value = e instanceof Error ? e.message : l("viewer.archive.error", "Could not read archive contents.");
53
54
  } finally {
54
55
  v.value = !1;
55
56
  }
56
57
  }
57
- k(_), b(() => r.filePath, _);
58
- const x = p(() => o.value.reduce((e, i) => e + (i.size || 0), 0)), h = p(() => o.value.filter((e) => !e.is_dir).length);
59
- return (e, i) => (s(), n("div", S, [
58
+ k(h), b(() => r.filePath, h);
59
+ const x = p(() => o.value.reduce((e, t) => e + (t.size || 0), 0)), _ = p(() => o.value.filter((e) => !e.is_dir).length);
60
+ return (e, t) => (s(), n("div", S, [
60
61
  c.value ? (s(), n("div", B, [
61
- i[0] || (i[0] = t("span", { class: "filex-viewer-fallback__icon" }, "🗜️", -1)),
62
- t("p", null, a(c.value), 1)
62
+ t[0] || (t[0] = i("span", { class: "filex-viewer-fallback__icon" }, "🗜️", -1)),
63
+ i("p", null, a(c.value), 1)
63
64
  ])) : v.value ? (s(), n("div", F, [
64
- i[1] || (i[1] = t("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
65
- t("p", null, a(l("viewer.loading", "Loading…")), 1)
65
+ t[1] || (t[1] = i("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
66
+ i("p", null, a(l("viewer.loading", "Loading…")), 1)
66
67
  ])) : o.value.length === 0 ? (s(), n("div", $, [
67
- i[2] || (i[2] = t("span", { class: "filex-viewer-fallback__icon" }, "🗜️", -1)),
68
- t("p", null, a(l("viewer.archive.empty", "Archive is empty.")), 1)
68
+ t[2] || (t[2] = i("span", { class: "filex-viewer-fallback__icon" }, "🗜️", -1)),
69
+ i("p", null, a(l("viewer.archive.empty", "Archive is empty.")), 1)
69
70
  ])) : (s(), n("div", P, [
70
- t("div", E, a(h.value) + " " + a(l("viewer.archive.entries", "{n} files").replace("{n}", String(h.value))) + " · " + a(f(x.value)), 1),
71
- t("table", N, [
72
- t("thead", null, [
73
- t("tr", null, [
74
- t("th", null, a(l("viewer.name", "Name")), 1),
75
- t("th", T, a(l("viewer.size", "Size")), 1)
71
+ i("div", E, a(_.value) + " " + a(l("viewer.archive.entries", "{n} files").replace("{n}", String(_.value))) + " · " + a(f(x.value)), 1),
72
+ i("table", L, [
73
+ i("thead", null, [
74
+ i("tr", null, [
75
+ i("th", null, a(l("viewer.name", "Name")), 1),
76
+ i("th", N, a(l("viewer.size", "Size")), 1)
76
77
  ])
77
78
  ]),
78
- t("tbody", null, [
79
+ i("tbody", null, [
79
80
  (s(!0), n(g, null, z(o.value, (u, m) => (s(), n("tr", {
80
81
  key: m,
81
82
  "data-dir": u.is_dir ? "1" : "0"
82
83
  }, [
83
- t("td", null, [
84
- t("span", V, a(u.is_dir ? "📁" : "📄"), 1),
84
+ i("td", null, [
85
+ i("span", H, a(u.is_dir ? "📁" : "📄"), 1),
85
86
  C(" " + a(u.name), 1)
86
87
  ]),
87
- t("td", j, a(u.is_dir ? "" : f(u.size)), 1)
88
- ], 8, H))), 128))
88
+ i("td", V, a(u.is_dir ? "" : f(u.size)), 1)
89
+ ], 8, T))), 128))
89
90
  ])
90
91
  ])
91
92
  ]))
@@ -93,6 +94,6 @@ const S = { class: "filex-viewer-archive" }, B = {
93
94
  }
94
95
  });
95
96
  export {
96
- L as default
97
+ A as default
97
98
  };
98
- //# sourceMappingURL=ArchiveViewer-B9JSFdX6.js.map
99
+ //# sourceMappingURL=ArchiveViewer-Cdfv9LFC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchiveViewer-Cdfv9LFC.js","sources":["../src/viewers/ArchiveViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * ArchiveViewer — minimal zip / archive contents preview.\n *\n * Hits the configured archive-list endpoint (`archiveListUrl`, default\n * `POST /api/files/archive/list`) with the adapter-qualified path\n * and renders the member list as a flat table (name, size, mtime).\n * Read-only — extraction is exposed elsewhere (context menu / actions\n * panel). The viewer's job is just \"what's inside?\" so the user can\n * decide whether to extract or download.\n */\nimport { computed, onMounted, ref, watch } from 'vue';\n\ninterface ArchiveEntry {\n name: string;\n size: number;\n mtime?: string;\n is_dir?: boolean;\n}\n\nconst props = defineProps<{\n url: string;\n filePath?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n /** ⚠ Where to ask. This used to be the literal '/api/files/archive/list',\n * which is the ONE thing an embed cannot assume: with `apiBase` pointing at\n * another origin the request went to the host page instead and 404'd, while\n * every other call in the package honoured the configured base. The default\n * keeps a same-origin install working unchanged. */\n archiveListUrl?: string;\n}>();\n\nconst entries = ref<ArchiveEntry[]>([]);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n\nfunction fmtSize(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n entries.value = [];\n // The viewer is mounted with the resolved file path. Hit the API\n // endpoint with the same adapter-qualified path the preview URL\n // points at — the backend resolves storage + relative path itself.\n if (!props.filePath) {\n error.value = tt('viewer.archive.error', 'Could not read archive contents.');\n loading.value = false;\n return;\n }\n try {\n const res = await fetch(props.archiveListUrl || '/api/files/archive/list', {\n method: 'POST',\n credentials: props.authCredentials || 'same-origin',\n headers: {\n 'Content-Type': 'application/json',\n ...(props.authHeaders ? await props.authHeaders() : {}),\n },\n body: JSON.stringify({ path: props.filePath }),\n });\n if (!res.ok) {\n throw new Error(`${res.status} ${res.statusText}`);\n }\n const body = (await res.json()) as { entries?: ArchiveEntry[] };\n entries.value = body.entries ?? [];\n } catch (err) {\n error.value = err instanceof Error ? err.message : tt('viewer.archive.error', 'Could not read archive contents.');\n } finally {\n loading.value = false;\n }\n}\n\nonMounted(load);\nwatch(() => props.filePath, load);\n\nconst totalSize = computed(() => entries.value.reduce((sum, e) => sum + (e.size || 0), 0));\nconst fileCount = computed(() => entries.value.filter((e) => !e.is_dir).length);\n</script>\n\n<template>\n <div class=\"filex-viewer-archive\">\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-if=\"entries.length === 0\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">🗜️</span>\n <p>{{ tt('viewer.archive.empty', 'Archive is empty.') }}</p>\n </div>\n <div v-else class=\"filex-viewer-archive__pane\">\n <div class=\"filex-viewer-archive__summary\">\n {{ fileCount }} {{ tt('viewer.archive.entries', '{n} files').replace('{n}', String(fileCount)) }}\n · {{ fmtSize(totalSize) }}\n </div>\n <table class=\"filex-viewer-archive__table\">\n <thead>\n <tr>\n <th>{{ tt('viewer.name', 'Name') }}</th>\n <th class=\"filex-viewer-archive__size\">{{ tt('viewer.size', 'Size') }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(e, i) in entries\" :key=\"i\" :data-dir=\"e.is_dir ? '1' : '0'\">\n <td>\n <span class=\"filex-viewer-archive__icon\">{{ e.is_dir ? '📁' : '📄' }}</span>\n {{ e.name }}\n </td>\n <td class=\"filex-viewer-archive__size\">{{ e.is_dir ? '' : fmtSize(e.size) }}</td>\n </tr>\n </tbody>\n </table>\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-archive {\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-archive__pane {\n flex: 1;\n overflow: auto;\n padding: 16px 20px;\n}\n.filex-viewer-archive__summary {\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n margin-bottom: 12px;\n font-variant-numeric: tabular-nums;\n}\n.filex-viewer-archive__table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n font-family: var(--fe-font-mono, monospace);\n}\n.filex-viewer-archive__table th,\n.filex-viewer-archive__table td {\n padding: 6px 12px;\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n text-align: left;\n}\n.filex-viewer-archive__table th {\n background: var(--fe-bg-elev, #f7f8fa);\n font-weight: 600;\n position: sticky;\n top: 0;\n}\n.filex-viewer-archive__size {\n text-align: right;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-archive__icon {\n margin-right: 6px;\n}\n.filex-viewer-archive__table tr[data-dir=\"1\"] {\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</style>\n"],"names":["props","__props","entries","ref","loading","error","tt","key","fallback","fmtSize","n","load","res","body","err","onMounted","watch","totalSize","computed","sum","e","fileCount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_cache","_createElementVNode","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_toDisplayString","_hoisted_7","_hoisted_8","_Fragment","_renderList","i","_hoisted_10","_hoisted_11"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,UAAMA,IAAQC,GAeRC,IAAUC,EAAoB,EAAE,GAChCC,IAAUD,EAAI,EAAI,GAClBE,IAAQF,EAAmB,IAAI;AAErC,aAASG,EAAGC,GAAaC,GAA0B;AACjD,aAAOR,EAAM,IAAIA,EAAM,EAAEO,CAAG,IAAIC;AAAA,IAClC;AAEA,aAASC,EAAQC,GAAmB;AAClC,aAAIA,IAAI,OAAa,GAAGA,CAAC,OACrBA,IAAI,OAAO,OAAa,IAAIA,IAAI,MAAM,QAAQ,CAAC,CAAC,QAChDA,IAAI,OAAO,OAAO,OAAa,IAAIA,KAAK,OAAO,OAAO,QAAQ,CAAC,CAAC,QAC7D,IAAIA,KAAK,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC;AAAA,IACjD;AAEA,mBAAeC,IAAsB;AAOnC,UANAP,EAAQ,QAAQ,IAChBC,EAAM,QAAQ,MACdH,EAAQ,QAAQ,CAAA,GAIZ,CAACF,EAAM,UAAU;AACnB,QAAAK,EAAM,QAAQC,EAAG,wBAAwB,kCAAkC,GAC3EF,EAAQ,QAAQ;AAChB;AAAA,MACF;AACA,UAAI;AACF,cAAMQ,IAAM,MAAM,MAAMZ,EAAM,kBAAkB,2BAA2B;AAAA,UACzE,QAAQ;AAAA,UACR,aAAaA,EAAM,mBAAmB;AAAA,UACtC,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,GAAIA,EAAM,cAAc,MAAMA,EAAM,YAAA,IAAgB,CAAA;AAAA,UAAC;AAAA,UAEvD,MAAM,KAAK,UAAU,EAAE,MAAMA,EAAM,UAAU;AAAA,QAAA,CAC9C;AACD,YAAI,CAACY,EAAI;AACP,gBAAM,IAAI,MAAM,GAAGA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE;AAEnD,cAAMC,IAAQ,MAAMD,EAAI,KAAA;AACxB,QAAAV,EAAQ,QAAQW,EAAK,WAAW,CAAA;AAAA,MAClC,SAASC,GAAK;AACZ,QAAAT,EAAM,QAAQS,aAAe,QAAQA,EAAI,UAAUR,EAAG,wBAAwB,kCAAkC;AAAA,MAClH,UAAA;AACE,QAAAF,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAEA,IAAAW,EAAUJ,CAAI,GACdK,EAAM,MAAMhB,EAAM,UAAUW,CAAI;AAEhC,UAAMM,IAAYC,EAAS,MAAMhB,EAAQ,MAAM,OAAO,CAACiB,GAAKC,MAAMD,KAAOC,EAAE,QAAQ,IAAI,CAAC,CAAC,GACnFC,IAAYH,EAAS,MAAMhB,EAAQ,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM;sBAI5EoB,EAAA,GAAAC,EAoCM,OApCNC,GAoCM;AAAA,MAnCOnB,EAAA,SAAXiB,EAAA,GAAAC,EAGM,OAHNE,GAGM;AAAA,QAFJC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAoD,QAAA,EAA9C,OAAM,8BAAA,GAA8B,OAAG,EAAA;AAAA,QAC7CA,EAAkB,aAAZtB,EAAA,KAAK,GAAA,CAAA;AAAA,MAAA,MAEGD,EAAA,SAAhBkB,KAAAC,EAGM,OAHNK,GAGM;AAAA,QAFJF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAkD,QAAA,EAA5C,OAAM,8BAAA,GAA8B,KAAC,EAAA;AAAA,QAC3CA,EAA6C,aAAvCrB,EAAE,kBAAA,UAAA,CAAA,GAAA,CAAA;AAAA,MAAA,MAEMJ,EAAA,MAAQ,WAAM,KAA9BoB,KAAAC,EAGM,OAHNM,GAGM;AAAA,QAFJH,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAoD,QAAA,EAA9C,OAAM,8BAAA,GAA8B,OAAG,EAAA;AAAA,QAC7CA,EAA4D,aAAtDrB,EAAE,wBAAA,mBAAA,CAAA,GAAA,CAAA;AAAA,MAAA,OAEVgB,EAAA,GAAAC,EAsBM,OAtBNO,GAsBM;AAAA,QArBJH,EAGM,OAHNI,GAGMC,EAFDX,OAAS,IAAG,QAAIf,EAAE,0BAAA,WAAA,EAAwC,QAAO,OAAQ,OAAOe,EAAA,KAAS,CAAA,CAAA,IAAK,QAC/FW,EAAGvB,EAAQQ,EAAA,KAAS,CAAA,GAAA,CAAA;AAAA,QAExBU,EAgBQ,SAhBRM,GAgBQ;AAAA,UAfNN,EAKQ,SAAA,MAAA;AAAA,YAJNA,EAGK,MAAA,MAAA;AAAA,cAFHA,EAAwC,cAAjCrB,EAAE,eAAA,MAAA,CAAA,GAAA,CAAA;AAAA,cACTqB,EAA2E,MAA3EO,GAA2EF,EAAjC1B,EAAE,eAAA,MAAA,CAAA,GAAA,CAAA;AAAA,YAAA;;UAGhDqB,EAQQ,SAAA,MAAA;AAAA,aAPNL,EAAA,EAAA,GAAAC,EAMKY,GAAA,MAAAC,EANgBlC,EAAA,OAAO,CAAhBkB,GAAGiB,YAAfd,EAMK,MAAA;AAAA,cAN0B,KAAKc;AAAA,cAAI,YAAUjB,EAAE,SAAM,MAAA;AAAA,YAAA;cACxDO,EAGK,MAAA,MAAA;AAAA,gBAFHA,EAA4E,QAA5EW,GAA4EN,EAAhCZ,EAAE,SAAM,OAAA,IAAA,GAAA,CAAA;AAAA,kBAAwB,MAC5EY,EAAGZ,EAAE,IAAI,GAAA,CAAA;AAAA,cAAA;cAEXO,EAAiF,MAAjFY,GAAiFP,EAAvCZ,EAAE,SAAM,KAAQX,EAAQW,EAAE,IAAI,CAAA,GAAA,CAAA;AAAA,YAAA;;;;;;;"}