@brftech/filex-core 0.42.1 → 0.43.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.
Files changed (233) hide show
  1. package/README.md +14 -2
  2. package/dist/ArchiveViewer-BqU761Wk.js +149 -0
  3. package/dist/ArchiveViewer-BqU761Wk.js.map +1 -0
  4. package/dist/CsvViewer-ByHVK5ga.js +172 -0
  5. package/dist/CsvViewer-ByHVK5ga.js.map +1 -0
  6. package/dist/{DrawioViewer-BuhZOAx6.js → DrawioViewer-Bgrj8-zG.js} +45 -44
  7. package/dist/DrawioViewer-Bgrj8-zG.js.map +1 -0
  8. package/dist/{EpubViewer-DS3mb3k8.js → EpubViewer-DJwUKlHW.js} +50 -50
  9. package/dist/EpubViewer-DJwUKlHW.js.map +1 -0
  10. package/dist/IpynbViewer-Bz0eJ4NS.js +184 -0
  11. package/dist/IpynbViewer-Bz0eJ4NS.js.map +1 -0
  12. package/dist/MermaidViewer-CEDTD_pp.js +136 -0
  13. package/dist/MermaidViewer-CEDTD_pp.js.map +1 -0
  14. package/dist/PsdViewer-CZcxUpZO.js +121 -0
  15. package/dist/PsdViewer-CZcxUpZO.js.map +1 -0
  16. package/dist/TiffViewer-BwI62CbQ.js +141 -0
  17. package/dist/TiffViewer-BwI62CbQ.js.map +1 -0
  18. package/dist/{Viewer3D-CIrOn63I.js → Viewer3D-DoeZcuMm.js} +16 -16
  19. package/dist/Viewer3D-DoeZcuMm.js.map +1 -0
  20. package/dist/filex-core.js +475 -219
  21. package/dist/filex-core.umd.cjs +165 -108
  22. package/dist/filex-core.umd.cjs.map +1 -1
  23. package/dist/fonts/caveat-latin-ext.woff2 +0 -0
  24. package/dist/fonts/caveat-latin.woff2 +0 -0
  25. package/dist/fonts/dancing-script-latin-ext.woff2 +0 -0
  26. package/dist/fonts/dancing-script-latin.woff2 +0 -0
  27. package/dist/fonts/homemade-apple-latin.woff2 +0 -0
  28. package/dist/fonts/source-serif-4-latin-ext.woff2 +0 -0
  29. package/dist/fonts/source-serif-4-latin.woff2 +0 -0
  30. package/dist/index-DuWnGuv5.js +35901 -0
  31. package/dist/index-DuWnGuv5.js.map +1 -0
  32. package/dist/index.d.ts +5241 -553
  33. package/dist/pdf-CaPYsOUo.js +21302 -0
  34. package/dist/pdf-CaPYsOUo.js.map +1 -0
  35. package/dist/style.css +1 -1
  36. package/package.json +1 -1
  37. package/src/FileExplorer.vue +1207 -343
  38. package/src/assets/fonts/LICENSE-Apache-2.0.txt +202 -0
  39. package/src/assets/fonts/LICENSE-OFL-1.1.txt +93 -0
  40. package/src/assets/fonts/README.md +58 -0
  41. package/src/assets/fonts/caveat-latin-ext.woff2 +0 -0
  42. package/src/assets/fonts/caveat-latin.woff2 +0 -0
  43. package/src/assets/fonts/dancing-script-latin-ext.woff2 +0 -0
  44. package/src/assets/fonts/dancing-script-latin.woff2 +0 -0
  45. package/src/assets/fonts/homemade-apple-latin.woff2 +0 -0
  46. package/src/assets/fonts/source-serif-4-latin-ext.woff2 +0 -0
  47. package/src/assets/fonts/source-serif-4-latin.woff2 +0 -0
  48. package/src/components/AdvancedSearch.vue +49 -0
  49. package/src/components/Breadcrumb.vue +5 -5
  50. package/src/components/ChoiceButtons.vue +152 -0
  51. package/src/components/CommandPalette.vue +5 -5
  52. package/src/components/ConnectionGuideView.vue +1 -1
  53. package/src/components/ConnectionNotice.vue +59 -0
  54. package/src/components/ConnectionsPanel.vue +30 -568
  55. package/src/components/ContextMenu.vue +31 -5
  56. package/src/components/DataTable.vue +1331 -0
  57. package/src/components/FilePane.vue +3 -0
  58. package/src/components/FilterBar.vue +12 -5
  59. package/src/components/GalleryView.vue +50 -2
  60. package/src/components/GridView.vue +51 -3
  61. package/src/components/HomeView.vue +18 -6
  62. package/src/components/InspectorPanel.vue +134 -17
  63. package/src/components/ListView.vue +366 -900
  64. package/src/components/LogoMark.vue +57 -0
  65. package/src/components/NFSExportsPanel.vue +76 -28
  66. package/src/components/OnboardingTour.vue +19 -7
  67. package/src/components/OperationsCenter.vue +77 -1
  68. package/src/components/PendingOpsTray.vue +59 -5
  69. package/src/components/PresenceBar.vue +7 -7
  70. package/src/components/ProductVersion.vue +31 -0
  71. package/src/components/QuickLook.vue +10 -14
  72. package/src/components/RecentlyOpened.vue +47 -17
  73. package/src/components/RecoveryKeyModal.vue +1 -1
  74. package/src/components/RowActions.vue +134 -0
  75. package/src/components/S3KeysPanel.vue +98 -56
  76. package/src/components/SSHKeysPanel.vue +79 -26
  77. package/src/components/SideNav.vue +260 -96
  78. package/src/components/StarButton.vue +1 -0
  79. package/src/components/StorageFields.vue +74 -6
  80. package/src/components/StorageTags.vue +62 -0
  81. package/src/components/TabBar.vue +1 -1
  82. package/src/components/TagKindIcon.vue +56 -0
  83. package/src/components/TagPicker.vue +226 -40
  84. package/src/components/ThemePalette.vue +4 -4
  85. package/src/components/TimeZonePicker.vue +29 -10
  86. package/src/components/TokensPanel.vue +82 -27
  87. package/src/components/Toolbar.vue +28 -6
  88. package/src/components/plugin/PluginConfirmModal.vue +54 -0
  89. package/src/components/plugin/PluginInspectorSection.vue +149 -0
  90. package/src/components/plugin/PluginPageView.vue +339 -0
  91. package/src/components/plugin/PluginViewModal.vue +159 -0
  92. package/src/components/plugin/SurfaceConversation.vue +76 -0
  93. package/src/components/plugin/SurfaceFooterButtons.vue +73 -0
  94. package/src/components/plugin/SurfaceRenderer.vue +299 -0
  95. package/src/components/plugin/SurfaceSections.vue +91 -0
  96. package/src/components/plugin/nodes/PdfFieldEditor.vue +509 -0
  97. package/src/components/plugin/nodes/SurfaceFileChooser.vue +94 -0
  98. package/src/components/plugin/nodes/SurfaceForm.vue +82 -0
  99. package/src/components/plugin/nodes/SurfaceList.vue +127 -0
  100. package/src/components/plugin/nodes/SurfacePdfFields.vue +1285 -0
  101. package/src/components/plugin/nodes/SurfacePeoplePicker.vue +213 -0
  102. package/src/components/plugin/nodes/SurfacePinInput.vue +57 -0
  103. package/src/components/plugin/nodes/SurfacePreview.vue +119 -0
  104. package/src/components/plugin/nodes/SurfaceProgress.vue +48 -0
  105. package/src/components/plugin/nodes/SurfaceSignaturePad.vue +472 -0
  106. package/src/components/plugin/nodes/SurfaceSteps.vue +53 -0
  107. package/src/components/public/PublicLanguagePicker.vue +58 -0
  108. package/src/components/public/PublicLinkPage.vue +286 -0
  109. package/src/components/public/PublicLinkPreview.vue +85 -0
  110. package/src/components/public/PublicPinGate.vue +108 -0
  111. package/src/components/public/PublicRequestBody.vue +204 -0
  112. package/src/components/public/PublicShareBody.vue +188 -0
  113. package/src/components/public/PublicShell.vue +332 -0
  114. package/src/composables/useConnections.ts +8 -2
  115. package/src/composables/useFileApi.ts +183 -44
  116. package/src/composables/useLocale.ts +277 -41
  117. package/src/composables/useNFSExports.ts +8 -10
  118. package/src/composables/useOperations.ts +44 -3
  119. package/src/composables/usePendingOps.ts +59 -8
  120. package/src/composables/usePluginActions.ts +121 -0
  121. package/src/composables/usePluginSurface.ts +223 -0
  122. package/src/composables/usePublicBranding.ts +172 -0
  123. package/src/composables/usePublicLink.ts +573 -0
  124. package/src/composables/usePublicPage.ts +61 -0
  125. package/src/composables/useS3Keys.ts +17 -12
  126. package/src/composables/useSSHKeys.ts +8 -10
  127. package/src/composables/useTokens.ts +8 -12
  128. package/src/composables/useUploadChunked.ts +18 -8
  129. package/src/composables/useViewerFetch.ts +6 -3
  130. package/src/index.ts +404 -8
  131. package/src/lib/actionIcons.ts +46 -1
  132. package/src/lib/advSearch.ts +14 -7
  133. package/src/lib/appLock.ts +130 -0
  134. package/src/lib/connection.ts +110 -0
  135. package/src/lib/destinationTree.ts +19 -3
  136. package/src/lib/direction.ts +353 -0
  137. package/src/lib/dragGhost.ts +6 -0
  138. package/src/lib/dropLimits.ts +69 -0
  139. package/src/lib/errorWords.ts +394 -0
  140. package/src/lib/externalReach.ts +5 -1
  141. package/src/lib/fileFilters.ts +7 -2
  142. package/src/lib/fileIcons.ts +4 -0
  143. package/src/lib/internalPaths.ts +77 -0
  144. package/src/lib/listInput.ts +64 -0
  145. package/src/lib/listing.ts +58 -23
  146. package/src/lib/modalStack.ts +26 -0
  147. package/src/lib/nodeRow.ts +121 -0
  148. package/src/lib/pdfFieldRules.ts +126 -0
  149. package/src/lib/pdfFields.ts +589 -0
  150. package/src/lib/pdfFieldsGeom.ts +203 -0
  151. package/src/lib/pdfjsLoader.ts +51 -0
  152. package/src/lib/personName.ts +47 -0
  153. package/src/lib/pluginApplies.ts +123 -0
  154. package/src/lib/pluginLabel.ts +72 -0
  155. package/src/lib/pluginMenu.ts +253 -0
  156. package/src/lib/pluginPage.ts +58 -0
  157. package/src/lib/plural.ts +181 -0
  158. package/src/lib/popupLayer.ts +103 -0
  159. package/src/lib/prefs.ts +563 -0
  160. package/src/lib/productVersion.ts +35 -0
  161. package/src/lib/publicLayout.ts +39 -0
  162. package/src/lib/serviceGate.ts +104 -0
  163. package/src/lib/shareTtl.ts +25 -11
  164. package/src/lib/signFonts.ts +85 -0
  165. package/src/lib/signaturePad.ts +111 -0
  166. package/src/lib/sortOrder.ts +100 -38
  167. package/src/lib/star.ts +7 -1
  168. package/src/lib/surfaceCell.ts +41 -0
  169. package/src/lib/surfaceConditions.ts +156 -0
  170. package/src/lib/surfaceOpen.ts +106 -0
  171. package/src/lib/surfaceSteps.ts +68 -0
  172. package/src/lib/surfaceValues.ts +191 -0
  173. package/src/lib/symlink.ts +150 -0
  174. package/src/lib/tableColumns.ts +493 -0
  175. package/src/lib/tableEnv.ts +34 -0
  176. package/src/lib/tablePrefs.ts +84 -0
  177. package/src/lib/tags.ts +121 -12
  178. package/src/lib/themes.ts +286 -18
  179. package/src/lib/tour.ts +152 -0
  180. package/src/lib/trashEmpty.ts +111 -0
  181. package/src/lib/trashTimeLeft.ts +23 -0
  182. package/src/lib/uiLocales.ts +460 -0
  183. package/src/lib/viewPrefs.ts +696 -660
  184. package/src/lib/viewPrefsHttp.ts +78 -0
  185. package/src/locales/en.ts +522 -119
  186. package/src/locales/resolve.ts +17 -8
  187. package/src/locales/tr.ts +539 -155
  188. package/src/modals/ConvertModal.vue +62 -11
  189. package/src/modals/DestinationPickerModal.vue +59 -16
  190. package/src/modals/Modal.vue +113 -23
  191. package/src/modals/NewDocumentModal.vue +16 -6
  192. package/src/modals/NewFolderModal.vue +8 -0
  193. package/src/modals/PermissionsModal.vue +272 -163
  194. package/src/modals/PreviewModal.vue +119 -20
  195. package/src/modals/RenameModal.vue +37 -1
  196. package/src/styles/base.css +2895 -241
  197. package/src/styles/sign-fonts.css +118 -0
  198. package/src/styles/variables.css +60 -0
  199. package/src/types/Connections.ts +17 -0
  200. package/src/types/ExplorerConfig.ts +117 -1
  201. package/src/types/FileNode.ts +58 -0
  202. package/src/types/Plugins.ts +494 -0
  203. package/src/types/Public.ts +212 -0
  204. package/src/viewers/ArchiveViewer.vue +93 -48
  205. package/src/viewers/CsvViewer.vue +99 -53
  206. package/src/viewers/DrawioViewer.vue +35 -9
  207. package/src/viewers/EpubViewer.vue +7 -8
  208. package/src/viewers/IpynbViewer.vue +3 -1
  209. package/src/viewers/MermaidViewer.vue +4 -5
  210. package/src/viewers/PdfViewer.vue +8 -17
  211. package/src/viewers/PsdViewer.vue +2 -4
  212. package/src/viewers/TiffViewer.vue +4 -5
  213. package/src/viewers/Viewer3D.vue +1 -1
  214. package/LICENSE +0 -21
  215. package/dist/ArchiveViewer-CLNevfPE.js +0 -124
  216. package/dist/ArchiveViewer-CLNevfPE.js.map +0 -1
  217. package/dist/CsvViewer-K8XA3z7N.js +0 -141
  218. package/dist/CsvViewer-K8XA3z7N.js.map +0 -1
  219. package/dist/DrawioViewer-BuhZOAx6.js.map +0 -1
  220. package/dist/EpubViewer-DS3mb3k8.js.map +0 -1
  221. package/dist/IpynbViewer-BTk7p4Dn.js +0 -184
  222. package/dist/IpynbViewer-BTk7p4Dn.js.map +0 -1
  223. package/dist/MermaidViewer-DqucH_io.js +0 -137
  224. package/dist/MermaidViewer-DqucH_io.js.map +0 -1
  225. package/dist/PsdViewer-CwiVENmq.js +0 -122
  226. package/dist/PsdViewer-CwiVENmq.js.map +0 -1
  227. package/dist/TiffViewer-CpewSVmQ.js +0 -142
  228. package/dist/TiffViewer-CpewSVmQ.js.map +0 -1
  229. package/dist/Viewer3D-CIrOn63I.js.map +0 -1
  230. package/dist/index-Dx0IbBcI.js +0 -26831
  231. package/dist/index-Dx0IbBcI.js.map +0 -1
  232. package/dist/useViewerFetch-czqbd2Lj.js +0 -25
  233. package/dist/useViewerFetch-czqbd2Lj.js.map +0 -1
