@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
|
@@ -8,14 +8,26 @@
|
|
|
8
8
|
* square tiles: thumbnail (or SVG file-type icon fallback) with the name
|
|
9
9
|
* below and size+date revealed on hover/focus. GridView itself is untouched.
|
|
10
10
|
*/
|
|
11
|
-
import { ref } from 'vue';
|
|
11
|
+
import { computed, onBeforeUnmount, ref } from 'vue';
|
|
12
12
|
import { hasInternalDrag } from '../lib/dragOut';
|
|
13
13
|
import type { FileNode } from '../types/FileNode';
|
|
14
14
|
import type { LocaleCode } from '../types/ExplorerConfig';
|
|
15
15
|
import { useLocale } from '../composables/useLocale';
|
|
16
|
-
import {
|
|
16
|
+
import { encryptedFolderTile, fileIconTile, isEncryptedFolder } from '../lib/fileIcons';
|
|
17
|
+
import {
|
|
18
|
+
createFilePreviews,
|
|
19
|
+
drawsAsPage,
|
|
20
|
+
drawsAsVideo,
|
|
21
|
+
type FilePreview,
|
|
22
|
+
} from '../lib/filePreview'; /* gorunum:v1-preview */
|
|
17
23
|
import StarButton from './StarButton.vue';
|
|
18
24
|
import { applyDragGhost } from '../lib/dragGhost';
|
|
25
|
+
import { parentDirOf } from '../lib/listing'; /* the folder a row sits in — one split rule for every view */
|
|
26
|
+
import {
|
|
27
|
+
groupByDate,
|
|
28
|
+
groupingActive,
|
|
29
|
+
} from '../lib/dateGroups'; /* gruplama */
|
|
30
|
+
import { useSortStore, type ListingOrder } from '../lib/sortOrder'; /* gruplama */
|
|
19
31
|
|
|
20
32
|
const props = defineProps<{
|
|
21
33
|
files: FileNode[];
|
|
@@ -50,6 +62,17 @@ const props = defineProps<{
|
|
|
50
62
|
apiBase?: string;
|
|
51
63
|
authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
52
64
|
authCredentials?: RequestCredentials;
|
|
65
|
+
/** gorunum:v1-preview — inside an E2E-encrypted folder every body is
|
|
66
|
+
* ciphertext, so the text preview stays off. Same prop, same meaning and
|
|
67
|
+
* same default as GridView's. */
|
|
68
|
+
e2eActive?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* gruplama — where these rows got their order, the same prop the list and
|
|
71
|
+
* the grid take (`lib/sortOrder.ListingOrder`). Read for one thing only: a
|
|
72
|
+
* date heading over the server's RANKED answer would be a claim about an
|
|
73
|
+
* order the tiles are not in. Omitted = an ordinary folder listing.
|
|
74
|
+
*/
|
|
75
|
+
order?: ListingOrder;
|
|
53
76
|
}>();
|
|
54
77
|
|
|
55
78
|
const emit = defineEmits<{
|
|
@@ -61,12 +84,68 @@ const emit = defineEmits<{
|
|
|
61
84
|
(e: 'star-change', node: FileNode, value: boolean): void;
|
|
62
85
|
}>();
|
|
63
86
|
|
|
64
|
-
const { t, formatSize, nodeDisplayName
|
|
87
|
+
const { t, formatSize, nodeDisplayName, formatDate, formatMonthYear, zonedYearMonth, toDate } =
|
|
88
|
+
useLocale(() => props.locale);
|
|
89
|
+
|
|
90
|
+
/* gruplama — this pane's sort, by injection, so the gallery cannot disagree
|
|
91
|
+
* with the list beside it about whether a date heading is honest right now. */
|
|
92
|
+
const sort = useSortStore();
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* gruplama — THE DATE HEADINGS, from the one module that owns the ladder
|
|
96
|
+
* (`lib/dateGroups`), read identically by ListView and GridView.
|
|
97
|
+
*
|
|
98
|
+
* ⚠ The gallery has no Folders / Files sections to collide with, so nothing
|
|
99
|
+
* here replaces anything: folders keep a run of their own at the top — with no
|
|
100
|
+
* heading, because the gallery has never named one — and each day of files
|
|
101
|
+
* gets its label. Any sort key but `modified` draws nothing at all, exactly as
|
|
102
|
+
* before this existed.
|
|
103
|
+
*
|
|
104
|
+
* ⚠ The tiles are handed to us ALREADY sorted (`FilePane.displayFiles` runs
|
|
105
|
+
* the pane's comparator, folders first, then the key), which is why this
|
|
106
|
+
* groups `props.files` in place rather than re-sorting: a second sort here is
|
|
107
|
+
* a second opinion about the order, and the grid learned that lesson once.
|
|
108
|
+
*/
|
|
109
|
+
const grouped = computed(() =>
|
|
110
|
+
groupByDate(props.files, {
|
|
111
|
+
active: groupingActive(sort.key.value, props.order),
|
|
112
|
+
dateOf: (n) => toDate(n.last_modified),
|
|
113
|
+
aside: (n) => (n.type === 'dir' ? { id: 'dirs' } : null),
|
|
114
|
+
labels: { t, formatMonthYear, zonedYearMonth },
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
65
117
|
|
|
66
118
|
function thumbOf(n: FileNode): string | null {
|
|
67
119
|
return props.thumbSrc ? props.thumbSrc(n) : (n.thumb_url ?? null);
|
|
68
120
|
}
|
|
69
121
|
|
|
122
|
+
/* gorunum:v1-preview — the SAME preview the grid card draws, from the same
|
|
123
|
+
* module and with the same bounds. Not a gallery variant: a text file in a
|
|
124
|
+
* gallery is the identical hole (the backend's generic extension-card), and
|
|
125
|
+
* "open it on the desktop, leave the embeds on the old behaviour" is how one
|
|
126
|
+
* product becomes two. Only the type scale differs, and that is CSS. */
|
|
127
|
+
const previews = createFilePreviews({
|
|
128
|
+
apiBase: props.apiBase,
|
|
129
|
+
authHeaders: props.authHeaders ? () => props.authHeaders!() : undefined,
|
|
130
|
+
credentials: props.authCredentials,
|
|
131
|
+
disabled: () => props.e2eActive === true,
|
|
132
|
+
});
|
|
133
|
+
onBeforeUnmount(() => previews.dispose());
|
|
134
|
+
|
|
135
|
+
function previewKind(n: FileNode) {
|
|
136
|
+
return previews.kindFor(n);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** At most one element — a typed local for the template, no `!` per loop. */
|
|
140
|
+
function previewFor(n: FileNode): FilePreview[] {
|
|
141
|
+
const p = previews.get(n);
|
|
142
|
+
return p ? [p] : [];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function bindPreview(el: unknown, n: FileNode) {
|
|
146
|
+
previews.bind(el instanceof Element ? el : null, n);
|
|
147
|
+
}
|
|
148
|
+
|
|
70
149
|
/** A card carries a star when the host wired the API and the node is a file
|
|
71
150
|
* with a server id — the same rule the list row uses. */
|
|
72
151
|
function canStar(n: FileNode): boolean {
|
|
@@ -148,25 +227,15 @@ function cancelPress() {
|
|
|
148
227
|
pressTarget = null;
|
|
149
228
|
}
|
|
150
229
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// Special rows keep their emoji (trash/storage are not file-TYPE icons).
|
|
159
|
-
function specialEmojiFor(n: FileNode): string | null {
|
|
160
|
-
if (n.basename === '.trash') return '🗑';
|
|
161
|
-
if (n.mime_type === 'inode/storage') return '💾';
|
|
162
|
-
if (n.type === 'dir' && n.e2e === true) return '🔒'; /* wiring:e2 — encrypted-folder badge */
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
|
|
230
|
+
/**
|
|
231
|
+
* zaman:z1 — routed through useLocale.formatDate, the package's one date
|
|
232
|
+
* formatter. It was a bare `toLocaleString()`, i.e. the BROWSER's locale and
|
|
233
|
+
* the BROWSER's zone: the same file's timestamp came out in a different
|
|
234
|
+
* language here than in the list two clicks away, and in a different clock
|
|
235
|
+
* than the viewer had chosen. Neither of those is a gallery decision.
|
|
236
|
+
*/
|
|
166
237
|
function displayDate(ms: number | undefined): string {
|
|
167
|
-
|
|
168
|
-
const d = new Date(ms * (ms < 1e12 ? 1000 : 1));
|
|
169
|
-
return d.toLocaleString();
|
|
238
|
+
return formatDate(ms, { time: true });
|
|
170
239
|
}
|
|
171
240
|
|
|
172
241
|
// Hover meta line: size for files, entry count (when known) for dirs.
|
|
@@ -186,9 +255,13 @@ function metaFor(n: FileNode): string {
|
|
|
186
255
|
:aria-label="t('gallery.aria')"
|
|
187
256
|
:aria-busy="loading ? 'true' : undefined"
|
|
188
257
|
>
|
|
258
|
+
<template v-for="n in files" :key="n.path">
|
|
259
|
+
<!-- gruplama — the date label: a grid item spanning every column, so the
|
|
260
|
+
tiles keep flowing under it. The cards keep `role="option"`; the
|
|
261
|
+
heading is aria-hidden and the day it names is already in each
|
|
262
|
+
card's own hover text. -->
|
|
263
|
+
<p v-if="grouped.headingBefore(n)" class="fe-gal__heading" aria-hidden="true">{{ grouped.headingBefore(n) }}</p>
|
|
189
264
|
<div
|
|
190
|
-
v-for="n in files"
|
|
191
|
-
:key="n.path"
|
|
192
265
|
class="fe-gal__card"
|
|
193
266
|
:class="{
|
|
194
267
|
'is-selected': isSelected(n),
|
|
@@ -214,23 +287,81 @@ function metaFor(n: FileNode): string {
|
|
|
214
287
|
@touchend="cancelPress"
|
|
215
288
|
@touchmove="cancelPress"
|
|
216
289
|
>
|
|
217
|
-
<div class="fe-gal__thumb">
|
|
290
|
+
<div class="fe-gal__thumb" :ref="(el) => bindPreview(el, n)">
|
|
291
|
+
<!-- gorunum:v1-preview — a text-readable file shows its own first
|
|
292
|
+
lines; it never reaches the <img> branch, so no generic
|
|
293
|
+
placeholder thumbnail is fetched for it either. -->
|
|
294
|
+
<template v-if="previewKind(n)">
|
|
295
|
+
<!-- ⚠ Interpolated, never v-html: this is somebody's file content. -->
|
|
296
|
+
<div
|
|
297
|
+
v-for="p in previewFor(n)"
|
|
298
|
+
:key="'fprev'"
|
|
299
|
+
class="fe-fprev"
|
|
300
|
+
:class="'fe-fprev--' + p.kind"
|
|
301
|
+
:style="p.kind === 'table' ? { '--fprev-cols': String(p.cols) } : undefined"
|
|
302
|
+
aria-hidden="true"
|
|
303
|
+
>
|
|
304
|
+
<!-- One grid, cells emitted flat: <template> makes no DOM, so a
|
|
305
|
+
short row's padding cells keep every column aligned. -->
|
|
306
|
+
<template v-if="p.kind === 'table'">
|
|
307
|
+
<template v-for="(row, ri) in p.rows" :key="ri">
|
|
308
|
+
<span
|
|
309
|
+
v-for="(cell, ci) in row"
|
|
310
|
+
:key="ci"
|
|
311
|
+
class="fe-fprev__cell"
|
|
312
|
+
:class="{ 'is-head': ri === 0 }"
|
|
313
|
+
>{{ cell }}</span>
|
|
314
|
+
</template>
|
|
315
|
+
</template>
|
|
316
|
+
<template v-else>
|
|
317
|
+
<div v-for="(ln, li) in p.lines" :key="li" class="fe-fprev__line"><span
|
|
318
|
+
v-if="ln.tint"
|
|
319
|
+
class="fe-fprev__tint"
|
|
320
|
+
>{{ ln.indent }}{{ ln.tint }}</span>{{ ln.text }}</div>
|
|
321
|
+
</template>
|
|
322
|
+
</div>
|
|
323
|
+
<!-- eslint-disable-next-line vue/no-v-html — static markup from lib/fileIcons -->
|
|
324
|
+
<span
|
|
325
|
+
v-if="previewFor(n).length === 0"
|
|
326
|
+
class="fe-gal__icon fe-gal__icon--svg"
|
|
327
|
+
v-html="fileIconTile(n)"
|
|
328
|
+
></span>
|
|
329
|
+
</template>
|
|
218
330
|
<!-- draggable="false" for the same reason as GridView: HTML5 image
|
|
219
331
|
drag adds a 'Files' MIME to dataTransfer, which would trip the
|
|
220
332
|
parent's upload handler on internal drags. -->
|
|
221
333
|
<img
|
|
222
|
-
v-if="thumbOf(n)"
|
|
334
|
+
v-else-if="thumbOf(n)"
|
|
223
335
|
:src="thumbOf(n)!"
|
|
224
336
|
:alt="n.basename"
|
|
337
|
+
:class="{ 'fe-thumb--page': drawsAsPage(n) /* gorunum:v1-preview — crop a page from its TOP */ }"
|
|
225
338
|
loading="lazy"
|
|
226
339
|
draggable="false"
|
|
227
340
|
/>
|
|
228
|
-
|
|
341
|
+
<!-- ikon:emoji — see GridView: the folder shape survives, the padlock
|
|
342
|
+
is cut out of it, and the name the 🔒 never had is on the span. -->
|
|
343
|
+
<!-- eslint-disable-next-line vue/no-v-html — static markup from lib/fileIcons -->
|
|
344
|
+
<span
|
|
345
|
+
v-else-if="isEncryptedFolder(n)"
|
|
346
|
+
class="fe-gal__icon fe-gal__icon--svg"
|
|
347
|
+
role="img"
|
|
348
|
+
:aria-label="t('e2e.badge')"
|
|
349
|
+
v-html="encryptedFolderTile()"
|
|
350
|
+
></span>
|
|
229
351
|
<!-- eslint-disable-next-line vue/no-v-html — static markup from lib/fileIcons -->
|
|
230
|
-
<span v-else class="fe-gal__icon fe-gal__icon--svg" v-html="
|
|
352
|
+
<span v-else class="fe-gal__icon fe-gal__icon--svg" v-html="fileIconTile(n)"></span>
|
|
231
353
|
<!-- Same star chip as the grid, same component, same rule: painted
|
|
232
354
|
when starred, on hover/focus otherwise. It sits above .fe-gal__meta
|
|
233
355
|
(which is aria-hidden and covers the tile's foot on hover). -->
|
|
356
|
+
<!-- gorunum:v1-preview — a frame lifted out of a video is, on a card,
|
|
357
|
+
indistinguishable from a photograph. The badge is the difference,
|
|
358
|
+
and it is drawn only over a real frame: a video that fell back to
|
|
359
|
+
its type tile already says what it is. -->
|
|
360
|
+
<span
|
|
361
|
+
v-if="!previewKind(n) && thumbOf(n) && drawsAsVideo(n)"
|
|
362
|
+
class="fe-thumb__play"
|
|
363
|
+
aria-hidden="true"
|
|
364
|
+
></span>
|
|
234
365
|
<div v-if="canStar(n)" class="fe-gal__star" @click.stop @dblclick.stop>
|
|
235
366
|
<StarButton
|
|
236
367
|
:starred="!!starredIds?.has(n.id!)"
|
|
@@ -247,16 +378,17 @@ function metaFor(n: FileNode): string {
|
|
|
247
378
|
<div class="fe-gal__meta" aria-hidden="true">
|
|
248
379
|
<span v-if="metaFor(n)" class="fe-gal__meta-line">{{ metaFor(n) }}</span>
|
|
249
380
|
<span
|
|
250
|
-
v-if="showParentPath &&
|
|
381
|
+
v-if="showParentPath && parentDirOf(n.path)"
|
|
251
382
|
class="fe-gal__meta-line fe-gal__meta-line--path"
|
|
252
|
-
:title="
|
|
253
|
-
>{{
|
|
383
|
+
:title="parentDirOf(n.path)"
|
|
384
|
+
>{{ parentDirOf(n.path) }}</span>
|
|
254
385
|
</div>
|
|
255
386
|
</div>
|
|
256
387
|
<div class="fe-gal__label" :title="n.basename">
|
|
257
388
|
{{ nodeDisplayName(n) }}
|
|
258
389
|
</div>
|
|
259
390
|
</div>
|
|
391
|
+
</template>
|
|
260
392
|
<div v-if="!loading && files.length === 0" class="fe-gal__empty">
|
|
261
393
|
{{ t('empty.folder') }}
|
|
262
394
|
</div>
|