vitepress-plugin-filelist 0.2.2 → 0.3.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 +26 -6
- package/dist/client/browser/index.d.ts +37 -0
- package/dist/client/browser/index.js +540 -131
- package/dist/client/ssr/index.d.ts +37 -0
- package/dist/client/ssr/index.js +264 -35
- package/dist/client/style.css +580 -95
- package/package.json +3 -1
|
@@ -6,6 +6,7 @@ interface FileListLabels {
|
|
|
6
6
|
filter: string;
|
|
7
7
|
refresh: string;
|
|
8
8
|
batch: string;
|
|
9
|
+
/** @deprecated No longer shown; the selection count lives in the toolbar. */
|
|
9
10
|
batchCount: string;
|
|
10
11
|
batching: string;
|
|
11
12
|
passwordPrompt: string;
|
|
@@ -33,6 +34,23 @@ interface FileListLabels {
|
|
|
33
34
|
previewFailed: string;
|
|
34
35
|
batchFailed: string;
|
|
35
36
|
defaultZip: string;
|
|
37
|
+
/** Text button that clears the selection (wide layout). */
|
|
38
|
+
clear: string;
|
|
39
|
+
/** Accessible name of the clear-selection button. */
|
|
40
|
+
clearSelection: string;
|
|
41
|
+
/** `{size}` total, used for the selection and the footer. */
|
|
42
|
+
totalSize: string;
|
|
43
|
+
/** `{count}` files inside a loaded folder. */
|
|
44
|
+
folderItems: string;
|
|
45
|
+
/** Label of the compact sort select shown in narrow containers. */
|
|
46
|
+
sortBy: string;
|
|
47
|
+
selectAll: string;
|
|
48
|
+
/** Accessible name of a row checkbox, `{name}`. */
|
|
49
|
+
selectItem: string;
|
|
50
|
+
/** Accessible name of the expand button, `{name}`. */
|
|
51
|
+
expand: string;
|
|
52
|
+
/** Accessible name of the collapse button, `{name}`. */
|
|
53
|
+
collapse: string;
|
|
36
54
|
}
|
|
37
55
|
interface FileListSource {
|
|
38
56
|
/** OpenList path, directory or single file. */
|
|
@@ -171,9 +189,28 @@ export interface SortableNode {
|
|
|
171
189
|
export type SortKey = 'name' | 'size' | 'modified';
|
|
172
190
|
export declare function joinPath(parent: string, name: string): string;
|
|
173
191
|
export declare function encodePath(path: string): string;
|
|
192
|
+
/**
|
|
193
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
194
|
+
* no `.` / `..` traversal, no empty names.
|
|
195
|
+
*/
|
|
196
|
+
export declare function zipSegment(name: string): string;
|
|
197
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
198
|
+
export declare function zipEntryName(segments: string[]): string;
|
|
199
|
+
/**
|
|
200
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
201
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
202
|
+
*/
|
|
203
|
+
export declare function uniqueEntryName(name: string, used: Set<string>): string;
|
|
174
204
|
export declare function formatSize(size: number): string;
|
|
175
205
|
export declare function formatDate(iso: string): string;
|
|
176
206
|
export declare function extOf(name: string): string;
|
|
207
|
+
export type FileKind = 'doc' | 'sheet' | 'slide' | 'pdf' | 'image' | 'media' | 'archive' | 'code' | 'other';
|
|
208
|
+
/** Rough file family, used to colour the type badge. */
|
|
209
|
+
export declare function fileKind(name: string): FileKind;
|
|
210
|
+
/** Sum of the `size` of the given entries, ignoring missing or invalid sizes. */
|
|
211
|
+
export declare function totalSize(items: Array<{
|
|
212
|
+
size?: number;
|
|
213
|
+
}>): number;
|
|
177
214
|
export declare function compareNodes(a: SortableNode, b: SortableNode, key: SortKey, ascending?: boolean): number;
|
|
178
215
|
/**
|
|
179
216
|
* Register `<FileList>` and `<VPFileList>` globally.
|
package/dist/client/ssr/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { computed, defineComponent, mergeProps, onMounted, ref, unref, useSSRContext } from "vue";
|
|
2
|
-
import { ssrIncludeBooleanAttr, ssrInterpolate, ssrRenderAttr, ssrRenderAttrs, ssrRenderClass, ssrRenderList, ssrRenderStyle } from "vue/server-renderer";
|
|
1
|
+
import { computed, defineComponent, mergeProps, onBeforeUnmount, onMounted, ref, unref, useSSRContext } from "vue";
|
|
2
|
+
import { ssrIncludeBooleanAttr, ssrInterpolate, ssrLooseContain, ssrLooseEqual, ssrRenderAttr, ssrRenderAttrs, ssrRenderClass, ssrRenderList, ssrRenderStyle } from "vue/server-renderer";
|
|
3
3
|
// src/client/locales.ts
|
|
4
4
|
const fileListLocales = {
|
|
5
5
|
"zh-CN": {
|
|
@@ -7,7 +7,7 @@ const fileListLocales = {
|
|
|
7
7
|
demoBadge: "演示数据",
|
|
8
8
|
filter: "筛选文件名",
|
|
9
9
|
refresh: "刷新",
|
|
10
|
-
batch: "
|
|
10
|
+
batch: "下载 ZIP",
|
|
11
11
|
batchCount: "批量下载({count})",
|
|
12
12
|
batching: "打包中 {percent}%",
|
|
13
13
|
passwordPrompt: "该目录受密码保护:",
|
|
@@ -34,7 +34,16 @@ const fileListLocales = {
|
|
|
34
34
|
downloadFailed: "下载失败:{message}",
|
|
35
35
|
previewFailed: "预览失败:{message}",
|
|
36
36
|
batchFailed: "打包失败:{message}",
|
|
37
|
-
defaultZip: "资源"
|
|
37
|
+
defaultZip: "资源",
|
|
38
|
+
clear: "清除",
|
|
39
|
+
clearSelection: "取消选择",
|
|
40
|
+
totalSize: "共 {size}",
|
|
41
|
+
folderItems: "{count} 项",
|
|
42
|
+
sortBy: "排序",
|
|
43
|
+
selectAll: "全选",
|
|
44
|
+
selectItem: "选择 {name}",
|
|
45
|
+
expand: "展开 {name}",
|
|
46
|
+
collapse: "收起 {name}"
|
|
38
47
|
},
|
|
39
48
|
"en-US": {
|
|
40
49
|
allFiles: "All files",
|
|
@@ -68,7 +77,16 @@ const fileListLocales = {
|
|
|
68
77
|
downloadFailed: "Download failed: {message}",
|
|
69
78
|
previewFailed: "Preview failed: {message}",
|
|
70
79
|
batchFailed: "Failed to create ZIP: {message}",
|
|
71
|
-
defaultZip: "resources"
|
|
80
|
+
defaultZip: "resources",
|
|
81
|
+
clear: "Clear",
|
|
82
|
+
clearSelection: "Clear selection",
|
|
83
|
+
totalSize: "{size} total",
|
|
84
|
+
folderItems: "{count} items",
|
|
85
|
+
sortBy: "Sort",
|
|
86
|
+
selectAll: "Select all",
|
|
87
|
+
selectItem: "Select {name}",
|
|
88
|
+
expand: "Expand {name}",
|
|
89
|
+
collapse: "Collapse {name}"
|
|
72
90
|
}
|
|
73
91
|
};
|
|
74
92
|
function formatLabel(template, values = {}) {
|
|
@@ -87,6 +105,41 @@ function joinPath(parent, name) {
|
|
|
87
105
|
function encodePath(path) {
|
|
88
106
|
return path.split("/").map(encodeURIComponent).join("/");
|
|
89
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
110
|
+
* no `.` / `..` traversal, no empty names.
|
|
111
|
+
*/
|
|
112
|
+
function zipSegment(name) {
|
|
113
|
+
const cleaned = name.replace(/[\\/]/g, "_").trim();
|
|
114
|
+
if (!cleaned || cleaned === "." || cleaned === "..") return "_";
|
|
115
|
+
return cleaned;
|
|
116
|
+
}
|
|
117
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
118
|
+
function zipEntryName(segments) {
|
|
119
|
+
return segments.map(zipSegment).join("/");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
123
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
124
|
+
*/
|
|
125
|
+
function uniqueEntryName(name, used) {
|
|
126
|
+
let candidate = name;
|
|
127
|
+
if (used.has(candidate)) {
|
|
128
|
+
const slash = name.lastIndexOf("/");
|
|
129
|
+
const dir = name.slice(0, slash + 1);
|
|
130
|
+
const base = name.slice(slash + 1);
|
|
131
|
+
const dot = base.lastIndexOf(".");
|
|
132
|
+
const stem = dot > 0 ? base.slice(0, dot) : base;
|
|
133
|
+
const ext = dot > 0 ? base.slice(dot) : "";
|
|
134
|
+
let index = 2;
|
|
135
|
+
do {
|
|
136
|
+
candidate = `${dir}${stem} (${index})${ext}`;
|
|
137
|
+
index += 1;
|
|
138
|
+
} while (used.has(candidate));
|
|
139
|
+
}
|
|
140
|
+
used.add(candidate);
|
|
141
|
+
return candidate;
|
|
142
|
+
}
|
|
90
143
|
function formatSize(size) {
|
|
91
144
|
if (!size || !Number.isFinite(size)) return "-";
|
|
92
145
|
const units = [
|
|
@@ -116,6 +169,97 @@ function extOf(name) {
|
|
|
116
169
|
const match = name.match(/\.([a-z0-9]+)$/i);
|
|
117
170
|
return match ? match[1].toUpperCase() : "";
|
|
118
171
|
}
|
|
172
|
+
const FILE_KINDS = {};
|
|
173
|
+
for (const [kind, exts] of Object.entries({
|
|
174
|
+
doc: [
|
|
175
|
+
"doc",
|
|
176
|
+
"docx",
|
|
177
|
+
"odt",
|
|
178
|
+
"rtf",
|
|
179
|
+
"txt",
|
|
180
|
+
"md",
|
|
181
|
+
"pages",
|
|
182
|
+
"wps"
|
|
183
|
+
],
|
|
184
|
+
sheet: [
|
|
185
|
+
"xls",
|
|
186
|
+
"xlsx",
|
|
187
|
+
"ods",
|
|
188
|
+
"csv",
|
|
189
|
+
"tsv",
|
|
190
|
+
"numbers",
|
|
191
|
+
"et"
|
|
192
|
+
],
|
|
193
|
+
slide: [
|
|
194
|
+
"ppt",
|
|
195
|
+
"pptx",
|
|
196
|
+
"odp",
|
|
197
|
+
"key",
|
|
198
|
+
"dps"
|
|
199
|
+
],
|
|
200
|
+
pdf: ["pdf"],
|
|
201
|
+
image: [
|
|
202
|
+
"png",
|
|
203
|
+
"jpg",
|
|
204
|
+
"jpeg",
|
|
205
|
+
"gif",
|
|
206
|
+
"webp",
|
|
207
|
+
"svg",
|
|
208
|
+
"bmp",
|
|
209
|
+
"ico",
|
|
210
|
+
"avif",
|
|
211
|
+
"heic"
|
|
212
|
+
],
|
|
213
|
+
media: [
|
|
214
|
+
"mp3",
|
|
215
|
+
"wav",
|
|
216
|
+
"flac",
|
|
217
|
+
"aac",
|
|
218
|
+
"ogg",
|
|
219
|
+
"m4a",
|
|
220
|
+
"mp4",
|
|
221
|
+
"webm",
|
|
222
|
+
"mov",
|
|
223
|
+
"mkv",
|
|
224
|
+
"avi"
|
|
225
|
+
],
|
|
226
|
+
archive: [
|
|
227
|
+
"zip",
|
|
228
|
+
"rar",
|
|
229
|
+
"7z",
|
|
230
|
+
"tar",
|
|
231
|
+
"gz",
|
|
232
|
+
"tgz",
|
|
233
|
+
"bz2",
|
|
234
|
+
"xz",
|
|
235
|
+
"iso"
|
|
236
|
+
],
|
|
237
|
+
code: [
|
|
238
|
+
"js",
|
|
239
|
+
"ts",
|
|
240
|
+
"json",
|
|
241
|
+
"html",
|
|
242
|
+
"css",
|
|
243
|
+
"py",
|
|
244
|
+
"java",
|
|
245
|
+
"c",
|
|
246
|
+
"cpp",
|
|
247
|
+
"go",
|
|
248
|
+
"rs",
|
|
249
|
+
"sh",
|
|
250
|
+
"yml",
|
|
251
|
+
"yaml",
|
|
252
|
+
"xml"
|
|
253
|
+
]
|
|
254
|
+
})) for (const ext of exts) FILE_KINDS[ext] = kind;
|
|
255
|
+
/** Rough file family, used to colour the type badge. */
|
|
256
|
+
function fileKind(name) {
|
|
257
|
+
return FILE_KINDS[extOf(name).toLowerCase()] ?? "other";
|
|
258
|
+
}
|
|
259
|
+
/** Sum of the `size` of the given entries, ignoring missing or invalid sizes. */
|
|
260
|
+
function totalSize(items) {
|
|
261
|
+
return items.reduce((sum, item) => sum + (Number.isFinite(item.size) && (item.size ?? 0) > 0 ? item.size : 0), 0);
|
|
262
|
+
}
|
|
119
263
|
function compareNodes(a, b, key, ascending = true) {
|
|
120
264
|
if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1;
|
|
121
265
|
let result = 0;
|
|
@@ -181,6 +325,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
181
325
|
function errorText(error) {
|
|
182
326
|
return error instanceof Error ? error.message : String(error);
|
|
183
327
|
}
|
|
328
|
+
function isPasswordError(error) {
|
|
329
|
+
return /password|密码/i.test(errorText(error));
|
|
330
|
+
}
|
|
184
331
|
const DEMO_TREE = {
|
|
185
332
|
"/": [
|
|
186
333
|
{
|
|
@@ -364,7 +511,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
364
511
|
nodes.sort((a, b) => compareNodes(a, b, sortKey.value, sortAsc.value));
|
|
365
512
|
for (const node of nodes) if (node.children.length) sortTree(node.children);
|
|
366
513
|
}
|
|
367
|
-
function toNodes(items, parent, depth, password = "") {
|
|
514
|
+
function toNodes(items, parent, depth, password = "", zipParent = []) {
|
|
368
515
|
return items.map((item) => ({
|
|
369
516
|
...item,
|
|
370
517
|
path: joinPath(parent, item.name),
|
|
@@ -373,9 +520,15 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
373
520
|
loaded: false,
|
|
374
521
|
loading: false,
|
|
375
522
|
children: [],
|
|
376
|
-
password
|
|
523
|
+
password,
|
|
524
|
+
zipPath: [...zipParent, item.name]
|
|
377
525
|
}));
|
|
378
526
|
}
|
|
527
|
+
function resortAll() {
|
|
528
|
+
if (props.sources.length) {
|
|
529
|
+
for (const root of roots.value) if (root.children.length) sortTree(root.children);
|
|
530
|
+
} else sortTree(roots.value);
|
|
531
|
+
}
|
|
379
532
|
function sourceName(path) {
|
|
380
533
|
const parts = path.split("/").filter(Boolean);
|
|
381
534
|
return parts[parts.length - 1] || path;
|
|
@@ -384,11 +537,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
384
537
|
if (node.loaded) return true;
|
|
385
538
|
node.loading = true;
|
|
386
539
|
try {
|
|
387
|
-
node.children = toNodes(await listDir(node.path, node.password), node.path, node.depth + 1, node.password);
|
|
540
|
+
node.children = toNodes(await listDir(node.path, node.password || activePassword.value), node.path, node.depth + 1, node.password, node.zipPath);
|
|
388
541
|
sortTree(node.children);
|
|
389
542
|
node.loaded = true;
|
|
390
543
|
return true;
|
|
391
544
|
} catch (error) {
|
|
545
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
392
546
|
showToast(t("folderFailed", { message: errorText(error) }));
|
|
393
547
|
return false;
|
|
394
548
|
} finally {
|
|
@@ -413,16 +567,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
413
567
|
} else try {
|
|
414
568
|
const data = await request("/api/fs/get", {
|
|
415
569
|
path,
|
|
416
|
-
password
|
|
570
|
+
password: password || activePassword.value
|
|
417
571
|
});
|
|
418
572
|
item = {
|
|
419
573
|
...item,
|
|
420
574
|
...data
|
|
421
575
|
};
|
|
422
576
|
} catch {}
|
|
577
|
+
const name = source.title || item.name || sourceName(path);
|
|
423
578
|
return {
|
|
424
579
|
...item,
|
|
425
|
-
name
|
|
580
|
+
name,
|
|
426
581
|
path,
|
|
427
582
|
depth: 0,
|
|
428
583
|
expanded: source.expanded ?? props.expanded,
|
|
@@ -430,7 +585,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
430
585
|
loading: false,
|
|
431
586
|
children: [],
|
|
432
587
|
password,
|
|
433
|
-
isRoot: true
|
|
588
|
+
isRoot: true,
|
|
589
|
+
zipPath: [item.is_dir ? name : item.name || sourceName(path)]
|
|
434
590
|
};
|
|
435
591
|
}
|
|
436
592
|
async function loadRoot() {
|
|
@@ -453,7 +609,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
453
609
|
downloadCache.clear();
|
|
454
610
|
} catch (error) {
|
|
455
611
|
const message = errorText(error);
|
|
456
|
-
if (
|
|
612
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
457
613
|
else errorMsg.value = message;
|
|
458
614
|
} finally {
|
|
459
615
|
loadingRoot.value = false;
|
|
@@ -489,6 +645,36 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
489
645
|
const allFiles = computed(() => roots.value.flatMap(descendantFiles));
|
|
490
646
|
const allChecked = computed(() => allFiles.value.length > 0 && allFiles.value.every((file) => selected.value.has(file.path)));
|
|
491
647
|
const someChecked = computed(() => !allChecked.value && allFiles.value.some((file) => selected.value.has(file.path)));
|
|
648
|
+
const selectedFiles = computed(() => allFiles.value.filter((file) => selected.value.has(file.path)));
|
|
649
|
+
const selectedBytes = computed(() => totalSize(selectedFiles.value));
|
|
650
|
+
const loadedBytes = computed(() => totalSize(allFiles.value));
|
|
651
|
+
function folderFiles(node) {
|
|
652
|
+
return node.is_dir && node.loaded ? descendantFiles(node) : [];
|
|
653
|
+
}
|
|
654
|
+
/** Compact sort control for narrow containers, where header cells are hidden. */
|
|
655
|
+
const sortOptions = computed(() => [
|
|
656
|
+
"name",
|
|
657
|
+
"size",
|
|
658
|
+
"modified"
|
|
659
|
+
].flatMap((key) => {
|
|
660
|
+
const label = t(key === "name" ? "columnName" : key === "size" ? "columnSize" : "columnDate");
|
|
661
|
+
return [{
|
|
662
|
+
value: `${key}:asc`,
|
|
663
|
+
label: `${label} ↑`
|
|
664
|
+
}, {
|
|
665
|
+
value: `${key}:desc`,
|
|
666
|
+
label: `${label} ↓`
|
|
667
|
+
}];
|
|
668
|
+
}));
|
|
669
|
+
const sortValue = computed({
|
|
670
|
+
get: () => `${sortKey.value}:${sortAsc.value ? "asc" : "desc"}`,
|
|
671
|
+
set: (value) => {
|
|
672
|
+
const [key, direction] = value.split(":");
|
|
673
|
+
sortKey.value = key;
|
|
674
|
+
sortAsc.value = direction !== "desc";
|
|
675
|
+
resortAll();
|
|
676
|
+
}
|
|
677
|
+
});
|
|
492
678
|
const unloadedFolders = computed(() => {
|
|
493
679
|
let count = 0;
|
|
494
680
|
const walk = (nodes) => {
|
|
@@ -505,18 +691,52 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
505
691
|
return !node.is_dir && previewable.test(node.name);
|
|
506
692
|
}
|
|
507
693
|
const displayTitle = computed(() => props.title || siteTitle.value || (props.path === "/" ? t("allFiles") : props.path));
|
|
694
|
+
const stickyTop = ref(0);
|
|
695
|
+
function measureStickyTop() {
|
|
696
|
+
if (typeof document === "undefined") return;
|
|
697
|
+
let top = 0;
|
|
698
|
+
for (const el of document.querySelectorAll(".VPNav, .VPLocalNav")) {
|
|
699
|
+
const style = getComputedStyle(el);
|
|
700
|
+
if (style.display === "none" || style.position !== "fixed" && style.position !== "sticky") continue;
|
|
701
|
+
top = Math.max(top, (Number.parseFloat(style.top) || 0) + el.offsetHeight);
|
|
702
|
+
}
|
|
703
|
+
stickyTop.value = top;
|
|
704
|
+
}
|
|
508
705
|
onMounted(() => {
|
|
509
706
|
loadRoot();
|
|
510
707
|
loadSiteTitle();
|
|
708
|
+
measureStickyTop();
|
|
709
|
+
window.addEventListener("resize", measureStickyTop, { passive: true });
|
|
710
|
+
});
|
|
711
|
+
onBeforeUnmount(() => {
|
|
712
|
+
window.removeEventListener("resize", measureStickyTop);
|
|
713
|
+
clearTimeout(toastTimer);
|
|
511
714
|
});
|
|
512
715
|
return (_ctx, _push, _parent, _attrs) => {
|
|
513
|
-
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
514
|
-
|
|
716
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
717
|
+
class: ["fl-root", { "fl-selecting": selected.value.size > 0 }],
|
|
718
|
+
style: { "--fl-sticky-top-auto": `${stickyTop.value}px` }
|
|
719
|
+
}, _attrs))}><div class="fl-bar">`);
|
|
720
|
+
if (selected.value.size) _push(`<div class="fl-selection" role="status"><span class="fl-selection-count">${ssrInterpolate(t("selected", { count: selected.value.size }))}</span><span class="fl-selection-size">${ssrInterpolate(t("totalSize", { size: unref(formatSize)(selectedBytes.value) }))}</span></div>`);
|
|
721
|
+
else {
|
|
722
|
+
_push(`<div class="fl-title"><span class="fl-title-text">${ssrInterpolate(displayTitle.value)}</span>`);
|
|
723
|
+
if (demo.value) _push(`<span class="fl-demo-badge">${ssrInterpolate(t("demoBadge"))}</span>`);
|
|
724
|
+
else _push(`<!---->`);
|
|
725
|
+
_push(`</div>`);
|
|
726
|
+
}
|
|
727
|
+
if (selected.value.size) _push(`<button class="fl-clear" type="button"${ssrRenderAttr("aria-label", t("clearSelection"))}${ssrRenderAttr("title", t("clearSelection"))}><svg class="fl-clear-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12"></path><path d="M18 6 6 18"></path></svg><span class="fl-clear-text">${ssrInterpolate(t("clear"))}</span></button>`);
|
|
515
728
|
else _push(`<!---->`);
|
|
516
|
-
_push(
|
|
517
|
-
if (
|
|
729
|
+
_push(`<div class="fl-tools"><label class="fl-search"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><path d="m20 20-3.5-3.5"></path></svg><input${ssrRenderAttr("value", keyword.value)} type="text"${ssrRenderAttr("placeholder", t("filter"))}${ssrRenderAttr("aria-label", t("filter"))}></label><button class="fl-icon-btn" type="button"${ssrRenderAttr("aria-label", t("refresh"))}${ssrRenderAttr("title", t("refresh"))}><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-3-6.7"></path><path d="M21 4v5h-5"></path></svg></button></div>`);
|
|
730
|
+
if (selected.value.size) _push(`<button class="fl-btn fl-btn-primary" type="button"${ssrIncludeBooleanAttr(batchBusy.value) ? " disabled" : ""}><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12"></path><path d="m7 10 5 5 5-5"></path><path d="M5 21h14"></path></svg> ${ssrInterpolate(batchBusy.value ? t("batching", { percent: batchProgress.value }) : t("batch"))}</button>`);
|
|
518
731
|
else _push(`<!---->`);
|
|
519
|
-
_push(
|
|
732
|
+
_push(`</div>`);
|
|
733
|
+
if (needsPassword.value) _push(`<div class="fl-password"><span>${ssrInterpolate(t("passwordPrompt"))}</span><input${ssrRenderAttr("value", passwordInput.value)} type="password"${ssrRenderAttr("placeholder", t("passwordPlaceholder"))}${ssrRenderAttr("aria-label", t("passwordPlaceholder"))}><button class="fl-btn fl-btn-primary" type="button">${ssrInterpolate(t("open"))}</button></div>`);
|
|
734
|
+
else _push(`<!---->`);
|
|
735
|
+
_push(`<div class="fl-row fl-head"><label class="fl-cell fl-cell-check"><input type="checkbox"${ssrRenderAttr("aria-label", t("selectAll"))}${ssrIncludeBooleanAttr(allChecked.value) ? " checked" : ""}${ssrRenderAttr("indeterminate", someChecked.value)}></label><span class="fl-cell fl-cell-name"><button class="fl-sort-btn" type="button"${ssrRenderAttr("aria-sort", sortKey.value === "name" ? sortAsc.value ? "ascending" : "descending" : void 0)}>${ssrInterpolate(t("columnName"))}<span class="fl-sort" aria-hidden="true">${ssrInterpolate(sortKey.value === "name" ? sortAsc.value ? "▲" : "▼" : "")}</span></button></span><span class="fl-cell fl-cell-size"><button class="fl-sort-btn" type="button">${ssrInterpolate(t("columnSize"))}<span class="fl-sort" aria-hidden="true">${ssrInterpolate(sortKey.value === "size" ? sortAsc.value ? "▲" : "▼" : "")}</span></button></span><span class="fl-cell fl-cell-date"><button class="fl-sort-btn" type="button">${ssrInterpolate(t("columnDate"))}<span class="fl-sort" aria-hidden="true">${ssrInterpolate(sortKey.value === "modified" ? sortAsc.value ? "▲" : "▼" : "")}</span></button></span><span class="fl-cell fl-cell-op"><label class="fl-sort-select"><span>${ssrInterpolate(t("sortBy"))}</span><span class="fl-sort-current" aria-hidden="true">${ssrInterpolate(sortOptions.value.find((option) => option.value === sortValue.value)?.label)}</span><select${ssrRenderAttr("aria-label", t("sortBy"))}><!--[-->`);
|
|
736
|
+
ssrRenderList(sortOptions.value, (option) => {
|
|
737
|
+
_push(`<option${ssrRenderAttr("value", option.value)}${ssrIncludeBooleanAttr(Array.isArray(sortValue.value) ? ssrLooseContain(sortValue.value, option.value) : ssrLooseEqual(sortValue.value, option.value)) ? " selected" : ""}>${ssrInterpolate(option.label)}</option>`);
|
|
738
|
+
});
|
|
739
|
+
_push(`<!--]--></select></label></span></div>`);
|
|
520
740
|
if (loadingRoot.value) _push(`<div class="fl-status">${ssrInterpolate(t("loading"))}</div>`);
|
|
521
741
|
else if (errorMsg.value) {
|
|
522
742
|
_push(`<div class="fl-status fl-error">${ssrInterpolate(t("loadFailed", { message: errorMsg.value }))} `);
|
|
@@ -532,30 +752,39 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
532
752
|
_push(`<div class="${ssrRenderClass([{
|
|
533
753
|
"fl-row-dir": node.is_dir,
|
|
534
754
|
"fl-row-root": node.isRoot,
|
|
535
|
-
"fl-row-selected": selected.value.has(node.path)
|
|
536
|
-
}, "fl-row"])}"><
|
|
537
|
-
if (node.is_dir) _push(`<button type="button" class="${ssrRenderClass([{ "fl-arrow-open": node.expanded }, "fl-arrow"])}"
|
|
538
|
-
else _push(`<span class="fl-arrow-placeholder"></span>`);
|
|
539
|
-
_push(`<
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
755
|
+
"fl-row-selected": !node.is_dir && selected.value.has(node.path)
|
|
756
|
+
}, "fl-row"])}" style="${ssrRenderStyle({ "--fl-depth": node.depth })}"><label class="fl-cell fl-cell-check"><input type="checkbox"${ssrRenderAttr("aria-label", t("selectItem", { name: node.name }))}${ssrIncludeBooleanAttr(isChecked(node)) ? " checked" : ""}${ssrRenderAttr("indeterminate", isIndeterminate(node))}></label><span class="fl-cell fl-cell-name"${ssrRenderAttr("title", node.isRoot ? node.path : void 0)}><span class="fl-indent" aria-hidden="true"></span>`);
|
|
757
|
+
if (node.is_dir) _push(`<button type="button" class="${ssrRenderClass([{ "fl-arrow-open": node.expanded }, "fl-arrow"])}"${ssrRenderAttr("aria-label", t(node.expanded ? "collapse" : "expand", { name: node.name }))}${ssrRenderAttr("aria-expanded", node.expanded)}><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"></path></svg></button>`);
|
|
758
|
+
else _push(`<span class="fl-arrow-placeholder" aria-hidden="true"></span>`);
|
|
759
|
+
if (node.is_dir) _push(`<svg class="fl-folder-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path></svg>`);
|
|
760
|
+
else _push(`<span class="fl-type"${ssrRenderAttr("data-kind", unref(fileKind)(node.name))} aria-hidden="true">${ssrInterpolate(unref(extOf)(node.name) || "FILE")}</span>`);
|
|
761
|
+
_push(`<span class="fl-label"><span class="${ssrRenderClass([{ "fl-name-dir": node.is_dir }, "fl-name"])}">${ssrInterpolate(node.name)}</span><span class="fl-meta">`);
|
|
762
|
+
if (node.is_dir) {
|
|
763
|
+
_push(`<!--[-->`);
|
|
764
|
+
if (node.loaded) _push(`<!--[-->${ssrInterpolate(t("folderItems", { count: folderFiles(node).length }))} · ${ssrInterpolate(unref(formatSize)(unref(totalSize)(folderFiles(node))))}<!--]-->`);
|
|
765
|
+
else _push(`<!---->`);
|
|
766
|
+
_push(`<!--]-->`);
|
|
767
|
+
} else _push(`<!--[-->${ssrInterpolate(unref(formatSize)(node.size))} · ${ssrInterpolate(unref(formatDate)(node.modified))}<!--]-->`);
|
|
768
|
+
_push(`</span></span>`);
|
|
769
|
+
if (node.is_dir && node.loaded) _push(`<span class="fl-count">${ssrInterpolate(t("folderItems", { count: folderFiles(node).length }))}</span>`);
|
|
770
|
+
else _push(`<!---->`);
|
|
771
|
+
if (node.loading) _push(`<span class="fl-loading" aria-hidden="true">…</span>`);
|
|
544
772
|
else _push(`<!---->`);
|
|
545
|
-
_push(`</span
|
|
546
|
-
if (
|
|
773
|
+
_push(`</span><span class="fl-cell fl-cell-size">${ssrInterpolate(node.is_dir ? "—" : unref(formatSize)(node.size))}</span><span class="fl-cell fl-cell-date">${ssrInterpolate(unref(formatDate)(node.modified))}</span><span class="fl-cell fl-cell-op">`);
|
|
774
|
+
if (node.is_dir) _push(`<button type="button" class="${ssrRenderClass([{ "fl-arrow-open": node.expanded }, "fl-action fl-arrow-end"])}"${ssrRenderAttr("aria-label", t(node.expanded ? "collapse" : "expand", { name: node.name }))}${ssrRenderAttr("aria-expanded", node.expanded)}><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"></path></svg></button>`);
|
|
775
|
+
else {
|
|
547
776
|
_push(`<!--[-->`);
|
|
548
|
-
if (canPreview(node)) _push(`<button class="fl-download" type="button"${ssrRenderAttr("title", t("preview"))}><svg viewBox="0 0 24 24" width="
|
|
777
|
+
if (canPreview(node)) _push(`<button class="fl-action fl-download" type="button"${ssrRenderAttr("aria-label", `${t("preview")} ${node.name}`)}${ssrRenderAttr("title", t("preview"))}><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"></path><circle cx="12" cy="12" r="3"></circle></svg></button>`);
|
|
549
778
|
else _push(`<!---->`);
|
|
550
|
-
_push(`<button class="fl-download" type="button"${ssrRenderAttr("title", t("download"))}><svg viewBox="0 0 24 24" width="
|
|
551
|
-
}
|
|
779
|
+
_push(`<button class="fl-action fl-download" type="button"${ssrRenderAttr("aria-label", `${t("download")} ${node.name}`)}${ssrRenderAttr("title", t("download"))}><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12"></path><path d="m7 10 5 5 5-5"></path><path d="M5 21h14"></path></svg></button><!--]-->`);
|
|
780
|
+
}
|
|
552
781
|
_push(`</span></div>`);
|
|
553
782
|
});
|
|
554
|
-
_push(`<!--]--><div class="fl-foot"><span>${ssrInterpolate(t("loaded", { count: allFiles.value.length }))} · ${ssrInterpolate(t("
|
|
555
|
-
if (unloadedFolders.value) _push(`<span
|
|
783
|
+
_push(`<!--]--><div class="fl-foot"><span>${ssrInterpolate(t("loaded", { count: allFiles.value.length }))} · ${ssrInterpolate(t("totalSize", { size: unref(formatSize)(loadedBytes.value) }))}</span>`);
|
|
784
|
+
if (unloadedFolders.value) _push(`<span class="fl-foot-hint">${ssrInterpolate(t("unloaded", { count: unloadedFolders.value }))}</span>`);
|
|
556
785
|
else _push(`<!---->`);
|
|
557
786
|
_push(`</div>`);
|
|
558
|
-
if (toast.value) _push(`<div class="fl-toast">${ssrInterpolate(toast.value)}</div>`);
|
|
787
|
+
if (toast.value) _push(`<div class="fl-toast" role="status">${ssrInterpolate(toast.value)}</div>`);
|
|
559
788
|
else _push(`<!---->`);
|
|
560
789
|
_push(`</div>`);
|
|
561
790
|
};
|
|
@@ -588,4 +817,4 @@ function enhanceAppWithFileList({ app }) {
|
|
|
588
817
|
if (!app._context.components.FileList) app.component("FileList", _sfc_main);
|
|
589
818
|
if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
|
|
590
819
|
}
|
|
591
|
-
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels };
|
|
820
|
+
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileKind, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, totalSize, uniqueEntryName, zipEntryName, zipSegment };
|