vitepress-plugin-filelist 0.2.3 → 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.
@@ -1,5 +1,5 @@
1
1
  import "../style.css";
2
- import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, normalizeClass, normalizeStyle, onMounted, openBlock, ref, renderList, toDisplayString, unref, vModelText, withDirectives, withKeys } from "vue";
2
+ import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, toDisplayString, unref, vModelSelect, vModelText, withDirectives, withKeys } from "vue";
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 = {}) {
@@ -151,6 +169,97 @@ function extOf(name) {
151
169
  const match = name.match(/\.([a-z0-9]+)$/i);
152
170
  return match ? match[1].toUpperCase() : "";
153
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
+ }
154
263
  function compareNodes(a, b, key, ascending = true) {
155
264
  if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1;
156
265
  let result = 0;
@@ -160,83 +269,152 @@ function compareNodes(a, b, key, ascending = true) {
160
269
  return ascending ? result : -result;
161
270
  }
162
271
  // src/client/FileList.vue
163
- const _hoisted_1 = { class: "fl-root" };
164
- const _hoisted_2 = { class: "fl-bar" };
165
- const _hoisted_3 = { class: "fl-title" };
166
- const _hoisted_4 = { class: "fl-title-text" };
272
+ const _hoisted_1 = { class: "fl-bar" };
273
+ const _hoisted_2 = {
274
+ key: 0,
275
+ class: "fl-selection",
276
+ role: "status"
277
+ };
278
+ const _hoisted_3 = { class: "fl-selection-count" };
279
+ const _hoisted_4 = { class: "fl-selection-size" };
167
280
  const _hoisted_5 = {
281
+ key: 1,
282
+ class: "fl-title"
283
+ };
284
+ const _hoisted_6 = { class: "fl-title-text" };
285
+ const _hoisted_7 = {
168
286
  key: 0,
169
287
  class: "fl-demo-badge"
170
288
  };
171
- const _hoisted_6 = { class: "fl-tools" };
172
- const _hoisted_7 = ["placeholder"];
173
- const _hoisted_8 = ["disabled"];
174
- const _hoisted_9 = {
289
+ const _hoisted_8 = ["aria-label", "title"];
290
+ const _hoisted_9 = { class: "fl-clear-text" };
291
+ const _hoisted_10 = { class: "fl-tools" };
292
+ const _hoisted_11 = { class: "fl-search" };
293
+ const _hoisted_12 = ["placeholder", "aria-label"];
294
+ const _hoisted_13 = ["aria-label", "title"];
295
+ const _hoisted_14 = ["disabled"];
296
+ const _hoisted_15 = {
175
297
  key: 0,
176
298
  class: "fl-password"
177
299
  };
178
- const _hoisted_10 = ["placeholder"];
179
- const _hoisted_11 = { class: "fl-row fl-head" };
180
- const _hoisted_12 = { class: "fl-cell fl-cell-check" };
181
- const _hoisted_13 = ["checked", ".indeterminate"];
182
- const _hoisted_14 = { class: "fl-sort" };
183
- const _hoisted_15 = { class: "fl-sort" };
184
- const _hoisted_16 = { class: "fl-sort" };
185
- const _hoisted_17 = {
300
+ const _hoisted_16 = ["placeholder", "aria-label"];
301
+ const _hoisted_17 = { class: "fl-row fl-head" };
302
+ const _hoisted_18 = { class: "fl-cell fl-cell-check" };
303
+ const _hoisted_19 = [
304
+ "aria-label",
305
+ "checked",
306
+ ".indeterminate"
307
+ ];
308
+ const _hoisted_20 = { class: "fl-cell fl-cell-name" };
309
+ const _hoisted_21 = ["aria-sort"];
310
+ const _hoisted_22 = {
311
+ class: "fl-sort",
312
+ "aria-hidden": "true"
313
+ };
314
+ const _hoisted_23 = { class: "fl-cell fl-cell-size" };
315
+ const _hoisted_24 = {
316
+ class: "fl-sort",
317
+ "aria-hidden": "true"
318
+ };
319
+ const _hoisted_25 = { class: "fl-cell fl-cell-date" };
320
+ const _hoisted_26 = {
321
+ class: "fl-sort",
322
+ "aria-hidden": "true"
323
+ };
324
+ const _hoisted_27 = { class: "fl-cell fl-cell-op" };
325
+ const _hoisted_28 = { class: "fl-sort-select" };
326
+ const _hoisted_29 = {
327
+ class: "fl-sort-current",
328
+ "aria-hidden": "true"
329
+ };
330
+ const _hoisted_30 = ["aria-label"];
331
+ const _hoisted_31 = ["value"];
332
+ const _hoisted_32 = {
186
333
  key: 1,
187
334
  class: "fl-status"
188
335
  };
189
- const _hoisted_18 = {
336
+ const _hoisted_33 = {
190
337
  key: 2,
191
338
  class: "fl-status fl-error"
192
339
  };
193
- const _hoisted_19 = {
340
+ const _hoisted_34 = {
194
341
  key: 0,
195
342
  class: "fl-hint"
196
343
  };
197
- const _hoisted_20 = {
344
+ const _hoisted_35 = {
198
345
  key: 1,
199
346
  class: "fl-hint"
200
347
  };
201
- const _hoisted_21 = {
348
+ const _hoisted_36 = {
202
349
  key: 3,
203
350
  class: "fl-status"
204
351
  };
205
- const _hoisted_22 = { class: "fl-cell fl-cell-check" };
206
- const _hoisted_23 = [
352
+ const _hoisted_37 = { class: "fl-cell fl-cell-check" };
353
+ const _hoisted_38 = [
354
+ "aria-label",
207
355
  "checked",
208
356
  ".indeterminate",
209
357
  "onChange"
210
358
  ];
211
- const _hoisted_24 = ["title"];
212
- const _hoisted_25 = ["onClick"];
213
- const _hoisted_26 = {
359
+ const _hoisted_39 = ["title"];
360
+ const _hoisted_40 = [
361
+ "aria-label",
362
+ "aria-expanded",
363
+ "onClick"
364
+ ];
365
+ const _hoisted_41 = {
214
366
  key: 1,
215
- class: "fl-arrow-placeholder"
367
+ class: "fl-arrow-placeholder",
368
+ "aria-hidden": "true"
216
369
  };
217
- const _hoisted_27 = ["onClick"];
218
- const _hoisted_28 = {
219
- key: 0,
220
- class: "fl-folder-icon"
370
+ const _hoisted_42 = {
371
+ key: 2,
372
+ class: "fl-folder-icon",
373
+ viewBox: "0 0 24 24",
374
+ width: "18",
375
+ height: "18",
376
+ "aria-hidden": "true"
221
377
  };
222
- const _hoisted_29 = {
223
- key: 1,
224
- class: "fl-ext-badge"
378
+ const _hoisted_43 = ["data-kind"];
379
+ const _hoisted_44 = { class: "fl-label" };
380
+ const _hoisted_45 = ["onClick"];
381
+ const _hoisted_46 = { class: "fl-meta" };
382
+ const _hoisted_47 = {
383
+ key: 4,
384
+ class: "fl-count"
225
385
  };
226
- const _hoisted_30 = {
227
- key: 2,
228
- class: "fl-loading"
386
+ const _hoisted_48 = {
387
+ key: 5,
388
+ class: "fl-loading",
389
+ "aria-hidden": "true"
229
390
  };
230
- const _hoisted_31 = { class: "fl-cell fl-cell-size" };
231
- const _hoisted_32 = { class: "fl-cell fl-cell-date" };
232
- const _hoisted_33 = { class: "fl-cell fl-cell-op" };
233
- const _hoisted_34 = ["title", "onClick"];
234
- const _hoisted_35 = ["title", "onClick"];
235
- const _hoisted_36 = { class: "fl-foot" };
236
- const _hoisted_37 = { key: 0 };
237
- const _hoisted_38 = {
391
+ const _hoisted_49 = { class: "fl-cell fl-cell-size" };
392
+ const _hoisted_50 = { class: "fl-cell fl-cell-date" };
393
+ const _hoisted_51 = { class: "fl-cell fl-cell-op" };
394
+ const _hoisted_52 = [
395
+ "aria-label",
396
+ "aria-expanded",
397
+ "onClick"
398
+ ];
399
+ const _hoisted_53 = [
400
+ "aria-label",
401
+ "title",
402
+ "onClick"
403
+ ];
404
+ const _hoisted_54 = [
405
+ "aria-label",
406
+ "title",
407
+ "onClick"
408
+ ];
409
+ const _hoisted_55 = { class: "fl-foot" };
410
+ const _hoisted_56 = {
411
+ key: 0,
412
+ class: "fl-foot-hint"
413
+ };
414
+ const _hoisted_57 = {
238
415
  key: 4,
239
- class: "fl-toast"
416
+ class: "fl-toast",
417
+ role: "status"
240
418
  };
241
419
  const _sfc_main = /*@__PURE__*/ defineComponent({
242
420
  __name: "FileList",
@@ -529,6 +707,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
529
707
  sortKey.value = key;
530
708
  sortAsc.value = true;
531
709
  }
710
+ resortAll();
711
+ }
712
+ function resortAll() {
532
713
  if (props.sources.length) {
533
714
  for (const root of roots.value) if (root.children.length) sortTree(root.children);
534
715
  } else sortTree(roots.value);
@@ -684,6 +865,39 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
684
865
  const allFiles = computed(() => roots.value.flatMap(descendantFiles));
685
866
  const allChecked = computed(() => allFiles.value.length > 0 && allFiles.value.every((file) => selected.value.has(file.path)));
686
867
  const someChecked = computed(() => !allChecked.value && allFiles.value.some((file) => selected.value.has(file.path)));
868
+ const selectedFiles = computed(() => allFiles.value.filter((file) => selected.value.has(file.path)));
869
+ const selectedBytes = computed(() => totalSize(selectedFiles.value));
870
+ const loadedBytes = computed(() => totalSize(allFiles.value));
871
+ function clearSelection() {
872
+ selected.value = /* @__PURE__ */ new Set();
873
+ }
874
+ function folderFiles(node) {
875
+ return node.is_dir && node.loaded ? descendantFiles(node) : [];
876
+ }
877
+ /** Compact sort control for narrow containers, where header cells are hidden. */
878
+ const sortOptions = computed(() => [
879
+ "name",
880
+ "size",
881
+ "modified"
882
+ ].flatMap((key) => {
883
+ const label = t(key === "name" ? "columnName" : key === "size" ? "columnSize" : "columnDate");
884
+ return [{
885
+ value: `${key}:asc`,
886
+ label: `${label} ↑`
887
+ }, {
888
+ value: `${key}:desc`,
889
+ label: `${label} ↓`
890
+ }];
891
+ }));
892
+ const sortValue = computed({
893
+ get: () => `${sortKey.value}:${sortAsc.value ? "asc" : "desc"}`,
894
+ set: (value) => {
895
+ const [key, direction] = value.split(":");
896
+ sortKey.value = key;
897
+ sortAsc.value = direction !== "desc";
898
+ resortAll();
899
+ }
900
+ });
687
901
  function toggleCheckAll() {
688
902
  selected.value = allChecked.value ? /* @__PURE__ */ new Set() : new Set(allFiles.value.map((file) => file.path));
689
903
  }
@@ -789,124 +1003,258 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
789
1003
  loadRoot();
790
1004
  }
791
1005
  const displayTitle = computed(() => props.title || siteTitle.value || (props.path === "/" ? t("allFiles") : props.path));
1006
+ const stickyTop = ref(0);
1007
+ function measureStickyTop() {
1008
+ if (typeof document === "undefined") return;
1009
+ let top = 0;
1010
+ for (const el of document.querySelectorAll(".VPNav, .VPLocalNav")) {
1011
+ const style = getComputedStyle(el);
1012
+ if (style.display === "none" || style.position !== "fixed" && style.position !== "sticky") continue;
1013
+ top = Math.max(top, (Number.parseFloat(style.top) || 0) + el.offsetHeight);
1014
+ }
1015
+ stickyTop.value = top;
1016
+ }
792
1017
  onMounted(() => {
793
1018
  loadRoot();
794
1019
  loadSiteTitle();
1020
+ measureStickyTop();
1021
+ window.addEventListener("resize", measureStickyTop, { passive: true });
1022
+ });
1023
+ onBeforeUnmount(() => {
1024
+ window.removeEventListener("resize", measureStickyTop);
1025
+ clearTimeout(toastTimer);
795
1026
  });
796
1027
  return (_ctx, _cache) => {
797
- return openBlock(), createElementBlock("div", _hoisted_1, [
798
- createElementVNode("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [
799
- _cache[5] || (_cache[5] = createElementVNode("span", { class: "fl-title-icon" }, "🗂️", -1)),
800
- createElementVNode("span", _hoisted_4, toDisplayString(displayTitle.value), 1),
801
- demo.value ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(t("demoBadge")), 1)) : createCommentVNode("v-if", true)
802
- ]), createElementVNode("div", _hoisted_6, [
803
- withDirectives(createElementVNode("input", {
1028
+ return openBlock(), createElementBlock("div", {
1029
+ class: normalizeClass(["fl-root", { "fl-selecting": selected.value.size > 0 }]),
1030
+ style: normalizeStyle({ "--fl-sticky-top-auto": `${stickyTop.value}px` })
1031
+ }, [
1032
+ createElementVNode("div", _hoisted_1, [
1033
+ selected.value.size ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("span", _hoisted_3, toDisplayString(t("selected", { count: selected.value.size })), 1), createElementVNode("span", _hoisted_4, toDisplayString(t("totalSize", { size: unref(formatSize)(selectedBytes.value) })), 1)])) : (openBlock(), createElementBlock("div", _hoisted_5, [createElementVNode("span", _hoisted_6, toDisplayString(displayTitle.value), 1), demo.value ? (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString(t("demoBadge")), 1)) : createCommentVNode("v-if", true)])),
1034
+ selected.value.size ? (openBlock(), createElementBlock("button", {
1035
+ key: 2,
1036
+ class: "fl-clear",
1037
+ type: "button",
1038
+ "aria-label": t("clearSelection"),
1039
+ title: t("clearSelection"),
1040
+ onClick: clearSelection
1041
+ }, [_cache[6] || (_cache[6] = createElementVNode("svg", {
1042
+ class: "fl-clear-icon",
1043
+ viewBox: "0 0 24 24",
1044
+ width: "18",
1045
+ height: "18",
1046
+ fill: "none",
1047
+ stroke: "currentColor",
1048
+ "stroke-width": "2.2",
1049
+ "stroke-linecap": "round",
1050
+ "aria-hidden": "true"
1051
+ }, [createElementVNode("path", { d: "M6 6l12 12" }), createElementVNode("path", { d: "M18 6 6 18" })], -1)), createElementVNode("span", _hoisted_9, toDisplayString(t("clear")), 1)], 8, _hoisted_8)) : createCommentVNode("v-if", true),
1052
+ createElementVNode("div", _hoisted_10, [createElementVNode("label", _hoisted_11, [_cache[7] || (_cache[7] = createElementVNode("svg", {
1053
+ viewBox: "0 0 24 24",
1054
+ width: "15",
1055
+ height: "15",
1056
+ fill: "none",
1057
+ stroke: "currentColor",
1058
+ "stroke-width": "2",
1059
+ "stroke-linecap": "round",
1060
+ "aria-hidden": "true"
1061
+ }, [createElementVNode("circle", {
1062
+ cx: "11",
1063
+ cy: "11",
1064
+ r: "7"
1065
+ }), createElementVNode("path", { d: "m20 20-3.5-3.5" })], -1)), withDirectives(createElementVNode("input", {
804
1066
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => keyword.value = $event),
805
- class: "fl-search",
806
1067
  type: "text",
807
- placeholder: t("filter")
808
- }, null, 8, _hoisted_7), [[vModelText, keyword.value]]),
809
- createElementVNode("button", {
810
- class: "fl-btn",
1068
+ placeholder: t("filter"),
1069
+ "aria-label": t("filter")
1070
+ }, null, 8, _hoisted_12), [[vModelText, keyword.value]])]), createElementVNode("button", {
1071
+ class: "fl-icon-btn",
811
1072
  type: "button",
1073
+ "aria-label": t("refresh"),
1074
+ title: t("refresh"),
812
1075
  onClick: loadRoot
813
- }, toDisplayString(t("refresh")), 1),
814
- createElementVNode("button", {
1076
+ }, [..._cache[8] || (_cache[8] = [createElementVNode("svg", {
1077
+ viewBox: "0 0 24 24",
1078
+ width: "15",
1079
+ height: "15",
1080
+ fill: "none",
1081
+ stroke: "currentColor",
1082
+ "stroke-width": "2",
1083
+ "stroke-linecap": "round",
1084
+ "stroke-linejoin": "round",
1085
+ "aria-hidden": "true"
1086
+ }, [createElementVNode("path", { d: "M21 12a9 9 0 1 1-3-6.7" }), createElementVNode("path", { d: "M21 4v5h-5" })], -1)])], 8, _hoisted_13)]),
1087
+ selected.value.size ? (openBlock(), createElementBlock("button", {
1088
+ key: 3,
815
1089
  class: "fl-btn fl-btn-primary",
816
1090
  type: "button",
817
- disabled: selected.value.size === 0 || batchBusy.value,
1091
+ disabled: batchBusy.value,
818
1092
  onClick: batchDownload
819
- }, toDisplayString(batchBusy.value ? t("batching", { percent: batchProgress.value }) : selected.value.size ? t("batchCount", { count: selected.value.size }) : t("batch")), 9, _hoisted_8)
820
- ])]),
821
- needsPassword.value ? (openBlock(), createElementBlock("div", _hoisted_9, [
1093
+ }, [_cache[9] || (_cache[9] = createElementVNode("svg", {
1094
+ viewBox: "0 0 24 24",
1095
+ width: "15",
1096
+ height: "15",
1097
+ fill: "none",
1098
+ stroke: "currentColor",
1099
+ "stroke-width": "2.2",
1100
+ "stroke-linecap": "round",
1101
+ "stroke-linejoin": "round",
1102
+ "aria-hidden": "true"
1103
+ }, [
1104
+ createElementVNode("path", { d: "M12 3v12" }),
1105
+ createElementVNode("path", { d: "m7 10 5 5 5-5" }),
1106
+ createElementVNode("path", { d: "M5 21h14" })
1107
+ ], -1)), createTextVNode(" " + toDisplayString(batchBusy.value ? t("batching", { percent: batchProgress.value }) : t("batch")), 1)], 8, _hoisted_14)) : createCommentVNode("v-if", true)
1108
+ ]),
1109
+ needsPassword.value ? (openBlock(), createElementBlock("div", _hoisted_15, [
822
1110
  createElementVNode("span", null, toDisplayString(t("passwordPrompt")), 1),
823
1111
  withDirectives(createElementVNode("input", {
824
1112
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => passwordInput.value = $event),
825
1113
  type: "password",
826
1114
  placeholder: t("passwordPlaceholder"),
1115
+ "aria-label": t("passwordPlaceholder"),
827
1116
  onKeyup: withKeys(submitPassword, ["enter"])
828
- }, null, 40, _hoisted_10), [[vModelText, passwordInput.value]]),
1117
+ }, null, 40, _hoisted_16), [[vModelText, passwordInput.value]]),
829
1118
  createElementVNode("button", {
830
1119
  class: "fl-btn fl-btn-primary",
831
1120
  type: "button",
832
1121
  onClick: submitPassword
833
1122
  }, toDisplayString(t("open")), 1)
834
1123
  ])) : createCommentVNode("v-if", true),
835
- createElementVNode("div", _hoisted_11, [
836
- createElementVNode("span", _hoisted_12, [createElementVNode("input", {
1124
+ createElementVNode("div", _hoisted_17, [
1125
+ createElementVNode("label", _hoisted_18, [createElementVNode("input", {
837
1126
  type: "checkbox",
1127
+ "aria-label": t("selectAll"),
838
1128
  checked: allChecked.value,
839
1129
  ".indeterminate": someChecked.value,
840
1130
  onChange: toggleCheckAll
841
- }, null, 40, _hoisted_13)]),
842
- createElementVNode("span", {
843
- class: "fl-cell fl-cell-name",
1131
+ }, null, 40, _hoisted_19)]),
1132
+ createElementVNode("span", _hoisted_20, [createElementVNode("button", {
1133
+ class: "fl-sort-btn",
1134
+ type: "button",
1135
+ "aria-sort": sortKey.value === "name" ? sortAsc.value ? "ascending" : "descending" : void 0,
844
1136
  onClick: _cache[2] || (_cache[2] = ($event) => setSort("name"))
845
- }, [createTextVNode(toDisplayString(t("columnName")), 1), createElementVNode("span", _hoisted_14, toDisplayString(sortKey.value === "name" ? sortAsc.value ? "▲" : "▼" : ""), 1)]),
846
- createElementVNode("span", {
847
- class: "fl-cell fl-cell-size",
1137
+ }, [createTextVNode(toDisplayString(t("columnName")), 1), createElementVNode("span", _hoisted_22, toDisplayString(sortKey.value === "name" ? sortAsc.value ? "▲" : "▼" : ""), 1)], 8, _hoisted_21)]),
1138
+ createElementVNode("span", _hoisted_23, [createElementVNode("button", {
1139
+ class: "fl-sort-btn",
1140
+ type: "button",
848
1141
  onClick: _cache[3] || (_cache[3] = ($event) => setSort("size"))
849
- }, [createTextVNode(toDisplayString(t("columnSize")), 1), createElementVNode("span", _hoisted_15, toDisplayString(sortKey.value === "size" ? sortAsc.value ? "▲" : "▼" : ""), 1)]),
850
- createElementVNode("span", {
851
- class: "fl-cell fl-cell-date",
1142
+ }, [createTextVNode(toDisplayString(t("columnSize")), 1), createElementVNode("span", _hoisted_24, toDisplayString(sortKey.value === "size" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
1143
+ createElementVNode("span", _hoisted_25, [createElementVNode("button", {
1144
+ class: "fl-sort-btn",
1145
+ type: "button",
852
1146
  onClick: _cache[4] || (_cache[4] = ($event) => setSort("modified"))
853
- }, [createTextVNode(toDisplayString(t("columnDate")), 1), createElementVNode("span", _hoisted_16, toDisplayString(sortKey.value === "modified" ? sortAsc.value ? "▲" : "▼" : ""), 1)]),
854
- _cache[6] || (_cache[6] = createElementVNode("span", { class: "fl-cell fl-cell-op" }, null, -1))
1147
+ }, [createTextVNode(toDisplayString(t("columnDate")), 1), createElementVNode("span", _hoisted_26, toDisplayString(sortKey.value === "modified" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
1148
+ createElementVNode("span", _hoisted_27, [createElementVNode("label", _hoisted_28, [
1149
+ createElementVNode("span", null, toDisplayString(t("sortBy")), 1),
1150
+ createElementVNode("span", _hoisted_29, toDisplayString(sortOptions.value.find((option) => option.value === sortValue.value)?.label), 1),
1151
+ withDirectives(createElementVNode("select", {
1152
+ "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => sortValue.value = $event),
1153
+ "aria-label": t("sortBy")
1154
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortOptions.value, (option) => {
1155
+ return openBlock(), createElementBlock("option", {
1156
+ key: option.value,
1157
+ value: option.value
1158
+ }, toDisplayString(option.label), 9, _hoisted_31);
1159
+ }), 128))], 8, _hoisted_30), [[vModelSelect, sortValue.value]])
1160
+ ])])
855
1161
  ]),
856
- loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_17, toDisplayString(t("loading")), 1)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_18, [
1162
+ loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_32, toDisplayString(t("loading")), 1)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_33, [
857
1163
  createTextVNode(toDisplayString(t("loadFailed", { message: errorMsg.value })) + " ", 1),
858
- /guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_19, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
859
- /failed to fetch|networkerror/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_20, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
1164
+ /guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_34, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
1165
+ /failed to fetch|networkerror/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_35, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
860
1166
  createElementVNode("button", {
861
1167
  class: "fl-btn",
862
1168
  type: "button",
863
1169
  onClick: loadRoot
864
1170
  }, toDisplayString(t("retry")), 1)
865
- ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_21, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
1171
+ ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_36, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
866
1172
  (openBlock(true), createElementBlock(Fragment, null, renderList(visible.value, (node) => {
867
1173
  return openBlock(), createElementBlock("div", {
868
1174
  key: node.path,
869
1175
  class: normalizeClass(["fl-row", {
870
1176
  "fl-row-dir": node.is_dir,
871
1177
  "fl-row-root": node.isRoot,
872
- "fl-row-selected": selected.value.has(node.path)
873
- }])
1178
+ "fl-row-selected": !node.is_dir && selected.value.has(node.path)
1179
+ }]),
1180
+ style: normalizeStyle({ "--fl-depth": node.depth })
874
1181
  }, [
875
- createElementVNode("span", _hoisted_22, [createElementVNode("input", {
1182
+ createElementVNode("label", _hoisted_37, [createElementVNode("input", {
876
1183
  type: "checkbox",
1184
+ "aria-label": t("selectItem", { name: node.name }),
877
1185
  checked: isChecked(node),
878
1186
  ".indeterminate": isIndeterminate(node),
879
1187
  onChange: ($event) => toggleCheck(node, $event)
880
- }, null, 40, _hoisted_23)]),
1188
+ }, null, 40, _hoisted_38)]),
881
1189
  createElementVNode("span", {
882
1190
  class: "fl-cell fl-cell-name",
883
- title: node.isRoot ? node.path : void 0,
884
- style: normalizeStyle({ paddingLeft: `${node.depth * 22}px` })
885
- }, [node.is_dir ? (openBlock(), createElementBlock("button", {
1191
+ title: node.isRoot ? node.path : void 0
1192
+ }, [
1193
+ _cache[12] || (_cache[12] = createElementVNode("span", {
1194
+ class: "fl-indent",
1195
+ "aria-hidden": "true"
1196
+ }, null, -1)),
1197
+ node.is_dir ? (openBlock(), createElementBlock("button", {
1198
+ key: 0,
1199
+ class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
1200
+ type: "button",
1201
+ "aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
1202
+ "aria-expanded": node.expanded,
1203
+ onClick: ($event) => toggleExpand(node)
1204
+ }, [..._cache[10] || (_cache[10] = [createElementVNode("svg", {
1205
+ viewBox: "0 0 24 24",
1206
+ width: "14",
1207
+ height: "14",
1208
+ fill: "none",
1209
+ stroke: "currentColor",
1210
+ "stroke-width": "2.4",
1211
+ "stroke-linecap": "round",
1212
+ "stroke-linejoin": "round",
1213
+ "aria-hidden": "true"
1214
+ }, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_40)) : (openBlock(), createElementBlock("span", _hoisted_41)),
1215
+ node.is_dir ? (openBlock(), createElementBlock("svg", _hoisted_42, [..._cache[11] || (_cache[11] = [createElementVNode("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" }, null, -1)])])) : (openBlock(), createElementBlock("span", {
1216
+ key: 3,
1217
+ class: "fl-type",
1218
+ "data-kind": unref(fileKind)(node.name),
1219
+ "aria-hidden": "true"
1220
+ }, toDisplayString(unref(extOf)(node.name) || "FILE"), 9, _hoisted_43)),
1221
+ createElementVNode("span", _hoisted_44, [createElementVNode("span", {
1222
+ class: normalizeClass(["fl-name", { "fl-name-dir": node.is_dir }]),
1223
+ onClick: ($event) => node.is_dir ? toggleExpand(node) : download(node)
1224
+ }, toDisplayString(node.name), 11, _hoisted_45), createElementVNode("span", _hoisted_46, [node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [node.loaded ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(t("folderItems", { count: folderFiles(node).length })) + " · " + toDisplayString(unref(formatSize)(unref(totalSize)(folderFiles(node)))), 1)], 64)) : createCommentVNode("v-if", true)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(formatSize)(node.size)) + " · " + toDisplayString(unref(formatDate)(node.modified)), 1)], 64))])]),
1225
+ node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_47, toDisplayString(t("folderItems", { count: folderFiles(node).length })), 1)) : createCommentVNode("v-if", true),
1226
+ node.loading ? (openBlock(), createElementBlock("span", _hoisted_48, "…")) : createCommentVNode("v-if", true)
1227
+ ], 8, _hoisted_39),
1228
+ createElementVNode("span", _hoisted_49, toDisplayString(node.is_dir ? "—" : unref(formatSize)(node.size)), 1),
1229
+ createElementVNode("span", _hoisted_50, toDisplayString(unref(formatDate)(node.modified)), 1),
1230
+ createElementVNode("span", _hoisted_51, [node.is_dir ? (openBlock(), createElementBlock("button", {
886
1231
  key: 0,
887
- class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
1232
+ class: normalizeClass(["fl-action fl-arrow-end", { "fl-arrow-open": node.expanded }]),
888
1233
  type: "button",
1234
+ "aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
1235
+ "aria-expanded": node.expanded,
889
1236
  onClick: ($event) => toggleExpand(node)
890
- }, "▸", 10, _hoisted_25)) : (openBlock(), createElementBlock("span", _hoisted_26)), createElementVNode("span", {
891
- class: normalizeClass(["fl-name", { "fl-name-link": node.is_dir }]),
892
- onClick: ($event) => node.is_dir ? toggleExpand(node) : download(node)
893
- }, [
894
- node.is_dir ? (openBlock(), createElementBlock("span", _hoisted_28, "📁")) : (openBlock(), createElementBlock("span", _hoisted_29, toDisplayString(unref(extOf)(node.name) || "FILE"), 1)),
895
- createTextVNode(" " + toDisplayString(node.name) + " ", 1),
896
- node.loading ? (openBlock(), createElementBlock("span", _hoisted_30, "…")) : createCommentVNode("v-if", true)
897
- ], 10, _hoisted_27)], 12, _hoisted_24),
898
- createElementVNode("span", _hoisted_31, toDisplayString(node.is_dir ? "-" : unref(formatSize)(node.size)), 1),
899
- createElementVNode("span", _hoisted_32, toDisplayString(unref(formatDate)(node.modified)), 1),
900
- createElementVNode("span", _hoisted_33, [!node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
1237
+ }, [..._cache[13] || (_cache[13] = [createElementVNode("svg", {
1238
+ viewBox: "0 0 24 24",
1239
+ width: "18",
1240
+ height: "18",
1241
+ fill: "none",
1242
+ stroke: "currentColor",
1243
+ "stroke-width": "2.2",
1244
+ "stroke-linecap": "round",
1245
+ "stroke-linejoin": "round",
1246
+ "aria-hidden": "true"
1247
+ }, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_52)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
901
1248
  key: 0,
902
- class: "fl-download",
1249
+ class: "fl-action fl-download",
903
1250
  type: "button",
1251
+ "aria-label": `${t("preview")} ${node.name}`,
904
1252
  title: t("preview"),
905
1253
  onClick: ($event) => preview(node)
906
- }, [..._cache[7] || (_cache[7] = [createElementVNode("svg", {
1254
+ }, [..._cache[14] || (_cache[14] = [createElementVNode("svg", {
907
1255
  viewBox: "0 0 24 24",
908
- width: "15",
909
- height: "15",
1256
+ width: "16",
1257
+ height: "16",
910
1258
  fill: "none",
911
1259
  stroke: "currentColor",
912
1260
  "stroke-width": "2",
@@ -917,15 +1265,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
917
1265
  cx: "12",
918
1266
  cy: "12",
919
1267
  r: "3"
920
- })], -1)])], 8, _hoisted_34)) : createCommentVNode("v-if", true), createElementVNode("button", {
921
- class: "fl-download",
1268
+ })], -1)])], 8, _hoisted_53)) : createCommentVNode("v-if", true), createElementVNode("button", {
1269
+ class: "fl-action fl-download",
922
1270
  type: "button",
1271
+ "aria-label": `${t("download")} ${node.name}`,
923
1272
  title: t("download"),
924
1273
  onClick: ($event) => download(node)
925
- }, [..._cache[8] || (_cache[8] = [createElementVNode("svg", {
1274
+ }, [..._cache[15] || (_cache[15] = [createElementVNode("svg", {
926
1275
  viewBox: "0 0 24 24",
927
- width: "15",
928
- height: "15",
1276
+ width: "16",
1277
+ height: "16",
929
1278
  fill: "none",
930
1279
  stroke: "currentColor",
931
1280
  "stroke-width": "2",
@@ -936,12 +1285,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
936
1285
  createElementVNode("path", { d: "M12 3v12" }),
937
1286
  createElementVNode("path", { d: "m7 10 5 5 5-5" }),
938
1287
  createElementVNode("path", { d: "M5 21h14" })
939
- ], -1)])], 8, _hoisted_35)], 64)) : createCommentVNode("v-if", true)])
940
- ], 2);
1288
+ ], -1)])], 8, _hoisted_54)], 64))])
1289
+ ], 6);
941
1290
  }), 128)),
