vitepress-plugin-filelist 0.2.3 → 0.3.1

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,148 @@ 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 = {
238
411
  key: 4,
239
- class: "fl-toast"
412
+ class: "fl-toast",
413
+ role: "status"
240
414
  };
241
415
  const _sfc_main = /*@__PURE__*/ defineComponent({
242
416
  __name: "FileList",
@@ -529,6 +703,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
529
703
  sortKey.value = key;
530
704
  sortAsc.value = true;
531
705
  }
706
+ resortAll();
707
+ }
708
+ function resortAll() {
532
709
  if (props.sources.length) {
533
710
  for (const root of roots.value) if (root.children.length) sortTree(root.children);
534
711
  } else sortTree(roots.value);
@@ -684,20 +861,42 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
684
861
  const allFiles = computed(() => roots.value.flatMap(descendantFiles));
685
862
  const allChecked = computed(() => allFiles.value.length > 0 && allFiles.value.every((file) => selected.value.has(file.path)));
686
863
  const someChecked = computed(() => !allChecked.value && allFiles.value.some((file) => selected.value.has(file.path)));
864
+ const selectedFiles = computed(() => allFiles.value.filter((file) => selected.value.has(file.path)));
865
+ const selectedBytes = computed(() => totalSize(selectedFiles.value));
866
+ const loadedBytes = computed(() => totalSize(allFiles.value));
867
+ function clearSelection() {
868
+ selected.value = /* @__PURE__ */ new Set();
869
+ }
870
+ function folderFiles(node) {
871
+ return node.is_dir && node.loaded ? descendantFiles(node) : [];
872
+ }
873
+ /** Compact sort control for narrow containers, where header cells are hidden. */
874
+ const sortOptions = computed(() => [
875
+ "name",
876
+ "size",
877
+ "modified"
878
+ ].flatMap((key) => {
879
+ const label = t(key === "name" ? "columnName" : key === "size" ? "columnSize" : "columnDate");
880
+ return [{
881
+ value: `${key}:asc`,
882
+ label: `${label} ↑`
883
+ }, {
884
+ value: `${key}:desc`,
885
+ label: `${label} ↓`
886
+ }];
887
+ }));
888
+ const sortValue = computed({
889
+ get: () => `${sortKey.value}:${sortAsc.value ? "asc" : "desc"}`,
890
+ set: (value) => {
891
+ const [key, direction] = value.split(":");
892
+ sortKey.value = key;
893
+ sortAsc.value = direction !== "desc";
894
+ resortAll();
895
+ }
896
+ });
687
897
  function toggleCheckAll() {
688
898
  selected.value = allChecked.value ? /* @__PURE__ */ new Set() : new Set(allFiles.value.map((file) => file.path));
689
899
  }
690
- const unloadedFolders = computed(() => {
691
- let count = 0;
692
- const walk = (nodes) => {
693
- for (const node of nodes) {
694
- if (node.is_dir && !node.loaded) count += 1;
695
- if (node.children.length) walk(node.children);
696
- }
697
- };
698
- walk(roots.value);
699
- return count;
700
- });
701
900
  function triggerUrl(url) {
702
901
  const anchor = document.createElement("a");
703
902
  anchor.href = url;
@@ -789,124 +988,258 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
789
988
  loadRoot();
790
989
  }
791
990
  const displayTitle = computed(() => props.title || siteTitle.value || (props.path === "/" ? t("allFiles") : props.path));
991
+ const stickyTop = ref(0);
992
+ function measureStickyTop() {
993
+ if (typeof document === "undefined") return;
994
+ let top = 0;
995
+ for (const el of document.querySelectorAll(".VPNav, .VPLocalNav")) {
996
+ const style = getComputedStyle(el);
997
+ if (style.display === "none" || style.position !== "fixed" && style.position !== "sticky") continue;
998
+ top = Math.max(top, (Number.parseFloat(style.top) || 0) + el.offsetHeight);
999
+ }
1000
+ stickyTop.value = top;
1001
+ }
792
1002
  onMounted(() => {
793
1003
  loadRoot();
794
1004
  loadSiteTitle();
1005
+ measureStickyTop();
1006
+ window.addEventListener("resize", measureStickyTop, { passive: true });
1007
+ });
1008
+ onBeforeUnmount(() => {
1009
+ window.removeEventListener("resize", measureStickyTop);
1010
+ clearTimeout(toastTimer);
795
1011
  });
796
1012
  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", {
1013
+ return openBlock(), createElementBlock("div", {
1014
+ class: normalizeClass(["fl-root", { "fl-selecting": selected.value.size > 0 }]),
1015
+ style: normalizeStyle({ "--fl-sticky-top-auto": `${stickyTop.value}px` })
1016
+ }, [
1017
+ createElementVNode("div", _hoisted_1, [
1018
+ 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)])),
1019
+ selected.value.size ? (openBlock(), createElementBlock("button", {
1020
+ key: 2,
1021
+ class: "fl-clear",
1022
+ type: "button",
1023
+ "aria-label": t("clearSelection"),
1024
+ title: t("clearSelection"),
1025
+ onClick: clearSelection
1026
+ }, [_cache[6] || (_cache[6] = createElementVNode("svg", {
1027
+ class: "fl-clear-icon",
1028
+ viewBox: "0 0 24 24",
1029
+ width: "18",
1030
+ height: "18",
1031
+ fill: "none",
1032
+ stroke: "currentColor",
1033
+ "stroke-width": "2.2",
1034
+ "stroke-linecap": "round",
1035
+ "aria-hidden": "true"
1036
+ }, [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),
1037
+ createElementVNode("div", _hoisted_10, [createElementVNode("label", _hoisted_11, [_cache[7] || (_cache[7] = createElementVNode("svg", {
1038
+ viewBox: "0 0 24 24",
1039
+ width: "15",
1040
+ height: "15",
1041
+ fill: "none",
1042
+ stroke: "currentColor",
1043
+ "stroke-width": "2",
1044
+ "stroke-linecap": "round",
1045
+ "aria-hidden": "true"
1046
+ }, [createElementVNode("circle", {
1047
+ cx: "11",
1048
+ cy: "11",
1049
+ r: "7"
1050
+ }), createElementVNode("path", { d: "m20 20-3.5-3.5" })], -1)), withDirectives(createElementVNode("input", {
804
1051
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => keyword.value = $event),
805
- class: "fl-search",
806
1052
  type: "text",
807
- placeholder: t("filter")
808
- }, null, 8, _hoisted_7), [[vModelText, keyword.value]]),
809
- createElementVNode("button", {
810
- class: "fl-btn",
1053
+ placeholder: t("filter"),
1054
+ "aria-label": t("filter")
1055
+ }, null, 8, _hoisted_12), [[vModelText, keyword.value]])]), createElementVNode("button", {
1056
+ class: "fl-icon-btn",
811
1057
  type: "button",
1058
+ "aria-label": t("refresh"),
1059
+ title: t("refresh"),
812
1060
  onClick: loadRoot
813
- }, toDisplayString(t("refresh")), 1),
814
- createElementVNode("button", {
1061
+ }, [..._cache[8] || (_cache[8] = [createElementVNode("svg", {
1062
+ viewBox: "0 0 24 24",
1063
+ width: "15",
1064
+ height: "15",
1065
+ fill: "none",
1066
+ stroke: "currentColor",
1067
+ "stroke-width": "2",
1068
+ "stroke-linecap": "round",
1069
+ "stroke-linejoin": "round",
1070
+ "aria-hidden": "true"
1071
+ }, [createElementVNode("path", { d: "M21 12a9 9 0 1 1-3-6.7" }), createElementVNode("path", { d: "M21 4v5h-5" })], -1)])], 8, _hoisted_13)]),
1072
+ selected.value.size ? (openBlock(), createElementBlock("button", {
1073
+ key: 3,
815
1074
  class: "fl-btn fl-btn-primary",
816
1075
  type: "button",
817
- disabled: selected.value.size === 0 || batchBusy.value,
1076
+ disabled: batchBusy.value,
818
1077
  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, [
1078
+ }, [_cache[9] || (_cache[9] = createElementVNode("svg", {
1079
+ viewBox: "0 0 24 24",
1080
+ width: "15",
1081
+ height: "15",
1082
+ fill: "none",
1083
+ stroke: "currentColor",
1084
+ "stroke-width": "2.2",
1085
+ "stroke-linecap": "round",
1086
+ "stroke-linejoin": "round",
1087
+ "aria-hidden": "true"
1088
+ }, [
1089
+ createElementVNode("path", { d: "M12 3v12" }),
1090
+ createElementVNode("path", { d: "m7 10 5 5 5-5" }),
1091
+ createElementVNode("path", { d: "M5 21h14" })
1092
+ ], -1)), createTextVNode(" " + toDisplayString(batchBusy.value ? t("batching", { percent: batchProgress.value }) : t("batch")), 1)], 8, _hoisted_14)) : createCommentVNode("v-if", true)
1093
+ ]),
1094
+ needsPassword.value ? (openBlock(), createElementBlock("div", _hoisted_15, [
822
1095
  createElementVNode("span", null, toDisplayString(t("passwordPrompt")), 1),
823
1096
  withDirectives(createElementVNode("input", {
824
1097
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => passwordInput.value = $event),
825
1098
  type: "password",
826
1099
  placeholder: t("passwordPlaceholder"),
1100
+ "aria-label": t("passwordPlaceholder"),
827
1101
  onKeyup: withKeys(submitPassword, ["enter"])
828
- }, null, 40, _hoisted_10), [[vModelText, passwordInput.value]]),
1102
+ }, null, 40, _hoisted_16), [[vModelText, passwordInput.value]]),
829
1103
  createElementVNode("button", {
830
1104
  class: "fl-btn fl-btn-primary",
831
1105
  type: "button",
832
1106
  onClick: submitPassword
833
1107
  }, toDisplayString(t("open")), 1)
834
1108
  ])) : createCommentVNode("v-if", true),
