@brftech/filex-core 0.39.1 → 0.41.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.
- package/README.md +32 -25
- package/dist/ArchiveViewer-BNqukFg8.js +124 -0
- package/dist/ArchiveViewer-BNqukFg8.js.map +1 -0
- package/dist/CsvViewer-ii_-MgmG.js +141 -0
- package/dist/CsvViewer-ii_-MgmG.js.map +1 -0
- package/dist/{DrawioViewer-BNALOB04.js → DrawioViewer-B2tuu4rX.js} +48 -42
- package/dist/DrawioViewer-B2tuu4rX.js.map +1 -0
- package/dist/EpubViewer-p4B8iiWb.js +163 -0
- package/dist/EpubViewer-p4B8iiWb.js.map +1 -0
- package/dist/IpynbViewer-D_qYRJhu.js +184 -0
- package/dist/IpynbViewer-D_qYRJhu.js.map +1 -0
- package/dist/MermaidViewer-3ZkfNM8v.js +137 -0
- package/dist/MermaidViewer-3ZkfNM8v.js.map +1 -0
- package/dist/PsdViewer-CuV-OPSd.js +122 -0
- package/dist/PsdViewer-CuV-OPSd.js.map +1 -0
- package/dist/TiffViewer-BLeoF4Be.js +142 -0
- package/dist/TiffViewer-BLeoF4Be.js.map +1 -0
- package/dist/Viewer3D-DHhhU76E.js +75 -0
- package/dist/Viewer3D-DHhhU76E.js.map +1 -0
- package/dist/filex-core.js +217 -20077
- package/dist/filex-core.js.map +1 -1
- package/dist/filex-core.umd.cjs +61 -62
- package/dist/filex-core.umd.cjs.map +1 -1
- package/dist/index-BraG7Cz4.js +26664 -0
- package/dist/index-BraG7Cz4.js.map +1 -0
- package/dist/index.d.ts +4276 -851
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/FileExplorer.vue +2170 -492
- package/src/components/AdvancedSearch.vue +870 -0
- package/src/components/Breadcrumb.vue +191 -19
- package/src/components/CommandPalette.vue +66 -22
- package/src/components/ConnectionsPanel.vue +6 -2
- package/src/components/ContextMenu.vue +57 -2
- package/src/components/EncryptedFolderModal.vue +31 -25
- package/src/components/FilePane.vue +939 -0
- package/src/components/FilterBar.vue +568 -72
- package/src/components/GalleryView.vue +162 -30
- package/src/components/GridView.vue +322 -58
- package/src/components/HomeView.vue +331 -0
- package/src/components/InspectorPanel.vue +296 -53
- package/src/components/ListView.vue +1158 -167
- package/src/components/NFSExportsPanel.vue +7 -4
- package/src/components/OnboardingTour.vue +156 -33
- package/src/components/QuickLook.vue +34 -5
- package/src/components/RecentlyOpened.vue +17 -2
- package/src/components/S3KeysPanel.vue +7 -4
- package/src/components/SSHKeysPanel.vue +7 -4
- package/src/components/ShortcutSettings.vue +43 -2
- package/src/components/ShortcutsHelp.vue +4 -1
- package/src/components/SideNav.vue +206 -140
- package/src/components/StorageFields.vue +19 -1
- package/src/components/TabBar.vue +87 -1
- package/src/components/TagPicker.vue +77 -6
- package/src/components/ThemeGallery.vue +13 -198
- package/src/components/ThemePalette.vue +244 -0
- package/src/components/TimeZoneDialog.vue +127 -0
- package/src/components/TimeZonePicker.vue +696 -0
- package/src/components/TokensPanel.vue +16 -4
- package/src/components/Toolbar.vue +965 -469
- package/src/components/ViewSwitcher.vue +9 -4
- package/src/composables/useConnections.ts +35 -4
- package/src/composables/useExplorerTimeZone.ts +85 -0
- package/src/composables/useFileApi.ts +53 -4
- package/src/composables/useKeyboardShortcuts.ts +122 -0
- package/src/composables/useLocale.ts +365 -25
- package/src/index.ts +182 -3
- package/src/lib/actionIcons.ts +330 -0
- package/src/lib/advSearch.ts +162 -0
- package/src/lib/dateGroups.ts +197 -0
- package/src/lib/destinationTree.ts +235 -0
- package/src/lib/downloadSelection.ts +154 -0
- package/src/lib/fileFilters.ts +319 -12
- package/src/lib/fileIcons.ts +299 -5
- package/src/lib/filePreview.ts +605 -0
- package/src/lib/listing.ts +72 -0
- package/src/lib/shareTtl.ts +11 -1
- package/src/lib/sortOrder.ts +459 -0
- package/src/lib/themes.ts +152 -23
- package/src/lib/timezone.ts +456 -0
- package/src/lib/uiProfile.ts +82 -0
- package/src/lib/viewPrefs.ts +1036 -0
- package/src/locales/en.ts +432 -25
- package/src/locales/tr.ts +425 -25
- package/src/modals/ConvertModal.vue +23 -3
- package/src/modals/DestinationPickerModal.vue +341 -0
- package/src/modals/Modal.vue +18 -4
- package/src/modals/NewDocumentModal.vue +525 -0
- package/src/modals/NewFolderModal.vue +15 -9
- package/src/modals/PermissionsModal.vue +543 -473
- package/src/modals/PreviewModal.vue +516 -156
- package/src/styles/base.css +5435 -8
- package/src/styles/variables.css +140 -60
- package/src/types/Connections.ts +9 -0
- package/src/types/ExplorerConfig.ts +144 -39
- package/src/types/FileNode.ts +28 -0
- package/src/viewers/ArchiveViewer.vue +46 -8
- package/src/viewers/CsvViewer.vue +19 -2
- package/src/viewers/DrawioViewer.vue +12 -1
- package/src/viewers/EpubViewer.vue +50 -6
- package/src/viewers/IpynbViewer.vue +19 -2
- package/src/viewers/MermaidViewer.vue +20 -3
- package/src/viewers/PdfViewer.vue +24 -4
- package/src/viewers/PsdViewer.vue +28 -4
- package/src/viewers/TiffViewer.vue +19 -2
- package/src/viewers/Viewer3D.vue +36 -2
- package/dist/ArchiveViewer-Cdfv9LFC.js +0 -99
- package/dist/ArchiveViewer-Cdfv9LFC.js.map +0 -1
- package/dist/CsvViewer-CqWeV8VO.js +0 -131
- package/dist/CsvViewer-CqWeV8VO.js.map +0 -1
- package/dist/DrawioViewer-BNALOB04.js.map +0 -1
- package/dist/EpubViewer-BPmlImG7.js +0 -145
- package/dist/EpubViewer-BPmlImG7.js.map +0 -1
- package/dist/IpynbViewer-CDlQmuCV.js +0 -175
- package/dist/IpynbViewer-CDlQmuCV.js.map +0 -1
- package/dist/MermaidViewer-sfZWdR-d.js +0 -127
- package/dist/MermaidViewer-sfZWdR-d.js.map +0 -1
- package/dist/PsdViewer-DwuySZsb.js +0 -112
- package/dist/PsdViewer-DwuySZsb.js.map +0 -1
- package/dist/TiffViewer-BDQ3d3CQ.js +0 -132
- package/dist/TiffViewer-BDQ3d3CQ.js.map +0 -1
- package/dist/Viewer3D-CJJJgkuv.js +0 -60
- package/dist/Viewer3D-CJJJgkuv.js.map +0 -1
- package/src/components/SecondaryPane.vue +0 -447
- package/src/modals/ShareModal.vue +0 -139
package/README.md
CHANGED
|
@@ -51,7 +51,6 @@ const config = {
|
|
|
51
51
|
sideNav: true, // the navigation panel (default on)
|
|
52
52
|
connections: true, // its "How to connect" + "API keys" entries
|
|
53
53
|
uiProfile: 'standard', // 'simple' — one pane, list/grid, no tabs
|
|
54
|
-
// 'drive' — that, plus the Drive-shaped shell
|
|
55
54
|
};
|
|
56
55
|
</script>
|
|
57
56
|
|
|
@@ -106,10 +105,14 @@ instead of drawing an empty key cap. See
|
|
|
106
105
|
|
|
107
106
|
### Navigation panel
|
|
108
107
|
|
|
109
|
-
The explorer ships a left navigation panel —
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
The explorer ships a left navigation panel — the primary **+ New** menu
|
|
109
|
+
(upload files · new folder · new document · request files), the destinations
|
|
110
|
+
**Home · Shared with me · Recent · Starred · Trash** (plus **My files** when
|
|
111
|
+
the caller reaches at most one storage), the tags in use, and the storages the
|
|
112
|
+
caller can see (a storage reached through a grant is marked *Shared*). It is on
|
|
113
|
+
by default on every surface; the viewer collapses it to an icon rail from the
|
|
114
|
+
control at the far left of the **top bar** — above the panel rather than inside
|
|
115
|
+
it, so it is still reachable once the panel is a rail — and that choice is
|
|
113
116
|
remembered per browser. Under 560px it becomes a drawer over the listing instead
|
|
114
117
|
of a column.
|
|
115
118
|
|
|
@@ -118,7 +121,7 @@ const config = {
|
|
|
118
121
|
apiBase: 'https://files.example.com',
|
|
119
122
|
auth: { kind: 'bearer', token },
|
|
120
123
|
sideNav: true, // default; `rootPath` flips it off
|
|
121
|
-
uiProfile: 'simple', // 'standard' (default) | 'simple'
|
|
124
|
+
uiProfile: 'simple', // 'standard' (default) | 'simple'
|
|
122
125
|
};
|
|
123
126
|
```
|
|
124
127
|
|
|
@@ -144,31 +147,35 @@ connect", Upload, the storages and Trash stay. See
|
|
|
144
147
|
|
|
145
148
|
`uiProfile: 'simple'` is a preset, not a feature switch — nothing is removed
|
|
146
149
|
from the build. It turns off the tab strip and the split pane, reduces the view
|
|
147
|
-
switcher to list + grid, and
|
|
148
|
-
people who want a file drive rather than a file manager.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
switcher to list + grid, and defaults the panel's "How to connect" / "API keys"
|
|
151
|
+
entries off, for the people who want a file drive rather than a file manager.
|
|
152
|
+
It does not gate the navigation panel: that ships in every profile, and only
|
|
153
|
+
the viewer's own collapse choice moves it.
|
|
154
|
+
|
|
155
|
+
There are **two profiles and no third**. ⚠ Anything else that reaches
|
|
156
|
+
`uiProfile` — a typo, or the `'drive'` profile that was **removed** after
|
|
157
|
+
v0.40.0 — resolves to `'standard'` and logs one console line naming it. **If
|
|
158
|
+
you were passing `'drive'`, pass `'simple'`.** It was only ever `simple` plus a
|
|
159
|
+
look, and the look below is now what *every* embed draws, with no string
|
|
160
|
+
passed:
|
|
161
|
+
|
|
162
|
+
- one primary **+ New** menu in the panel (upload files · new folder · new
|
|
163
|
+
document · request files) instead of the Upload / New folder pair,
|
|
154
164
|
- one **search field across the header** with a ⌘K / Ctrl+K chip that hands the
|
|
155
165
|
query to the command palette — the field searches the folder you are in, the
|
|
156
166
|
palette is where "everywhere", saved searches and commands live,
|
|
157
|
-
- a **filter row** under the breadcrumb: Type · Modified · Size,
|
|
158
|
-
- **Folders** and **Files** as labelled sections in grid view
|
|
167
|
+
- a **filter row** under the breadcrumb: Type · People · Modified · Size,
|
|
168
|
+
- **Folders** and **Files** as labelled sections in grid view — replaced by
|
|
169
|
+
**date headings** (Today · Yesterday · This Week · This Month · *September
|
|
170
|
+
2026*) in all three views while the listing is sorted by Modified,
|
|
159
171
|
- the details panel split into **Details** and **Activity**, with "People with
|
|
160
172
|
access" and a share-link row,
|
|
161
173
|
- a **storage line** under the navigation (`GET /api/files/quota/me`).
|
|
162
174
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
⚠ There is deliberately **no People filter** and no Owner column, though the
|
|
168
|
-
mockups this profile came from draw both: a listing row carries no owner
|
|
169
|
-
(`nodes.owner_id` is quota bookkeeping, serialized by nothing) and the listing
|
|
170
|
-
endpoint reads no owner parameter. A chip that opens, offers names and changes
|
|
171
|
-
nothing is worse than no chip.
|
|
175
|
+
The **People** chip and the **Owner** column are real now: migration `00038`
|
|
176
|
+
put the owner on the node itself, so a listing row carries one, the chip offers
|
|
177
|
+
only the people who actually own something in the rows on screen, and quota is
|
|
178
|
+
counted against the owner rather than whoever last touched the file.
|
|
172
179
|
|
|
173
180
|
### Connections
|
|
174
181
|
|
|
@@ -187,7 +194,7 @@ import {
|
|
|
187
194
|
NFSExportsPanel,
|
|
188
195
|
TokensPanel, // FTPS / WebDAV / filex mount sign in with a token
|
|
189
196
|
ConnectionGuideView,
|
|
190
|
-
buildGuide, guideProtocols,
|
|
197
|
+
buildGuide, guideProtocols,
|
|
191
198
|
useS3Keys, useSSHKeys, useNFSExports, useTokens,
|
|
192
199
|
type ProtocolGuide, type ApiToken,
|
|
193
200
|
} from '@brftech/filex-core';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { defineComponent as b, ref as v, onMounted as g, watch as L, computed as h, openBlock as s, createElementBlock as o, createElementVNode as i, toDisplayString as r, unref as H, Fragment as M, renderList as z, createTextVNode as C } from "vue";
|
|
2
|
+
import { f as x, a as S } from "./index-BraG7Cz4.js";
|
|
3
|
+
const $ = { class: "filex-viewer-archive" }, B = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "filex-viewer-fallback"
|
|
6
|
+
}, F = ["innerHTML"], P = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "filex-viewer-fallback"
|
|
9
|
+
}, E = ["innerHTML"], N = {
|
|
10
|
+
key: 2,
|
|
11
|
+
class: "filex-viewer-fallback"
|
|
12
|
+
}, I = ["innerHTML"], O = {
|
|
13
|
+
key: 3,
|
|
14
|
+
class: "filex-viewer-archive__pane"
|
|
15
|
+
}, V = { class: "filex-viewer-archive__summary" }, j = { class: "filex-viewer-archive__table" }, A = { class: "filex-viewer-archive__size" }, U = ["data-dir"], D = ["innerHTML"], G = { class: "filex-viewer-archive__size" }, q = /* @__PURE__ */ b({
|
|
16
|
+
__name: "ArchiveViewer",
|
|
17
|
+
props: {
|
|
18
|
+
url: {},
|
|
19
|
+
filePath: {},
|
|
20
|
+
ext: {},
|
|
21
|
+
t: { type: Function },
|
|
22
|
+
authHeaders: { type: Function },
|
|
23
|
+
authCredentials: {},
|
|
24
|
+
archiveListUrl: {}
|
|
25
|
+
},
|
|
26
|
+
setup(m) {
|
|
27
|
+
const t = m, c = v([]), d = v(!0), u = v(null);
|
|
28
|
+
function l(e, a, n) {
|
|
29
|
+
return t.t ? t.t(e, n) : a;
|
|
30
|
+
}
|
|
31
|
+
function _(e) {
|
|
32
|
+
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`;
|
|
33
|
+
}
|
|
34
|
+
async function f() {
|
|
35
|
+
if (d.value = !0, u.value = null, c.value = [], !t.filePath) {
|
|
36
|
+
u.value = l("viewer.archive.error", "Could not read archive contents."), d.value = !1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const e = await fetch(t.archiveListUrl || "/api/files/archive/list", {
|
|
41
|
+
method: "POST",
|
|
42
|
+
credentials: t.authCredentials || "same-origin",
|
|
43
|
+
headers: {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
...t.authHeaders ? await t.authHeaders() : {}
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({ path: t.filePath })
|
|
48
|
+
});
|
|
49
|
+
if (!e.ok)
|
|
50
|
+
throw new Error(`${e.status} ${e.statusText}`);
|
|
51
|
+
const a = await e.json();
|
|
52
|
+
c.value = a.entries ?? [];
|
|
53
|
+
} catch (e) {
|
|
54
|
+
u.value = e instanceof Error ? e.message : l("viewer.archive.error", "Could not read archive contents.");
|
|
55
|
+
} finally {
|
|
56
|
+
d.value = !1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
g(f), L(() => t.filePath, f);
|
|
60
|
+
const y = h(() => c.value.reduce((e, a) => e + (a.size || 0), 0)), p = h(() => c.value.filter((e) => !e.is_dir).length), w = h(() => x({ type: "file", extension: t.ext }));
|
|
61
|
+
function k(e) {
|
|
62
|
+
const a = e.name || "", n = a.lastIndexOf(".");
|
|
63
|
+
return x({
|
|
64
|
+
type: e.is_dir ? "dir" : "file",
|
|
65
|
+
extension: n > 0 ? a.slice(n + 1) : "",
|
|
66
|
+
basename: a
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return (e, a) => (s(), o("div", $, [
|
|
70
|
+
u.value ? (s(), o("div", B, [
|
|
71
|
+
i("span", {
|
|
72
|
+
class: "filex-viewer-fallback__icon",
|
|
73
|
+
"aria-hidden": "true",
|
|
74
|
+
innerHTML: w.value
|
|
75
|
+
}, null, 8, F),
|
|
76
|
+
i("p", null, r(u.value), 1)
|
|
77
|
+
])) : d.value ? (s(), o("div", P, [
|
|
78
|
+
i("span", {
|
|
79
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
80
|
+
"aria-hidden": "true",
|
|
81
|
+
innerHTML: H(S)("progress")
|
|
82
|
+
}, null, 8, E),
|
|
83
|
+
i("p", null, r(l("viewer.loading", "Loading…")), 1)
|
|
84
|
+
])) : c.value.length === 0 ? (s(), o("div", N, [
|
|
85
|
+
i("span", {
|
|
86
|
+
class: "filex-viewer-fallback__icon",
|
|
87
|
+
"aria-hidden": "true",
|
|
88
|
+
innerHTML: w.value
|
|
89
|
+
}, null, 8, I),
|
|
90
|
+
i("p", null, r(l("viewer.archive.empty", "Archive is empty.")), 1)
|
|
91
|
+
])) : (s(), o("div", O, [
|
|
92
|
+
i("div", V, r(l("viewer.archive.entries", `${p.value} files`, { n: p.value })) + " · " + r(_(y.value)), 1),
|
|
93
|
+
i("table", j, [
|
|
94
|
+
i("thead", null, [
|
|
95
|
+
i("tr", null, [
|
|
96
|
+
i("th", null, r(l("viewer.name", "Name")), 1),
|
|
97
|
+
i("th", A, r(l("viewer.size", "Size")), 1)
|
|
98
|
+
])
|
|
99
|
+
]),
|
|
100
|
+
i("tbody", null, [
|
|
101
|
+
(s(!0), o(M, null, z(c.value, (n, T) => (s(), o("tr", {
|
|
102
|
+
key: T,
|
|
103
|
+
"data-dir": n.is_dir ? "1" : "0"
|
|
104
|
+
}, [
|
|
105
|
+
i("td", null, [
|
|
106
|
+
i("span", {
|
|
107
|
+
class: "filex-viewer-archive__icon",
|
|
108
|
+
"aria-hidden": "true",
|
|
109
|
+
innerHTML: k(n)
|
|
110
|
+
}, null, 8, D),
|
|
111
|
+
C(" " + r(n.name), 1)
|
|
112
|
+
]),
|
|
113
|
+
i("td", G, r(n.is_dir ? "" : _(n.size)), 1)
|
|
114
|
+
], 8, U))), 128))
|
|
115
|
+
])
|
|
116
|
+
])
|
|
117
|
+
]))
|
|
118
|
+
]));
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
export {
|
|
122
|
+
q as default
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=ArchiveViewer-BNqukFg8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArchiveViewer-BNqukFg8.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';\nimport { actionIconSvg } from '../lib/actionIcons'; /* ikon:emoji */\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\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, vars?: Record<string, string | number>) => 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\n/** ⚠ `vars` go THROUGH `t()`, not into a `.replace()` afterwards: `t()` is what\n * picks the singular (`viewer.archive.entries_one`) from the count, and it can\n * only do that if it is told the count. Same shape CsvViewer's helper has. */\nfunction tt(key: string, fallback: string, vars?: Record<string, string | number>): string {\n return props.t ? props.t(key, vars) : 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\n/* === ikon:emoji — the fallback screen's mark ==========================\n * Every viewer opened its \"cannot show this\" / \"still loading\" screen with a\n * 48px colour emoji, one per format, each from whatever emoji font the OS\n * shipped. The format mark is `lib/fileIcons`'s tile — the SAME tile the row\n * the person just clicked is wearing, so the fallback is recognisably about\n * that file — and \"loading\" is the stroked ring, spun by CSS, because no\n * still picture can say \"still going\". */\nconst typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ext }));\n\n/** A row inside the archive, drawn the way the listing draws the same kind. */\nfunction entryTile(e: ArchiveEntry): string {\n const name = e.name || '';\n const dot = name.lastIndexOf('.');\n return fileIconTile({\n type: e.is_dir ? 'dir' : 'file',\n extension: dot > 0 ? name.slice(dot + 1) : '',\n basename: name,\n });\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-archive\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></span>\n <p>{{ error }}</p>\n </div>\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span\n class=\"filex-viewer-fallback__icon filex-viewer-fallback__icon--spin\"\n aria-hidden=\"true\"\n v-html=\"actionIconSvg('progress')\"\n ></span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div v-else-if=\"entries.length === 0\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></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 <!-- ⚠ The count is IN the message (\"{n} files\"). A `{{ fileCount }}`\n printed in front of it read \"3 3 files\". -->\n {{ tt('viewer.archive.entries', `${fileCount} files`, { n: 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 <!-- ikon:emoji — the same tile the listing draws for the same\n kind of file, so an archive's contents and the folder it\n came from read as one product. -->\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons -->\n <span class=\"filex-viewer-archive__icon\" aria-hidden=\"true\" v-html=\"entryTile(e)\"></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","vars","fmtSize","n","load","res","body","err","onMounted","watch","totalSize","computed","sum","e","fileCount","typeTile","fileIconTile","entryTile","name","dot","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_4","_unref","actionIconSvg","_hoisted_6","_hoisted_8","_hoisted_9","_toDisplayString","_hoisted_10","_hoisted_11","_Fragment","_renderList","i","_hoisted_14"],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { defineComponent as B, ref as v, onMounted as N, watch as b, computed as f, openBlock as s, createElementBlock as r, createElementVNode as n, toDisplayString as d, unref as W, Fragment as k, renderList as L, createCommentVNode as j } from "vue";
|
|
2
|
+
import { f as q, a as A } from "./index-BraG7Cz4.js";
|
|
3
|
+
import { f as G } from "./useViewerFetch-czqbd2Lj.js";
|
|
4
|
+
const O = { class: "filex-viewer-csv" }, Z = { class: "filex-viewer-csv__pane" }, z = {
|
|
5
|
+
key: 0,
|
|
6
|
+
class: "filex-viewer-fallback"
|
|
7
|
+
}, J = ["innerHTML"], K = {
|
|
8
|
+
key: 1,
|
|
9
|
+
class: "filex-viewer-fallback"
|
|
10
|
+
}, Q = ["innerHTML"], U = {
|
|
11
|
+
key: 2,
|
|
12
|
+
class: "filex-viewer-csv__table"
|
|
13
|
+
}, X = { class: "filex-viewer-csv__rownum" }, Y = {
|
|
14
|
+
key: 0,
|
|
15
|
+
class: "filex-viewer-csv__pager"
|
|
16
|
+
}, ee = ["disabled"], te = { class: "filex-viewer-csv__pageno" }, le = ["disabled"], C = 100, D = 1e3, re = /* @__PURE__ */ B({
|
|
17
|
+
__name: "CsvViewer",
|
|
18
|
+
props: {
|
|
19
|
+
url: {},
|
|
20
|
+
ext: {},
|
|
21
|
+
t: { type: Function },
|
|
22
|
+
authHeaders: { type: Function },
|
|
23
|
+
authCredentials: {}
|
|
24
|
+
},
|
|
25
|
+
setup(P) {
|
|
26
|
+
const i = P, o = v([]), _ = v(null), h = v(!0), T = v(!0), M = v(""), u = v(1), m = v(","), w = v("auto");
|
|
27
|
+
let H = 0;
|
|
28
|
+
function R(l) {
|
|
29
|
+
const e = l.split(/\r?\n/).slice(0, 5).join(`
|
|
30
|
+
`), t = (e.match(/\t/g) || []).length, a = (e.match(/;/g) || []).length, c = (e.match(/,/g) || []).length;
|
|
31
|
+
return t > c && t > a ? " " : a > c && a > t ? ";" : ",";
|
|
32
|
+
}
|
|
33
|
+
async function V(l, e) {
|
|
34
|
+
try {
|
|
35
|
+
const t = await import(
|
|
36
|
+
/* @vite-ignore */
|
|
37
|
+
"./papaparse.min-VB1HBwYX.js"
|
|
38
|
+
).then((y) => y.p);
|
|
39
|
+
return (t.default ?? t).parse(l, {
|
|
40
|
+
delimiter: e,
|
|
41
|
+
skipEmptyLines: !0,
|
|
42
|
+
header: !1
|
|
43
|
+
}).data.slice(0, D);
|
|
44
|
+
} catch {
|
|
45
|
+
return l.split(/\r?\n/).filter((t) => t.length > 0).slice(0, D).map((t) => t.split(e));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function g() {
|
|
49
|
+
var a;
|
|
50
|
+
h.value = !0, _.value = null, o.value = [], u.value = 1;
|
|
51
|
+
const l = ++H;
|
|
52
|
+
let e;
|
|
53
|
+
try {
|
|
54
|
+
e = await G({
|
|
55
|
+
url: i.url,
|
|
56
|
+
headers: await ((a = i.authHeaders) == null ? void 0 : a.call(i)) ?? {},
|
|
57
|
+
credentials: i.authCredentials
|
|
58
|
+
});
|
|
59
|
+
} catch (c) {
|
|
60
|
+
_.value = c instanceof Error ? c.message : "fetch failed", h.value = !1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (l !== H) return;
|
|
64
|
+
i.ext === "tsv" ? m.value = " " : m.value = R(e.slice(0, 4096));
|
|
65
|
+
const t = w.value === "auto" ? m.value : w.value;
|
|
66
|
+
o.value = await V(e, t), h.value = !1;
|
|
67
|
+
}
|
|
68
|
+
N(g), b(() => i.url, g), b(() => w.value, () => {
|
|
69
|
+
o.value.length !== 0 && g();
|
|
70
|
+
});
|
|
71
|
+
const $ = f(() => !T.value || o.value.length === 0 ? o.value.length === 0 ? [] : o.value[0].map((l, e) => `Col ${e + 1}`) : o.value[0]), E = f(() => T.value ? o.value.slice(1) : o.value), p = f(() => {
|
|
72
|
+
const l = M.value.trim().toLowerCase();
|
|
73
|
+
return l ? E.value.filter(
|
|
74
|
+
(e) => e.some((t) => (t || "").toLowerCase().includes(l))
|
|
75
|
+
) : E.value;
|
|
76
|
+
}), x = f(
|
|
77
|
+
() => Math.max(1, Math.ceil(p.value.length / C))
|
|
78
|
+
), F = f(() => {
|
|
79
|
+
const l = (u.value - 1) * C;
|
|
80
|
+
return p.value.slice(l, l + C);
|
|
81
|
+
});
|
|
82
|
+
b(M, () => {
|
|
83
|
+
u.value = 1;
|
|
84
|
+
});
|
|
85
|
+
function I(l, e, t) {
|
|
86
|
+
return i.t ? i.t(l, t) : e;
|
|
87
|
+
}
|
|
88
|
+
const S = f(() => q({ type: "file", extension: i.ext }));
|
|
89
|
+
return (l, e) => (s(), r("div", O, [
|
|
90
|
+
n("div", Z, [
|
|
91
|
+
_.value ? (s(), r("div", z, [
|
|
92
|
+
n("span", {
|
|
93
|
+
class: "filex-viewer-fallback__icon",
|
|
94
|
+
"aria-hidden": "true",
|
|
95
|
+
innerHTML: S.value
|
|
96
|
+
}, null, 8, J),
|
|
97
|
+
n("p", null, d(_.value), 1)
|
|
98
|
+
])) : h.value ? (s(), r("div", K, [
|
|
99
|
+
n("span", {
|
|
100
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
101
|
+
"aria-hidden": "true",
|
|
102
|
+
innerHTML: W(A)("progress")
|
|
103
|
+
}, null, 8, Q),
|
|
104
|
+
n("p", null, d(I("viewer.loading", "Loading…")), 1)
|
|
105
|
+
])) : (s(), r("table", U, [
|
|
106
|
+
n("thead", null, [
|
|
107
|
+
n("tr", null, [
|
|
108
|
+
e[2] || (e[2] = n("th", { class: "filex-viewer-csv__rownum" }, "#", -1)),
|
|
109
|
+
(s(!0), r(k, null, L($.value, (t, a) => (s(), r("th", { key: a }, d(t), 1))), 128))
|
|
110
|
+
])
|
|
111
|
+
]),
|
|
112
|
+
n("tbody", null, [
|
|
113
|
+
(s(!0), r(k, null, L(F.value, (t, a) => (s(), r("tr", { key: a }, [
|
|
114
|
+
n("td", X, d((u.value - 1) * 100 + a + 1), 1),
|
|
115
|
+
(s(!0), r(k, null, L(t, (c, y) => (s(), r("td", { key: y }, d(c), 1))), 128))
|
|
116
|
+
]))), 128))
|
|
117
|
+
])
|
|
118
|
+
]))
|
|
119
|
+
]),
|
|
120
|
+
!h.value && !_.value && x.value > 1 ? (s(), r("div", Y, [
|
|
121
|
+
n("button", {
|
|
122
|
+
type: "button",
|
|
123
|
+
class: "filex-viewer-btn",
|
|
124
|
+
disabled: u.value <= 1,
|
|
125
|
+
onClick: e[0] || (e[0] = (t) => u.value--)
|
|
126
|
+
}, "‹", 8, ee),
|
|
127
|
+
n("span", te, d(u.value) + " / " + d(x.value) + " (" + d(I("viewer.csv_rows", `${p.value.length} rows`, { n: p.value.length })) + ")", 1),
|
|
128
|
+
n("button", {
|
|
129
|
+
type: "button",
|
|
130
|
+
class: "filex-viewer-btn",
|
|
131
|
+
disabled: u.value >= x.value,
|
|
132
|
+
onClick: e[1] || (e[1] = (t) => u.value++)
|
|
133
|
+
}, "›", 8, le)
|
|
134
|
+
])) : j("", !0)
|
|
135
|
+
]));
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
export {
|
|
139
|
+
re as default
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=CsvViewer-ii_-MgmG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CsvViewer-ii_-MgmG.js","sources":["../src/viewers/CsvViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * CsvViewer — lightweight CSV / TSV table preview.\n *\n * Lazy-imports `papaparse` when available (best-quality parser — handles\n * embedded quotes, multi-line cells, etc). Falls back to a simple\n * `split` parser when the peer is missing — workable for the trivial\n * \"first 1000 rows\" preview case but loses fidelity on complex files.\n *\n * UX:\n * - first-row-as-header toggle\n * - filter input that case-insensitively matches any cell\n * - 100-rows-per-page pagination\n * - tab vs comma auto-detection (manual override via toolbar)\n */\nimport { computed, onMounted, ref, watch } from 'vue';\nimport { actionIconSvg } from '../lib/actionIcons'; /* ikon:emoji */\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\nimport { fetchViewerText } from '../composables/useViewerFetch';\n\nconst props = defineProps<{\n url: string;\n ext: string;\n t?: (key: string, vars?: Record<string, string | number>) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n}>();\n\nconst PAGE_SIZE = 100;\nconst ROW_LIMIT = 1000;\n\nconst rows = ref<string[][]>([]);\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst firstRowHeader = ref(true);\nconst filter = ref('');\nconst page = ref(1);\nconst detectedDelim = ref<',' | '\\t' | ';'>(',');\nconst userDelim = ref<'auto' | ',' | '\\t' | ';'>('auto');\n\nlet renderToken = 0;\n\nfunction detectDelimiter(sample: string): ',' | '\\t' | ';' {\n const sampleLines = sample.split(/\\r?\\n/).slice(0, 5).join('\\n');\n const tab = (sampleLines.match(/\\t/g) || []).length;\n const semi = (sampleLines.match(/;/g) || []).length;\n const comma = (sampleLines.match(/,/g) || []).length;\n if (tab > comma && tab > semi) return '\\t';\n if (semi > comma && semi > tab) return ';';\n return ',';\n}\n\nasync function parseWith(text: string, delim: string): Promise<string[][]> {\n try {\n const mod = await import(/* @vite-ignore */ 'papaparse');\n const Papa = (mod as any).default ?? mod;\n const result = Papa.parse(text, {\n delimiter: delim,\n skipEmptyLines: true,\n header: false,\n });\n return (result.data as string[][]).slice(0, ROW_LIMIT);\n } catch {\n // Fallback: naive line/column split. Loses quoted-comma support\n // but renders something reasonable.\n return text\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0)\n .slice(0, ROW_LIMIT)\n .map((line) => line.split(delim));\n }\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n rows.value = [];\n page.value = 1;\n const myToken = ++renderToken;\n\n let text: string;\n try {\n text = await fetchViewerText({\n url: props.url,\n headers: (await 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 if (props.ext === 'tsv') {\n detectedDelim.value = '\\t';\n } else {\n detectedDelim.value = detectDelimiter(text.slice(0, 4096));\n }\n\n const delim = userDelim.value === 'auto' ? detectedDelim.value : userDelim.value;\n rows.value = await parseWith(text, delim);\n loading.value = false;\n}\n\nonMounted(load);\nwatch(() => props.url, load);\nwatch(() => userDelim.value, () => {\n if (rows.value.length === 0) return;\n // Re-parse with the new delimiter using the cached source — but we\n // didn't keep it. Cheapest path is a refetch.\n load();\n});\n\nconst headers = computed<string[]>(() => {\n if (!firstRowHeader.value || rows.value.length === 0) {\n if (rows.value.length === 0) return [];\n return rows.value[0].map((_, i) => `Col ${i + 1}`);\n }\n return rows.value[0];\n});\n\nconst dataRows = computed<string[][]>(() => {\n return firstRowHeader.value ? rows.value.slice(1) : rows.value;\n});\n\nconst filtered = computed<string[][]>(() => {\n const q = filter.value.trim().toLowerCase();\n if (!q) return dataRows.value;\n return dataRows.value.filter((r) =>\n r.some((c) => (c || '').toLowerCase().includes(q)),\n );\n});\n\nconst totalPages = computed(() =>\n Math.max(1, Math.ceil(filtered.value.length / PAGE_SIZE)),\n);\n\nconst visibleRows = computed<string[][]>(() => {\n const start = (page.value - 1) * PAGE_SIZE;\n return filtered.value.slice(start, start + PAGE_SIZE);\n});\n\nwatch(filter, () => {\n page.value = 1;\n});\n\nfunction tt(key: string, fallback: string, vars?: Record<string, string | number>): string {\n return props.t ? props.t(key, vars) : fallback;\n}\n\n/* === ikon:emoji — the fallback screen's mark ==========================\n * Every viewer opened its \"cannot show this\" / \"still loading\" screen with a\n * 48px colour emoji, one per format, each from whatever emoji font the OS\n * shipped. The format mark is `lib/fileIcons`'s tile — the SAME tile the row\n * the person just clicked is wearing, so the fallback is recognisably about\n * that file — and \"loading\" is the stroked ring, spun by CSS, because no\n * still picture can say \"still going\". */\nconst typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ext }));\n</script>\n\n<template>\n <div class=\"filex-viewer-csv\">\n <div class=\"filex-viewer-csv__pane\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></span>\n <p>{{ error }}</p>\n </div>\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span\n class=\"filex-viewer-fallback__icon filex-viewer-fallback__icon--spin\"\n aria-hidden=\"true\"\n v-html=\"actionIconSvg('progress')\"\n ></span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <table v-else class=\"filex-viewer-csv__table\">\n <thead>\n <tr>\n <th class=\"filex-viewer-csv__rownum\">#</th>\n <th v-for=\"(h, i) in headers\" :key=\"i\">{{ h }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, ri) in visibleRows\" :key=\"ri\">\n <td class=\"filex-viewer-csv__rownum\">{{ (page - 1) * 100 + ri + 1 }}</td>\n <td v-for=\"(c, ci) in row\" :key=\"ci\">{{ c }}</td>\n </tr>\n </tbody>\n </table>\n </div>\n <div v-if=\"!loading && !error && totalPages > 1\" class=\"filex-viewer-csv__pager\">\n <button\n type=\"button\"\n class=\"filex-viewer-btn\"\n :disabled=\"page <= 1\"\n @click=\"page--\"\n >‹</button>\n <span class=\"filex-viewer-csv__pageno\">{{ page }} / {{ totalPages }} ({{ tt('viewer.csv_rows', `${filtered.length} rows`, { n: filtered.length }) }})</span>\n <button\n type=\"button\"\n class=\"filex-viewer-btn\"\n :disabled=\"page >= totalPages\"\n @click=\"page++\"\n >›</button>\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-csv {\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-csv__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}\n.filex-viewer-csv__check {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n}\n.filex-viewer-csv__select,\n.filex-viewer-csv__filter {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: inherit;\n padding: 4px 8px;\n border-radius: 4px;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-csv__filter {\n flex: 0 1 240px;\n}\n.filex-viewer-spacer { flex: 1; }\n.filex-viewer-csv__count {\n font-size: 11px;\n color: var(--fe-text-muted, #5a6475);\n font-variant-numeric: tabular-nums;\n}\n.filex-viewer-csv__pane {\n flex: 1;\n overflow: auto;\n}\n.filex-viewer-csv__table {\n border-collapse: collapse;\n width: max-content;\n min-width: 100%;\n font-size: 12px;\n font-family: var(--fe-font-mono, monospace);\n}\n.filex-viewer-csv__table th,\n.filex-viewer-csv__table td {\n padding: 4px 10px;\n border: 1px solid var(--fe-border, #e2e6ed);\n white-space: nowrap;\n max-width: 320px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.filex-viewer-csv__table th {\n background: var(--fe-bg-elev, #f7f8fa);\n position: sticky;\n top: 0;\n font-weight: 600;\n text-align: left;\n}\n.filex-viewer-csv__table tbody tr:nth-child(even) {\n background: var(--fe-bg-hover, rgba(0, 0, 0, 0.02));\n}\n.filex-viewer-csv__rownum {\n color: var(--fe-text-muted, #5a6475);\n text-align: right;\n background: var(--fe-bg-elev, #f7f8fa);\n font-variant-numeric: tabular-nums;\n position: sticky;\n left: 0;\n}\n.filex-viewer-csv__pager {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 8px;\n padding: 6px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-top: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n}\n.filex-viewer-csv__pageno {\n font-variant-numeric: tabular-nums;\n font-size: 12px;\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.4;\n cursor: not-allowed;\n}\n</style>\n"],"names":["PAGE_SIZE","ROW_LIMIT","props","__props","rows","ref","error","loading","firstRowHeader","filter","page","detectedDelim","userDelim","renderToken","detectDelimiter","sample","sampleLines","tab","semi","comma","parseWith","text","delim","mod","n","l","line","load","myToken","fetchViewerText","_a","err","onMounted","watch","headers","computed","_","i","dataRows","filtered","q","r","c","totalPages","visibleRows","start","tt","key","fallback","vars","typeTile","fileIconTile","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_5","_unref","actionIconSvg","_hoisted_7","_cache","_Fragment","_renderList","h","row","ri","_hoisted_8","_toDisplayString","ci","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { f as C } from "./
|
|
3
|
-
|
|
1
|
+
import { defineComponent as E, ref as s, computed as u, onMounted as S, watch as T, onBeforeUnmount as B, openBlock as c, createElementBlock as d, createElementVNode as g, toDisplayString as O } from "vue";
|
|
2
|
+
import { f as C } from "./index-BraG7Cz4.js";
|
|
3
|
+
import { f as H } from "./useViewerFetch-czqbd2Lj.js";
|
|
4
|
+
const L = { class: "filex-viewer-drawio" }, M = {
|
|
4
5
|
key: 0,
|
|
5
6
|
class: "filex-viewer-fallback"
|
|
6
|
-
}, N = ["src"],
|
|
7
|
+
}, $ = ["innerHTML"], N = ["src"], J = /* @__PURE__ */ E({
|
|
7
8
|
__name: "DrawioViewer",
|
|
8
9
|
props: {
|
|
9
10
|
url: {},
|
|
@@ -17,51 +18,51 @@ const T = { class: "filex-viewer-drawio" }, $ = {
|
|
|
17
18
|
authCredentials: {}
|
|
18
19
|
},
|
|
19
20
|
setup(x) {
|
|
20
|
-
const e = x,
|
|
21
|
+
const e = x, f = s(null), i = s(null), n = s("loading"), v = s(!!e.readOnly || !e.saveUrl), o = u(
|
|
21
22
|
() => e.drawioUrl ? e.drawioUrl.replace(/\/$/, "") : null
|
|
22
|
-
), _ =
|
|
23
|
+
), _ = u(() => {
|
|
23
24
|
if (!o.value) return "";
|
|
24
25
|
const a = new URLSearchParams({
|
|
25
26
|
embed: "1",
|
|
26
27
|
proto: "json",
|
|
27
28
|
spin: "1",
|
|
28
29
|
saveAndExit: "0",
|
|
29
|
-
noSaveBtn:
|
|
30
|
+
noSaveBtn: v.value ? "1" : "0",
|
|
30
31
|
noExitBtn: "1",
|
|
31
32
|
ui: "kennedy",
|
|
32
33
|
modified: "unsavedChanges"
|
|
33
34
|
});
|
|
34
35
|
return `${o.value}/?${a.toString()}`;
|
|
35
36
|
});
|
|
36
|
-
let
|
|
37
|
+
let m = "";
|
|
37
38
|
async function k() {
|
|
38
39
|
var a;
|
|
39
40
|
n.value = "loading", i.value = null;
|
|
40
41
|
try {
|
|
41
|
-
|
|
42
|
+
m = await H({
|
|
42
43
|
url: e.url,
|
|
43
44
|
headers: await ((a = e.authHeaders) == null ? void 0 : a.call(e)) ?? {},
|
|
44
45
|
credentials: e.authCredentials
|
|
45
46
|
});
|
|
46
|
-
} catch (
|
|
47
|
-
i.value =
|
|
47
|
+
} catch (r) {
|
|
48
|
+
i.value = r instanceof Error ? r.message : "fetch failed", n.value = "error";
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
function b(a) {
|
|
51
|
-
var
|
|
52
|
-
(
|
|
52
|
+
var r, t;
|
|
53
|
+
(t = (r = f.value) == null ? void 0 : r.contentWindow) == null || t.postMessage(JSON.stringify(a), "*");
|
|
53
54
|
}
|
|
54
|
-
async function
|
|
55
|
-
var
|
|
55
|
+
async function h(a) {
|
|
56
|
+
var r;
|
|
56
57
|
if (e.saveUrl) {
|
|
57
58
|
n.value = "saving";
|
|
58
59
|
try {
|
|
59
|
-
const
|
|
60
|
+
const t = {
|
|
60
61
|
"Content-Type": "application/json",
|
|
61
|
-
...await ((
|
|
62
|
+
...await ((r = e.authHeaders) == null ? void 0 : r.call(e)) ?? {}
|
|
62
63
|
}, l = await fetch(e.saveUrl, {
|
|
63
64
|
method: "POST",
|
|
64
|
-
headers:
|
|
65
|
+
headers: t,
|
|
65
66
|
credentials: e.authCredentials || "same-origin",
|
|
66
67
|
body: JSON.stringify({ path: e.filePath, content: a })
|
|
67
68
|
});
|
|
@@ -70,63 +71,68 @@ const T = { class: "filex-viewer-drawio" }, $ = {
|
|
|
70
71
|
n.value = "saved", setTimeout(() => {
|
|
71
72
|
n.value === "saved" && (n.value = "ready");
|
|
72
73
|
}, 2500);
|
|
73
|
-
} catch (
|
|
74
|
-
i.value =
|
|
74
|
+
} catch (t) {
|
|
75
|
+
i.value = t instanceof Error ? t.message : "save failed", n.value = "error";
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
function w(a) {
|
|
79
80
|
if (typeof a.data != "string" || a.data.length === 0) return;
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
let
|
|
81
|
+
const r = a.data[0];
|
|
82
|
+
if (r !== "{" && r !== "<") return;
|
|
83
|
+
let t;
|
|
83
84
|
try {
|
|
84
|
-
|
|
85
|
+
t = JSON.parse(a.data);
|
|
85
86
|
} catch {
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
|
-
if (!(!
|
|
89
|
-
switch (
|
|
89
|
+
if (!(!t || typeof t != "object"))
|
|
90
|
+
switch (t.event) {
|
|
90
91
|
case "init":
|
|
91
92
|
b({
|
|
92
93
|
action: "load",
|
|
93
|
-
xml:
|
|
94
|
+
xml: m,
|
|
94
95
|
autosave: 0
|
|
95
96
|
}), n.value = "ready";
|
|
96
97
|
break;
|
|
97
98
|
case "save":
|
|
98
|
-
typeof
|
|
99
|
+
typeof t.xml == "string" && h(t.xml);
|
|
99
100
|
break;
|
|
100
101
|
case "export":
|
|
101
102
|
break;
|
|
102
103
|
case "autosave":
|
|
103
|
-
typeof
|
|
104
|
+
typeof t.xml == "string" && !v.value && h(t.xml);
|
|
104
105
|
break;
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
|
-
function
|
|
108
|
+
function p() {
|
|
108
109
|
if (!o.value) {
|
|
109
110
|
i.value = y("viewer.drawio.disabled", "diagrams.net is not configured for this filex instance."), n.value = "error";
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
113
|
i.value === y("viewer.drawio.disabled", "diagrams.net is not configured for this filex instance.") && (i.value = null, n.value = "loading"), k();
|
|
113
114
|
}
|
|
114
|
-
|
|
115
|
-
window.addEventListener("message", w),
|
|
116
|
-
}),
|
|
115
|
+
S(() => {
|
|
116
|
+
window.addEventListener("message", w), p();
|
|
117
|
+
}), T(() => e.drawioUrl, p), B(() => {
|
|
117
118
|
window.removeEventListener("message", w);
|
|
118
119
|
});
|
|
119
|
-
function y(a,
|
|
120
|
-
return e.t ? e.t(a) :
|
|
120
|
+
function y(a, r) {
|
|
121
|
+
return e.t ? e.t(a) : r;
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
const U = u(() => C({ type: "file", extension: e.ext }));
|
|
124
|
+
return (a, r) => (c(), d("div", L, [
|
|
125
|
+
i.value ? (c(), d("div", M, [
|
|
126
|
+
g("span", {
|
|
127
|
+
class: "filex-viewer-fallback__icon",
|
|
128
|
+
"aria-hidden": "true",
|
|
129
|
+
innerHTML: U.value
|
|
130
|
+
}, null, 8, $),
|
|
125
131
|
g("p", null, O(i.value), 1)
|
|
126
|
-
])) : (
|
|
132
|
+
])) : (c(), d("iframe", {
|
|
127
133
|
key: 1,
|
|
128
134
|
ref_key: "iframeRef",
|
|
129
|
-
ref:
|
|
135
|
+
ref: f,
|
|
130
136
|
src: _.value,
|
|
131
137
|
class: "filex-viewer-drawio__frame",
|
|
132
138
|
title: "diagrams.net editor"
|
|
@@ -135,6 +141,6 @@ const T = { class: "filex-viewer-drawio" }, $ = {
|
|
|
135
141
|
}
|
|
136
142
|
});
|
|
137
143
|
export {
|
|
138
|
-
|
|
144
|
+
J as default
|
|
139
145
|
};
|
|
140
|
-
//# sourceMappingURL=DrawioViewer-
|
|
146
|
+
//# sourceMappingURL=DrawioViewer-B2tuu4rX.js.map
|