942
- createElementVNode("div", _hoisted_36, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("selected", { count: selected.value.size })), 1), unloadedFolders.value ? (openBlock(), createElementBlock("span", _hoisted_37, " · " + toDisplayString(t("unloaded", { count: unloadedFolders.value })), 1)) : createCommentVNode("v-if", true)]),
943
- toast.value ? (openBlock(), createElementBlock("div", _hoisted_38, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true)
944
- ]);
1291
+ createElementVNode("div", _hoisted_55, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: unref(formatSize)(loadedBytes.value) })), 1), unloadedFolders.value ? (openBlock(), createElementBlock("span", _hoisted_56, toDisplayString(t("unloaded", { count: unloadedFolders.value })), 1)) : createCommentVNode("v-if", true)]),
1292
+ toast.value ? (openBlock(), createElementBlock("div", _hoisted_57, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true)
1293
+ ], 6);
945
1294
  };
946
1295
  }
947
1296
  });
@@ -966,4 +1315,4 @@ function enhanceAppWithFileList({ app }) {
966
1315
  if (!app._context.components.FileList) app.component("FileList", _sfc_main);
967
1316
  if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
968
1317
  }
969
- export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, uniqueEntryName, zipEntryName, zipSegment };
1318
+ export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileKind, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, totalSize, uniqueEntryName, zipEntryName, zipSegment };