@@ -29,6 +29,9 @@ const props = defineProps<{
29
29
  t?: (key: string) => string;
30
30
  authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
31
31
  authCredentials?: RequestCredentials;
32
+ /** Could this person set up draw.io (`capabilities.caller_admin`)? Picks
33
+ * which sentence the "not configured" pane says — see `bootIfReady`. */
34
+ canConfigure?: boolean;
32
35
  }>();
33
36
 
34
37
  const iframeRef = ref<HTMLIFrameElement | null>(null);
@@ -76,7 +79,11 @@ async function loadXml(): Promise<void> {
76
79
  credentials: props.authCredentials,
77
80
  });
78
81
  } catch (err) {
79
- error.value = err instanceof Error ? err.message : 'fetch failed';
82
+ /* ⚠ A sentence, never `${status} ${statusText} — <body>` (which is what
83
+ fetchViewerText's error carries). The detail goes to the console. */
84
+ console.warn('[filex] diagram could not be read', err);
85
+ error.value = tt('viewer.drawio.load_failed', 'This diagram could not be read. Download it to open it elsewhere.');
86
+ disabledPane = false;
80
87
  status.value = 'error';
81
88
  }
82
89
  }
@@ -100,14 +107,19 @@ async function persist(xml: string): Promise<void> {
100
107
  body: JSON.stringify({ path: props.filePath, content: xml }),
101
108
  });