835
- createElementVNode("div", _hoisted_11, [
836
- createElementVNode("span", _hoisted_12, [createElementVNode("input", {
1109
+ createElementVNode("div", _hoisted_17, [
1110
+ createElementVNode("label", _hoisted_18, [createElementVNode("input", {
837
1111
  type: "checkbox",
1112
+ "aria-label": t("selectAll"),
838
1113
  checked: allChecked.value,
839
1114
  ".indeterminate": someChecked.value,
840
1115
  onChange: toggleCheckAll
841
- }, null, 40, _hoisted_13)]),
842
- createElementVNode("span", {
843
- class: "fl-cell fl-cell-name",
1116
+ }, null, 40, _hoisted_19)]),
1117
+ createElementVNode("span", _hoisted_20, [createElementVNode("button", {
1118
+ class: "fl-sort-btn",
1119
+ type: "button",
1120
+ "aria-sort": sortKey.value === "name" ? sortAsc.value ? "ascending" : "descending" : void 0,
844
1121
  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",
1122
+ }, [createTextVNode(toDisplayString(t("columnName")), 1), createElementVNode("span", _hoisted_22, toDisplayString(sortKey.value === "name" ? sortAsc.value ? "▲" : "▼" : ""), 1)], 8, _hoisted_21)]),
1123
+ createElementVNode("span", _hoisted_23, [createElementVNode("button", {
1124
+ class: "fl-sort-btn",
1125
+ type: "button",
848
1126
  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",
1127
+ }, [createTextVNode(toDisplayString(t("columnSize")), 1), createElementVNode("span", _hoisted_24, toDisplayString(sortKey.value === "size" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
1128
+ createElementVNode("span", _hoisted_25, [createElementVNode("button", {
1129
+ class: "fl-sort-btn",
1130
+ type: "button",
852
1131
  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))
1132
+ }, [createTextVNode(toDisplayString(t("columnDate")), 1), createElementVNode("span", _hoisted_26, toDisplayString(sortKey.value === "modified" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
1133
+ createElementVNode("span", _hoisted_27, [createElementVNode("label", _hoisted_28, [
1134
+ createElementVNode("span", null, toDisplayString(t("sortBy")), 1),
1135
+ createElementVNode("span", _hoisted_29, toDisplayString(sortOptions.value.find((option) => option.value === sortValue.value)?.label), 1),
1136
+ withDirectives(createElementVNode("select", {
1137
+ "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => sortValue.value = $event),
1138
+ "aria-label": t("sortBy")
1139
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortOptions.value, (option) => {
1140
+ return openBlock(), createElementBlock("option", {
1141
+ key: option.value,
1142
+ value: option.value
1143
+ }, toDisplayString(option.label), 9, _hoisted_31);
1144
+ }), 128))], 8, _hoisted_30), [[vModelSelect, sortValue.value]])
1145
+ ])])
855
1146
  ]),
856
- loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_17, toDisplayString(t("loading")), 1)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_18, [
1147
+ loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_32, toDisplayString(t("loading")), 1)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_33, [
857
1148
  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),
1149
+ /guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_34, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
1150
+ /failed to fetch|networkerror/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_35, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
860
1151
  createElementVNode("button", {
861
1152
  class: "fl-btn",
862
1153
  type: "button",
863
1154
  onClick: loadRoot
864
1155
  }, toDisplayString(t("retry")), 1)
865
- ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_21, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
1156
+ ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_36, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
866
1157
  (openBlock(true), createElementBlock(Fragment, null, renderList(visible.value, (node) => {
867
1158
  return openBlock(), createElementBlock("div", {
868
1159
  key: node.path,
869
1160
  class: normalizeClass(["fl-row", {
870
1161
  "fl-row-dir": node.is_dir,
871
1162
  "fl-row-root": node.isRoot,
872
- "fl-row-selected": selected.value.has(node.path)
873
- }])
1163
+ "fl-row-selected": !node.is_dir && selected.value.has(node.path)
1164
+ }]),
1165
+ style: normalizeStyle({ "--fl-depth": node.depth })
874
1166
  }, [
875
- createElementVNode("span", _hoisted_22, [createElementVNode("input", {
1167
+ createElementVNode("label", _hoisted_37, [createElementVNode("input", {
876
1168
  type: "checkbox",
1169
+ "aria-label": t("selectItem", { name: node.name }),
877
1170
  checked: isChecked(node),
878
1171
  ".indeterminate": isIndeterminate(node),
879
1172
  onChange: ($event) => toggleCheck(node, $event)
880
- }, null, 40, _hoisted_23)]),
1173
+ }, null, 40, _hoisted_38)]),
881
1174
  createElementVNode("span", {
882
1175
  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", {
1176
+ title: node.isRoot ? node.path : void 0
1177
+ }, [
1178
+ _cache[12] || (_cache[12] = createElementVNode("span", {
1179
+ class: "fl-indent",
1180
+ "aria-hidden": "true"
1181
+ }, null, -1)),
1182
+ node.is_dir ? (openBlock(), createElementBlock("button", {
1183
+ key: 0,
1184
+ class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
1185
+ type: "button",
1186
+ "aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
1187
+ "aria-expanded": node.expanded,
1188
+ onClick: ($event) => toggleExpand(node)
1189
+ }, [..._cache[10] || (_cache[10] = [createElementVNode("svg", {
1190
+ viewBox: "0 0 24 24",
1191
+ width: "14",
1192
+ height: "14",
1193
+ fill: "none",
1194
+ stroke: "currentColor",
1195
+ "stroke-width": "2.4",
1196
+ "stroke-linecap": "round",
1197
+ "stroke-linejoin": "round",
1198
+ "aria-hidden": "true"
1199
+ }, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_40)) : (openBlock(), createElementBlock("span", _hoisted_41)),
1200
+ 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", {
1201
+ key: 3,
1202
+ class: "fl-type",
1203
+ "data-kind": unref(fileKind)(node.name),
1204
+ "aria-hidden": "true"
1205
+ }, toDisplayString(unref(extOf)(node.name) || "FILE"), 9, _hoisted_43)),
1206
+ createElementVNode("span", _hoisted_44, [createElementVNode("span", {
1207
+ class: normalizeClass(["fl-name", { "fl-name-dir": node.is_dir }]),
1208
+ onClick: ($event) => node.is_dir ? toggleExpand(node) : download(node)
1209
+ }, 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))])]),
1210
+ node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_47, toDisplayString(t("folderItems", { count: folderFiles(node).length })), 1)) : createCommentVNode("v-if", true),
1211
+ node.loading ? (openBlock(), createElementBlock("span", _hoisted_48, "…")) : createCommentVNode("v-if", true)
1212
+ ], 8, _hoisted_39),
1213
+ createElementVNode("span", _hoisted_49, toDisplayString(node.is_dir ? "—" : unref(formatSize)(node.size)), 1),
1214
+ createElementVNode("span", _hoisted_50, toDisplayString(unref(formatDate)(node.modified)), 1),
1215
+ createElementVNode("span", _hoisted_51, [node.is_dir ? (openBlock(), createElementBlock("button", {
886
1216
  key: 0,
887
- class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
1217
+ class: normalizeClass(["fl-action fl-arrow-end", { "fl-arrow-open": node.expanded }]),
888
1218
  type: "button",
1219
+ "aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
1220
+ "aria-expanded": node.expanded,
889
1221
  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", {
1222
+ }, [..._cache[13] || (_cache[13] = [createElementVNode("svg", {
1223
+ viewBox: "0 0 24 24",
1224
+ width: "18",
1225
+ height: "18",
1226
+ fill: "none",
1227
+ stroke: "currentColor",
1228
+ "stroke-width": "2.2",
1229
+ "stroke-linecap": "round",
1230
+ "stroke-linejoin": "round",
1231
+ "aria-hidden": "true"
1232
+ }, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_52)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
901
1233
  key: 0,
902
- class: "fl-download",
1234
+ class: "fl-action fl-download",
903
1235
  type: "button",
1236
+ "aria-label": `${t("preview")} ${node.name}`,
904
1237
  title: t("preview"),
905
1238
  onClick: ($event) => preview(node)
906
- }, [..._cache[7] || (_cache[7] = [createElementVNode("svg", {
1239
+ }, [..._cache[14] || (_cache[14] = [createElementVNode("svg", {
907
1240
  viewBox: "0 0 24 24",
908
- width: "15",
909
- height: "15",
1241
+ width: "16",
1242
+ height: "16",
910
1243
  fill: "none",
911
1244
  stroke: "currentColor",
912
1245
  "stroke-width": "2",
@@ -917,15 +1250,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
917
1250
  cx: "12",
918
1251
  cy: "12",
919
1252
  r: "3"
920
- })], -1)])], 8, _hoisted_34)) : createCommentVNode("v-if", true), createElementVNode("button", {
921
- class: "fl-download",
1253
+ })], -1)])], 8, _hoisted_53)) : createCommentVNode("v-if", true), createElementVNode("button", {
1254
+ class: "fl-action fl-download",
922
1255
  type: "button",
1256
+ "aria-label": `${t("download")} ${node.name}`,
923
1257
  title: t("download"),
924
1258
  onClick: ($event) => download(node)
925
- }, [..._cache[8] || (_cache[8] = [createElementVNode("svg", {
1259
+ }, [..._cache[15] || (_cache[15] = [createElementVNode("svg", {
926
1260
  viewBox: "0 0 24 24",
927
- width: "15",
928
- height: "15",
1261
+ width: "16",
1262
+ height: "16",
929
1263
  fill: "none",
930
1264
  stroke: "currentColor",
931
1265
  "stroke-width": "2",
@@ -936,12 +1270,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
936
1270
  createElementVNode("path", { d: "M12 3v12" }),
937
1271
  createElementVNode("path", { d: "m7 10 5 5 5-5" }),
938
1272
  createElementVNode("path", { d: "M5 21h14" })
939
- ], -1)])], 8, _hoisted_35)], 64)) : createCommentVNode("v-if", true)])
940
- ], 2);
1273
+ ], -1)])], 8, _hoisted_54)], 64))])
1274
+ ], 6);
941
1275
  }), 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
- ]);
1276
+ createElementVNode("div", _hoisted_55, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: unref(formatSize)(loadedBytes.value) })), 1)]),
1277
+ toast.value ? (openBlock(), createElementBlock("div", _hoisted_56, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true)
1278
+ ], 6);
945
1279
  };
946
1280
  }
947
1281
  });
@@ -966,4 +1300,4 @@ function enhanceAppWithFileList({ app }) {
966
1300
  if (!app._context.components.FileList) app.component("FileList", _sfc_main);
967
1301
  if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
968
1302
  }
969
- export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, uniqueEntryName, zipEntryName, zipSegment };
1303
+ export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileKind, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, totalSize, uniqueEntryName, zipEntryName, zipSegment };