102
109
  if (!res.ok) {
103
- throw new Error(`${res.status} ${res.statusText}`);
110
+ /* ⚠ Never the HTTP layer on screen ("503 Service Unavailable" is what
111
+ this used to say when a save could not take its version snapshot). */
112
+ console.warn('[filex] diagram save failed', res.status, res.statusText);
113
+ throw new Error('save');
104
114
  }
105
115
  status.value = 'saved';
106
116
  setTimeout(() => {
107
117
  if (status.value === 'saved') status.value = 'ready';
108
118
  }, 2500);
109
119
  } catch (err) {
110
- error.value = err instanceof Error ? err.message : 'save failed';
120
+ console.warn('[filex] diagram save failed', err);
121
+ error.value = tt('viewer.drawio.save_failed', 'The diagram could not be saved. Your changes are still in the editor — try again.');
122
+ disabledPane = false;
111
123
  status.value = 'error';
112
124
  }
113
125
  }
@@ -152,15 +164,29 @@ function onMessage(ev: MessageEvent): void {
152
164
  }
153
165
  }
154
166
 
167
+ /** Is the pane on screen the "not configured" one (so a later answer that
168
+ * draw.io IS there can clear it)? A flag, not a comparison with the text:
169
+ * the text now depends on who is looking. */
170
+ let disabledPane = false;
171
+
155
172
  function bootIfReady(): void {
156
173
  if (!drawioBase.value) {
157
- error.value = tt('viewer.drawio.disabled', 'diagrams.net is not configured for this filex instance.');
174
+ /* The owner's rule for a missing service (2026-09-21): whoever can fix
175
+ it is told where; everybody else is told what they can do instead.
176
+ ⚠ The old sentence named an ENVIRONMENT VARIABLE to every reader —
177
+ "operator must wire FILEX_DRAWIO_URL" — which is a riddle to a person
178
+ who only wanted to look at a diagram. */
179
+ error.value = props.canConfigure
180
+ ? tt('viewer.drawio.disabled_admin', 'draw.io is not set up on this server. Set it up in the admin panel under External services.')
181
+ : tt('viewer.drawio.disabled', 'Diagrams cannot be opened here: this server has no draw.io. Download the file to open it elsewhere.');
182
+ disabledPane = true;
158
183
  status.value = 'error';
159
184
  return;
160
185
  }
161
- // Clear a previous "disabled" error in case the prop just became
162
- // available (capability probe finished after mount).
163
- if (error.value === tt('viewer.drawio.disabled', 'diagrams.net is not configured for this filex instance.')) {
186
+ // Clear a previous "disabled" pane in case the prop just became available
187
+ // (capability probe finished after mount).
188
+ if (disabledPane) {
189
+ disabledPane = false;
164
190
  error.value = null;
165
191
  status.value = 'loading';
166
192
  }
@@ -204,7 +230,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
204
230
  ref="iframeRef"
205
231
  :src="iframeSrc"
206
232
  class="filex-viewer-drawio__frame"
207
- title="diagrams.net editor"
233
+ title="draw.io"
208
234
  />
209
235
  </div>
210
236
  </template>
@@ -240,7 +266,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
240
266
  .filex-viewer-drawio__status[data-state="saved"] { color: #059669; }
241
267
  .filex-viewer-drawio__readonly {
242
268
  font-style: italic;
243
- margin-left: auto;
269
+ margin-inline-start: auto;
244
270
  }
245
271
  .filex-viewer-drawio__frame {
246
272
  flex: 1;
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { requestFailure } from '../lib/errorWords';
2
3
  /**
3
4
  * EpubViewer — flowable EPUB reader via `epubjs`.
4
5
  *
@@ -74,9 +75,7 @@ async function load(): Promise<void> {
74
75
  try {
75
76
  mod = await import(/* @vite-ignore */ 'epubjs');
76
77
  } catch {
77
- error.value = props.t
78
- ? props.t('viewer.peer_not_installed')
79
- : 'EPUB viewer requires `epubjs` — install or use download.';
78
+ error.value = tt('viewer.peer_not_installed', 'This kind of file cannot be shown here. Download it to open it on your device.');
80
79
  loading.value = false;
81
80
  return;
82
81
  }
@@ -92,7 +91,7 @@ async function load(): Promise<void> {
92
91
  headers,
93
92
  credentials: props.authCredentials || 'same-origin',
94
93
  });
95
- if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
94
+ if (!res.ok) throw requestFailure(res.status, await res.text().catch(() => ''), undefined);
96
95
  source = await res.arrayBuffer();
97
96
  }
98
97
  book = Epub(source);
@@ -242,7 +241,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
242
241
  .filex-viewer-epub__nav {
243
242
  position: absolute;
244
243
  bottom: 12px;
245
- left: 50%;
244
+ left: 50%; /* rtl-physical: centred by translate(-50%) — the same place in both directions */
246
245
  transform: translateX(-50%);
247
246
  display: flex;
248
247
  gap: 8px;
@@ -291,7 +290,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
291
290
  }
292
291
  .filex-viewer-epub__toc {
293
292
  width: 260px;
294
- border-right: 1px solid var(--fe-border, #e2e6ed);
293
+ border-inline-end: 1px solid var(--fe-border, #e2e6ed);
295
294
  overflow-y: auto;
296
295
  padding: 12px 0;
297
296
  background: var(--fe-bg-elev, #f7f8fa);
@@ -304,7 +303,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
304
303
  .filex-viewer-epub__toc-link {
305
304
  display: block;
306
305
  width: 100%;
307
- text-align: left;
306
+ text-align: start;
308
307
  background: transparent;
309
308
  border: 0;
310
309
  padding: 6px 14px;
@@ -316,7 +315,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
316
315
  background: var(--fe-bg-hover, #edf0f5);
317
316
  }
318
317
  .filex-viewer-epub__toc-link.is-child {
319
- padding-left: 28px;
318
+ padding-inline-start: 28px;
320
319
  color: var(--fe-text-muted, #5a6475);
321
320
  font-size: 12px;
322
321
  }
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { sayFailure } from '../lib/errorWords';
2
3
  /**
3
4
  * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.
4
5
  *
@@ -84,7 +85,7 @@ async function load(): Promise<void> {
84
85
  credentials: props.authCredentials,
85
86
  });
86
87
  } catch (err) {
87
- error.value = err instanceof Error ? err.message : 'fetch failed';
88
+ error.value = sayFailure(err, tt('viewer.failed_to_load', 'Failed to load file'), { t: props.t }).text;
88
89
  loading.value = false;
89
90
  return;
90
91
  }
@@ -263,6 +264,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
263
264
  <div
264
265
  v-if="renderedMarkdown.get(idx)"
265
266
  class="filex-viewer-ipynb__md"
267
+ dir="auto"
266
268
  v-html="renderedMarkdown.get(idx)"
267
269
  />
268
270
  <pre v-else class="filex-viewer-ipynb__md-raw">{{ joinSource(cell.source) }}</pre>
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { sayFailure } from '../lib/errorWords';
2
3
  /**
3
4
  * MermaidViewer — render a `.mmd` / `.mermaid` source file.
4
5
  *
@@ -60,9 +61,7 @@ async function load(): Promise<void> {
60
61
  const mermaid = await ensureMermaid();
61
62
  if (myToken !== renderToken) return;
62
63
  if (!mermaid) {
63
- error.value = props.t
64
- ? props.t('viewer.peer_not_installed')
65
- : 'Mermaid viewer requires `mermaid` — install or use download.';
64
+ error.value = tt('viewer.peer_not_installed', 'This kind of file cannot be shown here. Download it to open it on your device.');
66
65
  loading.value = false;
67
66
  return;
68
67
  }
@@ -75,7 +74,7 @@ async function load(): Promise<void> {
75
74
  credentials: props.authCredentials,
76
75
  });
77
76
  } catch (err) {
78
- error.value = err instanceof Error ? err.message : 'fetch failed';
77
+ error.value = sayFailure(err, tt('viewer.failed_to_load', 'Failed to load file'), { t: props.t }).text;
79
78
  loading.value = false;
80
79
  return;
81
80
  }
@@ -95,7 +94,7 @@ async function load(): Promise<void> {
95
94
  }
96
95
  }
97
96
  } catch (err) {
98
- error.value = err instanceof Error ? err.message : 'render failed';
97
+ error.value = sayFailure(err, tt('viewer.failed_to_load', 'Failed to load file'), { t: props.t }).text;
99
98
  } finally {
100
99
  loading.value = false;
101
100
  }
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { requestFailure, sayFailure } from '../lib/errorWords';
2
3
  /**
3
4
  * PdfViewer — rich PDF preview/edit via `pdfjs-dist`.
4
5
  *
@@ -23,6 +24,7 @@ import { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue'
23
24
  import { actionIconSvg } from '../lib/actionIcons'; /* ikon:emoji */
24
25
  import { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */
25
26
  import { fetchViewerArrayBuffer } from '../composables/useViewerFetch';
27
+ import { loadPdfjs } from '../lib/pdfjsLoader';
26
28
 
27
29
  const props = defineProps<{
28
30
  url: string;
@@ -60,21 +62,10 @@ let renderToken = 0;
60
62
 
61
63
  async function ensurePdfjs(): Promise<any | null> {
62
64
  if (pdfjs) return pdfjs;
63
- try {
64
- // Use the legacy build for broader browser compatibility and
65
- // simpler worker bootstrap (no module worker requirement).
66
- const mod = await import(/* @vite-ignore */ 'pdfjs-dist/legacy/build/pdf');
67
- pdfjs = mod.default ?? mod;
68
- if (pdfjs.GlobalWorkerOptions) {
69
- const version = pdfjs.version || '4.0.379';
70
- pdfjs.GlobalWorkerOptions.workerSrc =
71
- props.pdfWorkerUrl ||
72
- `https://cdn.jsdelivr.net/npm/pdfjs-dist@${version}/legacy/build/pdf.worker.min.js`;
73
- }
74
- return pdfjs;
75
- } catch {
76
- return null;
77
- }
65
+ // One loader for every pdf.js consumer in the package (lib/pdfjsLoader):
66
+ // the legacy build, the host's worker URL or the pinned CDN copy.
67
+ pdfjs = await loadPdfjs(props.pdfWorkerUrl);
68
+ return pdfjs;
78
69
  }
79
70
 
80
71
  // useNativeViewer flips the renderer to <embed type="application/pdf">
@@ -311,14 +302,14 @@ async function saveAnnotations(): Promise<void> {
311
302
  credentials: props.authCredentials || 'same-origin',
312
303
  body: JSON.stringify({ path: props.filePath, base64 }),
313
304
  });
314
- if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
305
+ if (!res.ok) throw requestFailure(res.status, await res.text().catch(() => ''), undefined);
315
306
  saveStatus.value = 'saved';
316
307
  setTimeout(() => {
317
308
  if (saveStatus.value === 'saved') saveStatus.value = 'idle';
318
309
  }, 2500);
319
310
  } catch (err) {
320
311
  saveStatus.value = 'error';
321
- error.value = err instanceof Error ? err.message : 'save failed';
312
+ error.value = sayFailure(err, tt('err.save_failed', 'Your changes could not be saved.'), { t: props.t }).text;
322
313
  }
323
314
  }
324
315
 
@@ -74,9 +74,7 @@ async function load(): Promise<void> {
74
74
  const lib = await ensureAgPsd();
75
75
  if (myToken !== renderToken) return;
76
76
  if (!lib) {
77
- error.value = props.t
78
- ? props.t('viewer.peer_not_installed')
79
- : 'PSD viewer requires `ag-psd` — install or use download.';
77
+ error.value = tt('viewer.peer_not_installed', 'This kind of file cannot be shown here. Download it to open it on your device.');
80
78
  loading.value = false;
81
79
  return;
82
80
  }
@@ -222,7 +220,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
222
220
  }
223
221
  .filex-viewer-psd__layers {
224
222
  width: 240px;
225
- border-right: 1px solid var(--fe-border, #e2e6ed);
223
+ border-inline-end: 1px solid var(--fe-border, #e2e6ed);
226
224
  overflow-y: auto;
227
225
  padding: 8px 0;
228
226
  background: var(--fe-bg-elev, #f7f8fa);
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { sayFailure } from '../lib/errorWords';
2
3
  /**
3
4
  * TiffViewer — multi-page TIFF preview via `utif`.
4
5
  *
@@ -56,9 +57,7 @@ async function load(): Promise<void> {
56
57
  const lib = await ensureUtif();
57
58
  if (myToken !== renderToken) return;
58
59
  if (!lib) {
59
- error.value = props.t
60
- ? props.t('viewer.peer_not_installed')
61
- : 'TIFF viewer requires `utif` — install or use download.';
60
+ error.value = tt('viewer.peer_not_installed', 'This kind of file cannot be shown here. Download it to open it on your device.');
62
61
  loading.value = false;
63
62
  return;
64
63
  }
@@ -77,7 +76,7 @@ async function load(): Promise<void> {
77
76
  }
78
77
  paint();
79
78
  } catch (err) {
80
- error.value = err instanceof Error ? err.message : 'TIFF decode failed';
79
+ error.value = sayFailure(err, tt('viewer.failed_to_load', 'Failed to load file'), { t: props.t }).text;
81
80
  } finally {
82
81
  loading.value = false;
83
82
  }
@@ -209,7 +208,7 @@ const typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ex
209
208
  .filex-viewer-tiff__pager {
210
209
  position: absolute;
211
210
  bottom: 12px;
212
- left: 50%;
211
+ left: 50%; /* rtl-physical: centred by translate(-50%) — the same place in both directions */
213
212
  transform: translateX(-50%);
214
213
  display: flex;
215
214
  align-items: center;
@@ -55,7 +55,7 @@ async function load(): Promise<void> {
55
55
  } catch {
56
56
  error.value = props.t
57
57
  ? props.t('viewer.peer_not_installed')
58
- : '3D viewer requires `@google/model-viewer` — install or use download.';
58
+ : 'This kind of file cannot be shown here. Download it to open it on your device.';
59
59
  }
60
60
  }
61
61
 
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 BRF Tech
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,124 +0,0 @@
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-Dx0IbBcI.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-CLNevfPE.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ArchiveViewer-CLNevfPE.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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"}
@@ -1,141 +0,0 @@
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-Dx0IbBcI.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-K8XA3z7N.js.map