vitepress-plugin-filelist 0.7.2 → 0.9.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.
@@ -353,6 +353,56 @@ function createOpenListApi(base, token) {
353
353
  }
354
354
  };
355
355
  }
356
+ // src/client/demoSamples.ts
357
+ const SAMPLE_FOLDER = "/示例文件";
358
+ const SAMPLES = {
359
+ "使用说明.md": {
360
+ type: "text/markdown",
361
+ body: "# 使用说明\n\n这是 **vitepress-plugin-filelist** 演示数据自带的 Markdown 文件。\n\n## 试一试\n\n- 点右上角“渲染”,按 VitePress 正文样式显示\n- 用 ← / → 切换到同一目录里的其它文件\n- 勾选“示例文件”文件夹,点“下载 ZIP”打包\n\n| 文件 | 类型 |\n| --- | --- |\n| 讲义.pdf | PDF |\n| 课程海报.svg | 图片 |\n| 网页示例.html | 网页 |\n\n> 接入 OpenList 后,这里显示的就是网盘里的真实文件。\n\n更多说明见 [文档站](https://nrjycyd.github.io/vitepress-plugin-filelist/)。\n"
362
+ },
363
+ "网页示例.html": {
364
+ type: "text/html",
365
+ body: "<!doctype html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"utf-8\">\n<title>网页示例</title>\n<style>\n body { font-family: system-ui, sans-serif; margin: 24px; line-height: 1.6; color: #1f2937; }\n h1 { color: #3451b2; }\n .card { padding: 12px 16px; border: 1px solid #d1d5db; border-radius: 8px; }\n</style>\n</head>\n<body>\n<h1>网页示例</h1>\n<p>切换到“渲染”后,这个网页在沙盒中显示:带样式,但脚本不会运行。</p>\n<div class=\"card\">下面的按钮由脚本控制,在沙盒里点了没有反应。</div>\n<p><button onclick=\"alert('脚本运行了')\">点我</button></p>\n<script>document.body.dataset.ran = 'yes'<\/script>\n</body>\n</html>\n"
366
+ },
367
+ "课程海报.svg": {
368
+ type: "image/svg+xml",
369
+ body: "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"800\" height=\"450\" viewBox=\"0 0 800 450\">\n<defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"#3451b2\"/><stop offset=\"1\" stop-color=\"#5672cd\"/></linearGradient></defs>\n<rect width=\"800\" height=\"450\" fill=\"url(#g)\"/>\n<circle cx=\"660\" cy=\"90\" r=\"120\" fill=\"#ffffff\" opacity=\"0.08\"/>\n<circle cx=\"120\" cy=\"420\" r=\"160\" fill=\"#ffffff\" opacity=\"0.06\"/>\n<text x=\"64\" y=\"190\" font-family=\"system-ui, sans-serif\" font-size=\"56\" font-weight=\"700\" fill=\"#ffffff\">课程海报</text>\n<text x=\"64\" y=\"250\" font-family=\"system-ui, sans-serif\" font-size=\"26\" fill=\"#dfe5ff\">线性代数 · 2026 秋季学期</text>\n<text x=\"64\" y=\"380\" font-family=\"system-ui, sans-serif\" font-size=\"18\" fill=\"#dfe5ff\">vitepress-plugin-filelist 演示图片</text>\n</svg>\n"
370
+ },
371
+ "讲义.pdf": {
372
+ type: "application/pdf",
373
+ body: "%PDF-1.4\n1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n5 0 obj\n<< /Length 257 >>\nstream\nBT\n/F1 20 Tf\n72 760 Td\n(FileList sample PDF) Tj\n/F1 12 Tf\n0 -22 Td\n() Tj\n0 -22 Td\n(This small PDF ships with the demo data of) Tj\n0 -22 Td\n(vitepress-plugin-filelist, so preview, download) Tj\n0 -22 Td\n(and ZIP can be tried without an OpenList server.) Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 n \n0000000058 00000 n \n0000000115 00000 n \n0000000241 00000 n \n0000000311 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n619\n%%EOF\n"
374
+ },
375
+ "课程表.txt": {
376
+ type: "text/plain",
377
+ body: "课程表(演示文本)\n\n周一 08:00 线性代数 教 301\n周三 10:00 线性代数习题课 教 205\n周五 14:00 答疑 图书馆 2 楼\n\n纯文本文件只读取前 1 MB,按原样显示。\n"
378
+ }
379
+ };
380
+ const SAMPLE_NAMES = Object.keys(SAMPLES);
381
+ /** Size in bytes of a sample, as UTF-8. */
382
+ function sampleSize(name) {
383
+ return new TextEncoder().encode(SAMPLES[name].body).byteLength;
384
+ }
385
+ function nameOf(path) {
386
+ const name = path.slice(6);
387
+ return path.startsWith(`/示例文件/`) && name in SAMPLES ? name : void 0;
388
+ }
389
+ /** Whether a demo path is one of the sample files (which have a real URL). */
390
+ function isSample(path) {
391
+ return nameOf(path) !== void 0;
392
+ }
393
+ const urls = /* @__PURE__ */ new Map();
394
+ /** A blob: URL for a sample file, `''` for any other path or outside a browser. */
395
+ function sampleUrl(path) {
396
+ const name = nameOf(path);
397
+ if (!name || typeof URL.createObjectURL !== "function") return "";
398
+ let url = urls.get(name);
399
+ if (!url) {
400
+ const { type, body } = SAMPLES[name];
401
+ url = URL.createObjectURL(new Blob([body], { type: `${type};charset=utf-8` }));
402
+ urls.set(name, url);
403
+ }
404
+ return url;
405
+ }
356
406
  // src/client/demo.ts
357
407
  /** Built-in sample data, used when no `base` is given. */
358
408
  const TREE = {
@@ -392,8 +442,32 @@ const TREE = {
392
442
  size: 0,
393
443
  is_dir: true,
394
444
  modified: "2026-10-20T18:00:00+08:00"
445
+ },
446
+ {
447
+ name: "示例文件",
448
+ size: 0,
449
+ is_dir: true,
450
+ modified: "2026-11-11T09:00:00+08:00"
451
+ },
452
+ {
453
+ name: "照片(260 张)",
454
+ size: 0,
455
+ is_dir: true,
456
+ modified: "2026-10-01T12:00:00+08:00"
395
457
  }
396
458
  ],
459
+ [SAMPLE_FOLDER]: SAMPLE_NAMES.map((name) => ({
460
+ name,
461
+ size: sampleSize(name),
462
+ is_dir: false,
463
+ modified: "2026-11-11T09:00:00+08:00"
464
+ })),
465
+ "/照片(260 张)": Array.from({ length: 260 }, (_, index) => ({
466
+ name: `IMG_${String(index + 1).padStart(4, "0")}.jpg`,
467
+ size: 2e6 + index * 7919 % 15e5,
468
+ is_dir: false,
469
+ modified: "2026-10-01T12:00:00+08:00"
470
+ })),
397
471
  "/assignments": [{
398
472
  name: "线代作业参考答案",
399
473
  size: 0,
@@ -514,7 +588,7 @@ function guard(path, password) {
514
588
  function parentOf(path) {
515
589
  return path.slice(0, path.lastIndexOf("/")) || "/";
516
590
  }
517
- /** Demo OpenList: same API, no network; files have no URL. */
591
+ /** Demo OpenList: same API, no network; only the sample files have a URL. */
518
592
  function createDemoApi(delay = 220) {
519
593
  return {
520
594
  async list(path, password) {
@@ -533,12 +607,46 @@ function createDemoApi(delay = 220) {
533
607
  title: "",
534
608
  iframePreviews: ""
535
609
  }),
536
- fileUrl: async () => "",
610
+ fileUrl: async (file) => sampleUrl(file.path),
537
611
  directUrl: () => "",
538
- isAttachmentUrl: () => false,
612
+ isAttachmentUrl: (url) => url.startsWith("blob:"),
539
613
  clearCache: () => {}
540
614
  };
541
615
  }
616
+ /** Whether a demo file can really be previewed, downloaded and zipped. */
617
+ const isDemoFile = isSample;
618
+ // src/client/devWarnings.ts
619
+ const SECURITY_DOC = "https://nrjycyd.github.io/vitepress-plugin-filelist/guide/security";
620
+ /** Props a page wrote that end up, readable by anyone, in the built site. */
621
+ function publicSecrets(props) {
622
+ const found = [];
623
+ if (props.token) found.push("token");
624
+ if (props.password || props.sources?.some((source) => source.password)) found.push("password");
625
+ return found;
626
+ }
627
+ /**
628
+ * Development builds only. The site's Vite replaces `import.meta.env` in
629
+ * dependencies too (`DEV` is true under `vitepress dev`, false in a build);
630
+ * without a bundler there is no `env` and this is not a development build.
631
+ */
632
+ function isDevBuild() {
633
+ return import.meta.env?.DEV === true;
634
+ }
635
+ let warned = false;
636
+ /**
637
+ * While the site runs in development, say once per page load that `token` and
638
+ * `password` written in Markdown are public. Production builds stay silent.
639
+ * Returns whether it warned.
640
+ */
641
+ function warnPublicSecrets(props, locale, dev = isDevBuild()) {
642
+ if (warned || !dev) return false;
643
+ const found = publicSecrets(props);
644
+ if (!found.length) return false;
645
+ warned = true;
646
+ const names = found.join(" / ");
647
+ console.warn(locale === "en-US" ? `[vitepress-plugin-filelist] This page sets ${names} on <FileList>. It is copied as is into the built site, where every visitor can read it. Prefer a guest account limited to a base path. ${SECURITY_DOC} (shown in development only)` : `[vitepress-plugin-filelist] 本页的 <FileList> 写了 ${names}:它会原样进入构建后的网页,所有访客都能看到。建议改用限定基础路径的 guest 账户。${SECURITY_DOC}(仅开发时提示)`);
648
+ return true;
649
+ }
542
650
  // src/client/ConfirmDialog.vue
543
651
  const _hoisted_1$3 = ["aria-label"];
544
652
  const _hoisted_2$3 = {
@@ -801,6 +909,14 @@ const ICONS = {
801
909
  stroke: 2.2,
802
910
  paths: ["m15 6-6 6 6 6"]
803
911
  },
912
+ down: {
913
+ stroke: 2.4,
914
+ paths: ["m6 9 6 6 6-6"]
915
+ },
916
+ up: {
917
+ stroke: 2.4,
918
+ paths: ["m18 15-6-6-6 6"]
919
+ },
804
920
  zoomIn: {
805
921
  stroke: 2,
806
922
  paths: [
@@ -860,7 +976,6 @@ const fileListLocales = {
860
976
  filter: "筛选文件名",
861
977
  refresh: "刷新",
862
978
  batch: "下载 ZIP",
863
- batchCount: "批量下载({count})",
864
979
  batching: "打包中 {percent}%",
865
980
  passwordPrompt: "该目录受密码保护:",
866
981
  passwordPlaceholder: "输入密码",
@@ -878,13 +993,11 @@ const fileListLocales = {
878
993
  download: "下载",
879
994
  loaded: "{count} 个已加载文件",
880
995
  selected: "已选 {count} 项",
881
- unloaded: "{count} 个目录未展开,未计入全选",
882
996
  folderFailed: "打开文件夹失败:{message}",
883
997
  demoDownload: "演示模式:接入 OpenList 后会下载「{name}」",
884
998
  demoPreview: "演示模式:接入 OpenList 后可预览「{name}」",
885
999
  demoBatch: "演示模式:将打包已勾选的 {count} 个文件",
886
1000
  downloadFailed: "下载失败:{message}",
887
- previewFailed: "预览失败:{message}",
888
1001
  batchFailed: "打包失败:{message}",
889
1002
  defaultZip: "资源",
890
1003
  clear: "清除",
@@ -915,7 +1028,6 @@ const fileListLocales = {
915
1028
  remembered: "已记住",
916
1029
  forgetPassword: "忘记",
917
1030
  unlockFolder: "输入 {name} 的密码",
918
- networkHint: "可能被跨域拦截:请检查 OpenList 的 cors.allow_origins,或 OpenList-Worker 的 ALLOW_URLS。",
919
1031
  deepHint: "只筛选了已加载的内容,",
920
1032
  deepSearch: "尝试深度搜索",
921
1033
  deepRunning: "正在深度搜索 · 已查找 {count} 个文件夹",
@@ -946,9 +1058,14 @@ const fileListLocales = {
946
1058
  zipBlockText: "当前浏览器一次最多打包 {limit},请分批勾选下载。",
947
1059
  gotIt: "知道了",
948
1060
  moreRemaining: "还有 {count} 项",
949
- showMore: "显示更多",
950
1061
  showAll: "全部显示",
951
- showRest: "显示剩余 {count} 项"
1062
+ showRest: "显示剩余 {count} 项",
1063
+ showLess: "收起",
1064
+ allShown: "已显示全部 {count} 项",
1065
+ moreShown: "已显示 {shown} / {total} 项",
1066
+ showAllShort: "全部",
1067
+ showNext: "再显示 {count} 项",
1068
+ showNextShort: "+{count}"
952
1069
  },
953
1070
  "en-US": {
954
1071
  allFiles: "All files",
@@ -956,7 +1073,6 @@ const fileListLocales = {
956
1073
  filter: "Filter files",
957
1074
  refresh: "Refresh",
958
1075
  batch: "Download ZIP",
959
- batchCount: "Download ZIP ({count})",
960
1076
  batching: "Zipping {percent}%",
961
1077
  passwordPrompt: "This folder is password protected:",
962
1078
  passwordPlaceholder: "Folder password",
@@ -974,13 +1090,11 @@ const fileListLocales = {
974
1090
  download: "Download",
975
1091
  loaded: "{count} loaded file(s)",
976
1092
  selected: "{count} selected",
977
- unloaded: "{count} folder(s) not expanded, excluded from select-all",
978
1093
  folderFailed: "Failed to open folder: {message}",
979
1094
  demoDownload: "Demo mode: \"{name}\" will download once OpenList is connected.",
980
1095
  demoPreview: "Demo mode: \"{name}\" will preview once OpenList is connected.",
981
1096
  demoBatch: "Demo mode: {count} selected file(s) would be zipped.",
982
1097
  downloadFailed: "Download failed: {message}",
983
- previewFailed: "Preview failed: {message}",
984
1098
  batchFailed: "Failed to create ZIP: {message}",
985
1099
  defaultZip: "resources",
986
1100
  clear: "Clear",
@@ -1011,7 +1125,6 @@ const fileListLocales = {
1011
1125
  remembered: "Remembered",
1012
1126
  forgetPassword: "Forget",
1013
1127
  unlockFolder: "Enter the password for {name}",
1014
- networkHint: "Possibly blocked by CORS: check cors.allow_origins in OpenList, or ALLOW_URLS in OpenList-Worker.",
1015
1128
  deepHint: "Only loaded folders are filtered. ",
1016
1129
  deepSearch: "Try deep search",
1017
1130
  deepRunning: "Searching · {count} folders checked",
@@ -1042,9 +1155,14 @@ const fileListLocales = {
1042
1155
  zipBlockText: "This browser can zip at most {limit} at once. Select fewer files.",
1043
1156
  gotIt: "OK",
1044
1157
  moreRemaining: "{count} more",
1045
- showMore: "Show more",
1046
1158
  showAll: "Show all",
1047
- showRest: "Show the remaining {count}"
1159
+ showRest: "Show the remaining {count}",
1160
+ showLess: "Show less",
1161
+ allShown: "All {count} shown",
1162
+ moreShown: "Showing {shown} of {total}",
1163
+ showAllShort: "All",
1164
+ showNext: "Show {count} more",
1165
+ showNextShort: "+{count}"
1048
1166
  }
1049
1167
  };
1050
1168
  function formatLabel(template, values = {}) {
@@ -1813,73 +1931,97 @@ const _hoisted_27 = {
1813
1931
  };
1814
1932
  const _hoisted_28 = ["aria-label"];
1815
1933
  const _hoisted_29 = ["value"];
1816
- const _hoisted_30 = {
1934
+ const _hoisted_30 = { class: "fl-cell fl-cell-name" };
1935
+ const _hoisted_31 = {
1936
+ key: 0,
1937
+ class: "fl-indent",
1938
+ "aria-hidden": "true"
1939
+ };
1940
+ const _hoisted_32 = {
1941
+ key: 1,
1942
+ class: "fl-pin-arrow",
1943
+ "aria-hidden": "true"
1944
+ };
1945
+ const _hoisted_33 = { class: "fl-pin-name" };
1946
+ const _hoisted_34 = { class: "fl-pin-count" };
1947
+ const _hoisted_35 = {
1817
1948
  key: 0,
1818
1949
  class: "fl-status"
1819
1950
  };
1820
- const _hoisted_31 = ["for"];
1821
- const _hoisted_32 = ["id"];
1822
- const _hoisted_33 = { class: "fl-unlock" };
1823
- const _hoisted_34 = [
1951
+ const _hoisted_36 = ["for"];
1952
+ const _hoisted_37 = ["id"];
1953
+ const _hoisted_38 = { class: "fl-unlock" };
1954
+ const _hoisted_39 = [
1824
1955
  "id",
1825
1956
  "data-unlock",
1826
1957
  "placeholder",
1827
1958
  "aria-invalid",
1828
1959
  "aria-describedby"
1829
1960
  ];
1830
- const _hoisted_35 = [
1961
+ const _hoisted_40 = [
1831
1962
  "aria-pressed",
1832
1963
  "aria-label",
1833
1964
  "title"
1834
1965
  ];
1835
- const _hoisted_36 = ["disabled"];
1836
- const _hoisted_37 = {
1966
+ const _hoisted_41 = ["disabled"];
1967
+ const _hoisted_42 = {
1837
1968
  key: 2,
1838
1969
  class: "fl-status fl-error"
1839
1970
  };
1840
- const _hoisted_38 = {
1971
+ const _hoisted_43 = {
1841
1972
  key: 0,
1842
1973
  class: "fl-hint"
1843
1974
  };
1844
- const _hoisted_39 = {
1975
+ const _hoisted_44 = {
1845
1976
  key: 1,
1846
1977
  class: "fl-hint"
1847
1978
  };
1848
- const _hoisted_40 = {
1979
+ const _hoisted_45 = {
1849
1980
  key: 3,
1850
1981
  class: "fl-status"
1851
1982
  };
1852
- const _hoisted_41 = { class: "fl-cell fl-more-cell" };
1853
- const _hoisted_42 = { class: "fl-more-count" };
1854
- const _hoisted_43 = ["onClick"];
1855
- const _hoisted_44 = { class: "fl-more-page" };
1856
- const _hoisted_45 = ["onClick"];
1857
- const _hoisted_46 = ["onClick"];
1858
- const _hoisted_47 = { class: "fl-cell fl-cell-check" };
1859
- const _hoisted_48 = [
1983
+ const _hoisted_46 = { class: "fl-cell fl-more-cell" };
1984
+ const _hoisted_47 = { class: "fl-more-count" };
1985
+ const _hoisted_48 = { class: "fl-more-actions" };
1986
+ const _hoisted_49 = ["aria-label", "onClick"];
1987
+ const _hoisted_50 = { class: "fl-more-long" };
1988
+ const _hoisted_51 = {
1989
+ class: "fl-more-short",
1990
+ "aria-hidden": "true"
1991
+ };
1992
+ const _hoisted_52 = ["aria-label", "onClick"];
1993
+ const _hoisted_53 = { class: "fl-more-long" };
1994
+ const _hoisted_54 = {
1995
+ class: "fl-more-short",
1996
+ "aria-hidden": "true"
1997
+ };
1998
+ const _hoisted_55 = ["onClick"];
1999
+ const _hoisted_56 = ["data-path"];
2000
+ const _hoisted_57 = { class: "fl-cell fl-cell-check" };
2001
+ const _hoisted_58 = [
1860
2002
  "disabled",
1861
2003
  "aria-label",
1862
2004
  "checked",
1863
2005
  ".indeterminate",
1864
2006
  "onChange"
1865
2007
  ];
1866
- const _hoisted_49 = ["title"];
1867
- const _hoisted_50 = [
2008
+ const _hoisted_59 = ["title"];
2009
+ const _hoisted_60 = [
1868
2010
  "aria-label",
1869
2011
  "title",
1870
2012
  "onClick"
1871
2013
  ];
1872
- const _hoisted_51 = [
2014
+ const _hoisted_61 = [
1873
2015
  "aria-label",
1874
2016
  "aria-expanded",
1875
2017
  "onClick"
1876
2018
  ];
1877
- const _hoisted_52 = {
2019
+ const _hoisted_62 = {
1878
2020
  key: 2,
1879
2021
  class: "fl-arrow-placeholder",
1880
2022
  "aria-hidden": "true"
1881
2023
  };
1882
- const _hoisted_53 = {
2024
+ const _hoisted_63 = {
1883
2025
  key: 3,
1884
2026
  class: "fl-folder-icon",
1885
2027
  viewBox: "0 0 24 24",
@@ -1887,39 +2029,39 @@ const _hoisted_53 = {
1887
2029
  height: "18",
1888
2030
  "aria-hidden": "true"
1889
2031
  };
1890
- const _hoisted_54 = ["data-kind"];
1891
- const _hoisted_55 = { class: "fl-label" };
1892
- const _hoisted_56 = ["onClick"];
1893
- const _hoisted_57 = {
2032
+ const _hoisted_64 = ["data-kind"];
2033
+ const _hoisted_65 = { class: "fl-label" };
2034
+ const _hoisted_66 = ["onClick"];
2035
+ const _hoisted_67 = {
1894
2036
  key: 0,
1895
2037
  class: "fl-hit"
1896
2038
  };
1897
- const _hoisted_58 = { class: "fl-meta" };
1898
- const _hoisted_59 = {
2039
+ const _hoisted_68 = { class: "fl-meta" };
2040
+ const _hoisted_69 = {
1899
2041
  key: 2,
1900
2042
  class: "fl-locked-note"
1901
2043
  };
1902
- const _hoisted_60 = {
2044
+ const _hoisted_70 = {
1903
2045
  key: 5,
1904
2046
  class: "fl-locked-note fl-locked-hint"
1905
2047
  };
1906
- const _hoisted_61 = {
2048
+ const _hoisted_71 = {
1907
2049
  key: 6,
1908
2050
  class: "fl-count"
1909
2051
  };
1910
- const _hoisted_62 = ["id"];
1911
- const _hoisted_63 = [
2052
+ const _hoisted_72 = ["id"];
2053
+ const _hoisted_73 = [
1912
2054
  "aria-label",
1913
2055
  "title",
1914
2056
  "onClick"
1915
2057
  ];
1916
- const _hoisted_64 = {
2058
+ const _hoisted_74 = {
1917
2059
  key: 9,
1918
2060
  class: "fl-loading",
1919
2061
  "aria-hidden": "true"
1920
2062
  };
1921
- const _hoisted_65 = ["onSubmit", "onKeydown"];
1922
- const _hoisted_66 = [
2063
+ const _hoisted_75 = ["onSubmit", "onKeydown"];
2064
+ const _hoisted_76 = [
1923
2065
  "onUpdate:modelValue",
1924
2066
  "data-unlock",
1925
2067
  "placeholder",
@@ -1927,50 +2069,50 @@ const _hoisted_66 = [
1927
2069
  "aria-invalid",
1928
2070
  "aria-describedby"
1929
2071
  ];
1930
- const _hoisted_67 = [
2072
+ const _hoisted_77 = [
1931
2073
  "aria-pressed",
1932
2074
  "aria-label",
1933
2075
  "title",
1934
2076
  "onClick"
1935
2077
  ];
1936
- const _hoisted_68 = ["disabled"];
1937
- const _hoisted_69 = [
2078
+ const _hoisted_78 = ["disabled"];
2079
+ const _hoisted_79 = [
1938
2080
  "aria-label",
1939
2081
  "title",
1940
2082
  "onClick"
1941
2083
  ];
1942
- const _hoisted_70 = { class: "fl-cell fl-cell-size" };
1943
- const _hoisted_71 = { class: "fl-cell fl-cell-date" };
1944
- const _hoisted_72 = { class: "fl-cell fl-cell-op" };
1945
- const _hoisted_73 = ["aria-label", "onClick"];
1946
- const _hoisted_74 = [
2084
+ const _hoisted_80 = { class: "fl-cell fl-cell-size" };
2085
+ const _hoisted_81 = { class: "fl-cell fl-cell-date" };
2086
+ const _hoisted_82 = { class: "fl-cell fl-cell-op" };
2087
+ const _hoisted_83 = ["aria-label", "onClick"];
2088
+ const _hoisted_84 = [
1947
2089
  "aria-label",
1948
2090
  "aria-expanded",
1949
2091
  "onClick"
1950
2092
  ];
1951
- const _hoisted_75 = [
2093
+ const _hoisted_85 = [
1952
2094
  "aria-label",
1953
2095
  "title",
1954
2096
  "onClick"
1955
2097
  ];
1956
- const _hoisted_76 = [
2098
+ const _hoisted_86 = [
1957
2099
  "aria-label",
1958
2100
  "title",
1959
2101
  "onClick"
1960
2102
  ];
1961
- const _hoisted_77 = {
2103
+ const _hoisted_87 = {
1962
2104
  key: 4,
1963
2105
  class: "fl-deep",
1964
2106
  role: "status"
1965
2107
  };
1966
- const _hoisted_78 = { class: "fl-deep-text" };
1967
- const _hoisted_79 = {
2108
+ const _hoisted_88 = { class: "fl-deep-text" };
2109
+ const _hoisted_89 = {
1968
2110
  key: 0,
1969
2111
  class: "fl-deep-bar",
1970
2112
  "aria-hidden": "true"
1971
2113
  };
1972
- const _hoisted_80 = { class: "fl-foot" };
1973
- const _hoisted_81 = {
2114
+ const _hoisted_90 = { class: "fl-foot" };
2115
+ const _hoisted_91 = {
1974
2116
  key: 5,
1975
2117
  class: "fl-toast",
1976
2118
  role: "status"
@@ -1994,7 +2136,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
1994
2136
  type: Boolean,
1995
2137
  default: true
1996
2138
  },
1997
- pageSize: { default: 200 },
2139
+ pageSize: { default: 15 },
1998
2140
  deepSearchLimit: { default: 500 },
1999
2141
  deepSearch: { default: "manual" },
2000
2142
  zipWarnSize: {},
@@ -2341,6 +2483,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2341
2483
  if (!node.is_dir) return;
2342
2484
  if (node.expanded) {
2343
2485
  node.expanded = false;
2486
+ for (const key of [...shown.keys()]) if (isWithin(key, node.path)) shown.delete(key);
2344
2487
  return;
2345
2488
  }
2346
2489
  node.expanded = await loadChildren(node, "focus");
@@ -2376,22 +2519,37 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2376
2519
  applySort(key, direction !== "desc");
2377
2520
  }
2378
2521
  });
2379
- /** A “show more” row closing a folder whose children are cut at `pageSize`. */
2522
+ /** The row closing a long folder while its children are cut at `pageSize`. */
2380
2523
  const shown = reactive(/* @__PURE__ */ new Map());
2524
+ function pageSizeOf() {
2525
+ return Math.max(0, Math.floor(props.pageSize ?? 15));
2526
+ }
2381
2527
  function limitOf(key) {
2382
- const size = Math.max(0, Math.floor(props.pageSize ?? 200));
2528
+ const size = pageSizeOf();
2383
2529
  return size ? shown.get(key) ?? size : Number.POSITIVE_INFINITY;
2384
2530
  }
2385
2531
  function showMore(row, all) {
2386
- const size = Math.max(1, Math.floor(props.pageSize ?? 200));
2532
+ const size = Math.max(1, pageSizeOf());
2387
2533
  shown.set(row.key, all ? Number.POSITIVE_INFINITY : limitOf(row.key) + size);
2388
2534
  }
2535
+ /** Back to the first page; the folder's row (or the list's top) comes back into view. */
2536
+ async function showLess(key) {
2537
+ shown.delete(key);
2538
+ pinned.value = null;
2539
+ await nextTick();
2540
+ const root = rootEl.value;
2541
+ if (!root) return;
2542
+ const target = rowElement(key) ?? root;
2543
+ if (target.getBoundingClientRect().top < stickyTop.value) target.scrollIntoView({ block: "start" });
2544
+ }
2389
2545
  function isMore(row) {
2390
2546
  return "more" in row;
2391
2547
  }
2392
- const rows = computed(() => {
2548
+ const layout = computed(() => {
2393
2549
  const out = [];
2550
+ const long = [];
2394
2551
  const query = keyword.value.trim().toLowerCase();
2552
+ const size = pageSizeOf();
2395
2553
  const matches = (node) => !query || node.name.toLowerCase().includes(query) || node.is_dir && (node.children.some(matches) || deepMode.value && !!node.lock);
2396
2554
  const walk = (nodes, key, depth) => {
2397
2555
  const list = nodes.filter(matches);
@@ -2406,10 +2564,70 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2406
2564
  depth,
2407
2565
  remaining: list.length - limit
2408
2566
  });
2567
+ let end = out.length - 1;
2568
+ while (end >= 0 && isMore(out[end])) end -= 1;
2569
+ const last = out[end];
2570
+ if (!query && size > 0 && limit > size && last && !isMore(last)) long.push({
2571
+ key,
2572
+ depth: depth - 1,
2573
+ shown: limit,
2574
+ total: list.length,
2575
+ last: last.path
2576
+ });
2409
2577
  };
2410
2578
  walk(roots.value, props.sources.length ? "" : props.path, 0);
2411
- return out;
2579
+ return {
2580
+ rows: out,
2581
+ long
2582
+ };
2412
2583
  });
2584
+ const rows = computed(() => layout.value.rows);
2585
+ const pinned = ref(null);
2586
+ /** Height of the sticky selection bar above the pinned row (narrow lists only). */
2587
+ const pinOffset = ref(0);
2588
+ function rowElement(path) {
2589
+ return [...rootEl.value?.querySelectorAll("[data-path]") ?? []].find((el) => el.dataset.path === path);
2590
+ }
2591
+ /** The pinned folder's name: its own, or for a single path's top level, the list's title. */
2592
+ const pinnedName = computed(() => {
2593
+ const folder = pinned.value;
2594
+ if (!folder) return "";
2595
+ if (folder.depth < 0) return props.title || folder.key.split("/").filter(Boolean).pop() || "/";
2596
+ const find = (nodes) => {
2597
+ for (const node of nodes) {
2598
+ if (node.path === folder.key) return node;
2599
+ const inner = isWithin(folder.key, node.path) ? find(node.children) : void 0;
2600
+ if (inner) return inner;
2601
+ }
2602
+ };
2603
+ return find(roots.value)?.name ?? "";
2604
+ });
2605
+ /** Pin the innermost long folder whose own row has scrolled away while its files are still on screen. */
2606
+ function updatePin() {
2607
+ const root = rootEl.value;
2608
+ if (!root) return;
2609
+ const bar = root.querySelector(".fl-bar");
2610
+ pinOffset.value = bar && getComputedStyle(bar).position === "sticky" ? bar.offsetHeight : 0;
2611
+ const top = stickyTop.value + pinOffset.value;
2612
+ const rowHeight = root.querySelector(".fl-head")?.offsetHeight ?? 40;
2613
+ let found = null;
2614
+ for (const folder of layout.value.long) {
2615
+ const head = folder.depth < 0 ? root.querySelector(".fl-head") : rowElement(folder.key);
2616
+ const last = rowElement(folder.last);
2617
+ if (!head || !last) continue;
2618
+ if (head.getBoundingClientRect().bottom <= top && last.getBoundingClientRect().bottom > top + rowHeight && (!found || folder.depth > found.depth)) found = folder;
2619
+ }
2620
+ pinned.value = found;
2621
+ }
2622
+ let pinFrame = 0;
2623
+ function schedulePin() {
2624
+ if (pinFrame) return;
2625
+ pinFrame = requestAnimationFrame(() => {
2626
+ pinFrame = 0;
2627
+ updatePin();
2628
+ });
2629
+ }
2630
+ watch(layout, () => void nextTick(schedulePin));
2413
2631
  const visible = computed(() => rows.value.filter((row) => !isMore(row)));
2414
2632
  /** A name split around the filter keyword, for highlighting. */
2415
2633
  function nameParts(name) {
@@ -2653,7 +2871,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2653
2871
  }
2654
2872
  async function download(node) {
2655
2873
  if (node.is_dir) return;
2656
- if (demo.value) {
2874
+ if (demo.value && !isDemoFile(node.path)) {
2657
2875
  showToast(t("demoDownload", { name: node.name }));
2658
2876
  return;
2659
2877
  }
@@ -2711,7 +2929,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2711
2929
  async function batchDownload() {
2712
2930
  const files = selectedFiles.value;
2713
2931
  if (!files.length || batchBusy.value) return;
2714
- if (demo.value) {
2932
+ if (demo.value && !files.every((file) => isDemoFile(file.path))) {
2715
2933
  showToast(t("demoBatch", { count: files.length }));
2716
2934
  return;
2717
2935
  }
@@ -2809,7 +3027,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2809
3027
  previewViewer.value = "";
2810
3028
  previewError.value = "";
2811
3029
  previewResolving.value = false;
2812
- if (demo.value || !canPreview(node)) return;
3030
+ if (demo.value && !isDemoFile(node.path) || !canPreview(node)) return;
2813
3031
  previewResolving.value = true;
2814
3032
  try {
2815
3033
  const url = await fileUrlOf(node);
@@ -2853,15 +3071,21 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2853
3071
  stickyTop.value = top;
2854
3072
  }
2855
3073
  onMounted(() => {
3074
+ warnPublicSecrets(props, props.locale);
2856
3075
  passwords.sync();
2857
3076
  loadRoot();
2858
3077
  loadSettings();
2859
3078
  measureStickyTop();
2860
3079
  window.addEventListener("resize", measureStickyTop, { passive: true });
3080
+ window.addEventListener("scroll", schedulePin, { passive: true });
3081
+ window.addEventListener("resize", schedulePin, { passive: true });
2861
3082
  });
2862
3083
  onBeforeUnmount(() => {
2863
3084
  zipAbort?.abort();
2864
3085
  window.removeEventListener("resize", measureStickyTop);
3086
+ window.removeEventListener("scroll", schedulePin);
3087
+ window.removeEventListener("resize", schedulePin);
3088
+ cancelAnimationFrame(pinFrame);
2865
3089
  clearTimeout(toastTimer);
2866
3090
  });
2867
3091
  return (_ctx, _cache) => {
@@ -2990,7 +3214,45 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
2990
3214
  }), 128))], 8, _hoisted_28), [[vModelSelect, sortValue.value]])
2991
3215
  ])])
2992
3216
  ]),
2993
- loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_30, toDisplayString(t("loading")), 1)) : rootLock.value ? (openBlock(), createElementBlock("form", {
3217
+ createCommentVNode(" While scrolling through a long folder, its row stays at the top with “show less”. "),
3218
+ createElementVNode("div", {
3219
+ class: "fl-pin-anchor",
3220
+ style: normalizeStyle({ "--fl-pin-offset": `${pinOffset.value}px` })
3221
+ }, [pinned.value ? (openBlock(), createElementBlock("div", {
3222
+ key: 0,
3223
+ class: "fl-pin",
3224
+ style: normalizeStyle({ "--fl-depth": Math.max(pinned.value.depth, 0) })
3225
+ }, [
3226
+ _cache[11] || (_cache[11] = createElementVNode("span", { class: "fl-cell fl-cell-check" }, null, -1)),
3227
+ createElementVNode("span", _hoisted_30, [
3228
+ pinned.value.depth >= 0 ? (openBlock(), createElementBlock("span", _hoisted_31)) : createCommentVNode("v-if", true),
3229
+ pinned.value.depth >= 0 ? (openBlock(), createElementBlock("span", _hoisted_32, [createVNode(_sfc_main$2, {
3230
+ name: "next",
3231
+ size: 14
3232
+ })])) : createCommentVNode("v-if", true),
3233
+ _cache[10] || (_cache[10] = createElementVNode("svg", {
3234
+ class: "fl-folder-icon",
3235
+ viewBox: "0 0 24 24",
3236
+ width: "18",
3237
+ height: "18",
3238
+ "aria-hidden": "true"
3239
+ }, [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" })], -1)),
3240
+ createElementVNode("span", _hoisted_33, toDisplayString(pinnedName.value), 1),
3241
+ createElementVNode("span", _hoisted_34, toDisplayString(pinned.value.shown < pinned.value.total ? t("moreShown", {
3242
+ shown: pinned.value.shown,
3243
+ total: pinned.value.total
3244
+ }) : t("allShown", { count: pinned.value.total })), 1)
3245
+ ]),
3246
+ createElementVNode("button", {
3247
+ class: "fl-pin-less",
3248
+ type: "button",
3249
+ onClick: _cache[3] || (_cache[3] = ($event) => showLess(pinned.value.key))
3250
+ }, [createTextVNode(toDisplayString(t("showLess")), 1), createVNode(_sfc_main$2, {
3251
+ name: "up",
3252
+ size: 12
3253
+ })])
3254
+ ], 4)) : createCommentVNode("v-if", true)], 4),
3255
+ loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_35, toDisplayString(t("loading")), 1)) : rootLock.value ? (openBlock(), createElementBlock("form", {
2994
3256
  key: 1,
2995
3257
  class: normalizeClass(["fl-unlock-root", { "fl-unlock-error": rootLock.value.error }]),
2996
3258
  onSubmit: withModifiers(submitRootUnlock, ["prevent"])
@@ -3002,24 +3264,24 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3002
3264
  createElementVNode("label", {
3003
3265
  class: "fl-unlock-label",
3004
3266
  for: `${unref(uid)}-root`
3005
- }, toDisplayString(t("passwordPrompt")), 9, _hoisted_31),
3267
+ }, toDisplayString(t("passwordPrompt")), 9, _hoisted_36),
3006
3268
  rootLock.value.error ? (openBlock(), createElementBlock("span", {
3007
3269
  key: 0,
3008
3270
  id: `${unref(uid)}-root-error`,
3009
3271
  class: "fl-unlock-message",
3010
3272
  role: "alert"
3011
- }, toDisplayString(unlockErrorText(rootLock.value.error)), 9, _hoisted_32)) : createCommentVNode("v-if", true),
3012
- createElementVNode("span", _hoisted_33, [
3273
+ }, toDisplayString(unlockErrorText(rootLock.value.error)), 9, _hoisted_37)) : createCommentVNode("v-if", true),
3274
+ createElementVNode("span", _hoisted_38, [
3013
3275
  withDirectives(createElementVNode("input", {
3014
3276
  id: `${unref(uid)}-root`,
3015
- "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => rootLock.value.input = $event),
3277
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => rootLock.value.input = $event),
3016
3278
  type: "password",
3017
3279
  autocomplete: "off",
3018
3280
  "data-unlock": __props.path,
3019
3281
  placeholder: t("passwordPlaceholder"),
3020
3282
  "aria-invalid": !!rootLock.value.error,
3021
3283
  "aria-describedby": rootLock.value.error ? `${unref(uid)}-root-error` : void 0
3022
- }, null, 8, _hoisted_34), [[vModelText, rootLock.value.input]]),
3284
+ }, null, 8, _hoisted_39), [[vModelText, rootLock.value.input]]),
3023
3285
  canRemember.value ? (openBlock(), createElementBlock("button", {
3024
3286
  key: 0,
3025
3287
  class: "fl-unlock-remember",
@@ -3027,49 +3289,60 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3027
3289
  "aria-pressed": rootLock.value.remember,
3028
3290
  "aria-label": t("rememberPassword"),
3029
3291
  title: t("rememberPassword"),
3030
- onClick: _cache[4] || (_cache[4] = ($event) => rootLock.value.remember = !rootLock.value.remember)
3031
- }, [createVNode(_sfc_main$2, { name: "key" })], 8, _hoisted_35)) : createCommentVNode("v-if", true),
3292
+ onClick: _cache[5] || (_cache[5] = ($event) => rootLock.value.remember = !rootLock.value.remember)
3293
+ }, [createVNode(_sfc_main$2, { name: "key" })], 8, _hoisted_40)) : createCommentVNode("v-if", true),
3032
3294
  createElementVNode("button", {
3033
3295
  class: "fl-unlock-submit",
3034
3296
  type: "submit",
3035
3297
  disabled: rootLock.value.busy || !rootLock.value.input
3036
- }, toDisplayString(t("open")), 9, _hoisted_36)
3298
+ }, toDisplayString(t("open")), 9, _hoisted_41)
3037
3299
  ])
3038
- ], 34)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_37, [
3300
+ ], 34)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_42, [
3039
3301
  createTextVNode(toDisplayString(t("loadFailed", { message: errorMsg.value })) + " ", 1),
3040
- /guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("div", _hoisted_38, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
3041
- unref(isNetworkError)(errorMsg.value) ? (openBlock(), createElementBlock("div", _hoisted_39, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
3302
+ /guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("div", _hoisted_43, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
3303
+ unref(isNetworkError)(errorMsg.value) ? (openBlock(), createElementBlock("div", _hoisted_44, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
3042
3304
  createElementVNode("button", {
3043
3305
  class: "fl-btn",
3044
3306
  type: "button",
3045
3307
  onClick: loadRoot
3046
3308
  }, toDisplayString(t("retry")), 1)
3047
- ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_40, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
3309
+ ])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_45, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
3048
3310
  (openBlock(true), createElementBlock(Fragment, null, renderList(rows.value, (node, index) => {
3049
3311
  return openBlock(), createElementBlock(Fragment, { key: isMore(node) ? `more:${node.key}` : node.path }, [isMore(node) ? (openBlock(), createElementBlock("div", {
3050
3312
  key: 0,
3051
3313
  class: "fl-row fl-more",
3052
3314
  style: normalizeStyle({ "--fl-depth": node.depth })
3053
- }, [_cache[10] || (_cache[10] = createElementVNode("span", { class: "fl-cell fl-cell-check" }, null, -1)), createElementVNode("span", _hoisted_41, [
3054
- _cache[9] || (_cache[9] = createElementVNode("span", {
3315
+ }, [_cache[15] || (_cache[15] = createElementVNode("span", { class: "fl-cell fl-cell-check" }, null, -1)), createElementVNode("span", _hoisted_46, [
3316
+ createCommentVNode(" Reads as one more row of the folder: “⋯” in the type column, the count where names start. "),
3317
+ _cache[12] || (_cache[12] = createElementVNode("span", {
3055
3318
  class: "fl-indent",
3056
3319
  "aria-hidden": "true"
3057
3320
  }, null, -1)),
3058
- createElementVNode("span", _hoisted_42, toDisplayString(t("moreRemaining", { count: node.remaining })), 1),
3059
- node.remaining > (__props.pageSize || 0) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("button", {
3060
- class: "fl-more-btn",
3321
+ _cache[13] || (_cache[13] = createElementVNode("span", {
3322
+ class: "fl-arrow-placeholder",
3323
+ "aria-hidden": "true"
3324
+ }, null, -1)),
3325
+ _cache[14] || (_cache[14] = createElementVNode("span", {
3326
+ class: "fl-more-tag",
3327
+ "aria-hidden": "true"
3328
+ }, "⋯", -1)),
3329
+ createElementVNode("span", _hoisted_47, toDisplayString(t("moreRemaining", { count: node.remaining })), 1),
3330
+ createElementVNode("span", _hoisted_48, [node.remaining > (__props.pageSize || 0) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("button", {
3331
+ class: "fl-more-link",
3061
3332
  type: "button",
3333
+ "aria-label": t("showNext", { count: __props.pageSize }),
3062
3334
  onClick: ($event) => showMore(node, false)
3063
- }, [createTextVNode(toDisplayString(t("showMore")), 1), createElementVNode("span", _hoisted_44, toDisplayString(` ${t("folderItems", { count: __props.pageSize })}`), 1)], 8, _hoisted_43), createElementVNode("button", {
3064
- class: "fl-more-btn fl-more-all",
3335
+ }, [createElementVNode("span", _hoisted_50, toDisplayString(t("showNext", { count: __props.pageSize })), 1), createElementVNode("span", _hoisted_51, toDisplayString(t("showNextShort", { count: __props.pageSize })), 1)], 8, _hoisted_49), createElementVNode("button", {
3336
+ class: "fl-more-link fl-more-all",
3065
3337
  type: "button",
3338
+ "aria-label": t("showAll"),
3066
3339
  onClick: ($event) => showMore(node, true)
3067
- }, toDisplayString(t("showAll")), 9, _hoisted_45)], 64)) : (openBlock(), createElementBlock("button", {
3340
+ }, [createElementVNode("span", _hoisted_53, toDisplayString(t("showAll")), 1), createElementVNode("span", _hoisted_54, toDisplayString(t("showAllShort")), 1)], 8, _hoisted_52)], 64)) : (openBlock(), createElementBlock("button", {
3068
3341
  key: 1,
3069
- class: "fl-more-btn",
3342
+ class: "fl-more-link fl-more-all",
3070
3343
  type: "button",
3071
3344
  onClick: ($event) => showMore(node, true)
3072
- }, toDisplayString(t("showRest", { count: node.remaining })), 9, _hoisted_46))
3345
+ }, toDisplayString(t("showRest", { count: node.remaining })), 9, _hoisted_55))])
3073
3346
  ])], 4)) : (openBlock(), createElementBlock("div", {
3074
3347
  key: 1,
3075
3348
  class: normalizeClass(["fl-row", {
@@ -3080,21 +3353,22 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3080
3353
  "fl-row-prompting": node.lock?.prompting,
3081
3354
  "fl-row-error": node.lock?.prompting && !!node.lock.error
3082
3355
  }]),
3083
- style: normalizeStyle({ "--fl-depth": node.depth })
3356
+ style: normalizeStyle({ "--fl-depth": node.depth }),
3357
+ "data-path": node.path
3084
3358
  }, [
3085
- createElementVNode("label", _hoisted_47, [createElementVNode("input", {
3359
+ createElementVNode("label", _hoisted_57, [createElementVNode("input", {
3086
3360
  type: "checkbox",
3087
3361
  disabled: !!node.lock || batchBusy.value,
3088
3362
  "aria-label": t("selectItem", { name: node.name }),
3089
3363
  checked: isChecked(node),
3090
3364
  ".indeterminate": isIndeterminate(node),
3091
3365
  onChange: ($event) => toggleCheck(node, $event)
3092
- }, null, 40, _hoisted_48)]),
3366
+ }, null, 40, _hoisted_58)]),
3093
3367
  createElementVNode("span", {
3094
3368
  class: "fl-cell fl-cell-name",
3095
3369
  title: node.isRoot ? node.path : void 0
3096
3370
  }, [
3097
- _cache[12] || (_cache[12] = createElementVNode("span", {
3371
+ _cache[17] || (_cache[17] = createElementVNode("span", {
3098
3372
  class: "fl-indent",
3099
3373
  "aria-hidden": "true"
3100
3374
  }, null, -1)),
@@ -3108,7 +3382,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3108
3382
  }, [createVNode(_sfc_main$2, {
3109
3383
  name: "lock",
3110
3384
  size: 14
3111
- })], 8, _hoisted_50)) : node.is_dir ? (openBlock(), createElementBlock("button", {
3385
+ })], 8, _hoisted_60)) : node.is_dir ? (openBlock(), createElementBlock("button", {
3112
3386
  key: 1,
3113
3387
  class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
3114
3388
  type: "button",
@@ -3118,27 +3392,27 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3118
3392
  }, [createVNode(_sfc_main$2, {
3119
3393
  name: "next",
3120
3394
  size: 14
3121
- })], 10, _hoisted_51)) : (openBlock(), createElementBlock("span", _hoisted_52)),
3122
- node.is_dir ? (openBlock(), createElementBlock("svg", _hoisted_53, [..._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", {
3395
+ })], 10, _hoisted_61)) : (openBlock(), createElementBlock("span", _hoisted_62)),
3396
+ node.is_dir ? (openBlock(), createElementBlock("svg", _hoisted_63, [..._cache[16] || (_cache[16] = [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", {
3123
3397
  key: 4,
3124
3398
  class: "fl-type",
3125
3399
  "data-kind": unref(fileKind)(node.name),
3126
3400
  "aria-hidden": "true"
3127
- }, toDisplayString(unref(extOf)(node.name) || "FILE"), 9, _hoisted_54)),
3128
- createElementVNode("span", _hoisted_55, [createElementVNode("span", {
3401
+ }, toDisplayString(unref(extOf)(node.name) || "FILE"), 9, _hoisted_64)),
3402
+ createElementVNode("span", _hoisted_65, [createElementVNode("span", {
3129
3403
  class: normalizeClass(["fl-name", { "fl-name-dir": node.is_dir }]),
3130
3404
  onClick: ($event) => node.lock || node.is_dir ? toggleExpand(node) : download(node)
3131
3405
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(nameParts(node.name), (part, at) => {
3132
- return openBlock(), createElementBlock(Fragment, { key: at }, [part.hit ? (openBlock(), createElementBlock("mark", _hoisted_57, toDisplayString(part.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(part.text), 1)], 64))], 64);
3133
- }), 128))], 10, _hoisted_56), createElementVNode("span", _hoisted_58, [!node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(formatSize)(node.size)) + " · " + toDisplayString(unref(formatDate)(node.modified)), 1)], 64)) : node.loaded ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(t("folderItems", { count: statsOf(node).files })) + " · " + toDisplayString(unref(formatSize)(statsOf(node).bytes)), 1)], 64)) : lockedInSearch(node) ? (openBlock(), createElementBlock("span", _hoisted_59, toDisplayString(t("deepLocked")), 1)) : createCommentVNode("v-if", true)])]),
3134
- lockedInSearch(node) && !node.lock?.prompting ? (openBlock(), createElementBlock("span", _hoisted_60, toDisplayString(t("deepLocked")), 1)) : createCommentVNode("v-if", true),
3135
- node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_61, toDisplayString(t("folderItems", { count: statsOf(node).files })), 1)) : createCommentVNode("v-if", true),
3406
+ return openBlock(), createElementBlock(Fragment, { key: at }, [part.hit ? (openBlock(), createElementBlock("mark", _hoisted_67, toDisplayString(part.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(part.text), 1)], 64))], 64);
3407
+ }), 128))], 10, _hoisted_66), createElementVNode("span", _hoisted_68, [!node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(formatSize)(node.size)) + " · " + toDisplayString(unref(formatDate)(node.modified)), 1)], 64)) : node.loaded ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(t("folderItems", { count: statsOf(node).files })) + " · " + toDisplayString(unref(formatSize)(statsOf(node).bytes)), 1)], 64)) : lockedInSearch(node) ? (openBlock(), createElementBlock("span", _hoisted_69, toDisplayString(t("deepLocked")), 1)) : createCommentVNode("v-if", true)])]),
3408
+ lockedInSearch(node) && !node.lock?.prompting ? (openBlock(), createElementBlock("span", _hoisted_70, toDisplayString(t("deepLocked")), 1)) : createCommentVNode("v-if", true),
3409
+ node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_71, toDisplayString(t("folderItems", { count: statsOf(node).files })), 1)) : createCommentVNode("v-if", true),
3136
3410
  node.lock?.prompting && node.lock.error ? (openBlock(), createElementBlock("span", {
3137
3411
  key: 7,
3138
3412
  id: `${unref(uid)}-error-${index}`,
3139
3413
  class: "fl-unlock-message",
3140
3414
  role: "alert"
3141
- }, toDisplayString(unlockErrorText(node.lock.error)), 9, _hoisted_62)) : createCommentVNode("v-if", true),
3415
+ }, toDisplayString(unlockErrorText(node.lock.error)), 9, _hoisted_72)) : createCommentVNode("v-if", true),
3142
3416
  !node.lock && unref(remembered).has(node.path) ? (openBlock(), createElementBlock("button", {
3143
3417
  key: 8,
3144
3418
  class: "fl-remembered",
@@ -3149,9 +3423,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3149
3423
  }, [createVNode(_sfc_main$2, {
3150
3424
  name: "key",
3151
3425
  size: 11
3152
- }), createTextVNode(" " + toDisplayString(t("remembered")) + " · " + toDisplayString(t("forgetPassword")), 1)], 8, _hoisted_63)) : createCommentVNode("v-if", true),
3153
- node.loading ? (openBlock(), createElementBlock("span", _hoisted_64, "…")) : createCommentVNode("v-if", true)
3154
- ], 8, _hoisted_49),
3426
+ }), createTextVNode(" " + toDisplayString(t("remembered")) + " · " + toDisplayString(t("forgetPassword")), 1)], 8, _hoisted_73)) : createCommentVNode("v-if", true),
3427
+ node.loading ? (openBlock(), createElementBlock("span", _hoisted_74, "…")) : createCommentVNode("v-if", true)
3428
+ ], 8, _hoisted_59),
3155
3429
  node.lock?.prompting ? (openBlock(), createElementBlock("form", {
3156
3430
  key: 0,
3157
3431
  class: "fl-unlock fl-unlock-row",
@@ -3172,7 +3446,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3172
3446
  "aria-label": t("passwordFor", { name: node.name }),
3173
3447
  "aria-invalid": !!node.lock.error,
3174
3448
  "aria-describedby": node.lock.error ? `${unref(uid)}-error-${index}` : void 0
3175
- }, null, 8, _hoisted_66), [[vModelText, node.lock.input]]),
3449
+ }, null, 8, _hoisted_76), [[vModelText, node.lock.input]]),
3176
3450
  canRemember.value ? (openBlock(), createElementBlock("button", {
3177
3451
  key: 0,
3178
3452
  class: "fl-unlock-remember",
@@ -3181,12 +3455,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3181
3455
  "aria-label": t("rememberPassword"),
3182
3456
  title: t("rememberPassword"),
3183
3457
  onClick: ($event) => node.lock.remember = !node.lock.remember
3184
- }, [createVNode(_sfc_main$2, { name: "key" })], 8, _hoisted_67)) : createCommentVNode("v-if", true),
3458
+ }, [createVNode(_sfc_main$2, { name: "key" })], 8, _hoisted_77)) : createCommentVNode("v-if", true),
3185
3459
  createElementVNode("button", {
3186
3460
  class: "fl-unlock-submit",
3187
3461
  type: "submit",
3188
3462
  disabled: node.lock.busy || !node.lock.input
3189
- }, toDisplayString(t("open")), 9, _hoisted_68),
3463
+ }, toDisplayString(t("open")), 9, _hoisted_78),
3190
3464
  createElementVNode("button", {
3191
3465
  class: "fl-unlock-cancel",
3192
3466
  type: "button",
@@ -3196,11 +3470,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3196
3470
  }, [createVNode(_sfc_main$2, {
3197
3471
  name: "close",
3198
3472
  size: 14
3199
- })], 8, _hoisted_69)
3200
- ], 40, _hoisted_65)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
3201
- createElementVNode("span", _hoisted_70, toDisplayString(node.is_dir ? "—" : unref(formatSize)(node.size)), 1),
3202
- createElementVNode("span", _hoisted_71, toDisplayString(unref(formatDate)(node.modified)), 1),
3203
- createElementVNode("span", _hoisted_72, [node.lock ? (openBlock(), createElementBlock("button", {
3473
+ })], 8, _hoisted_79)
3474
+ ], 40, _hoisted_75)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
3475
+ createElementVNode("span", _hoisted_80, toDisplayString(node.is_dir ? "—" : unref(formatSize)(node.size)), 1),
3476
+ createElementVNode("span", _hoisted_81, toDisplayString(unref(formatDate)(node.modified)), 1),
3477
+ createElementVNode("span", _hoisted_82, [node.lock ? (openBlock(), createElementBlock("button", {
3204
3478
  key: 0,
3205
3479
  class: "fl-action fl-arrow-end fl-lock",
3206
3480
  type: "button",
@@ -3209,7 +3483,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3209
3483
  }, [createVNode(_sfc_main$2, {
3210
3484
  name: "lock",
3211
3485
  size: 18
3212
- })], 8, _hoisted_73)) : node.is_dir ? (openBlock(), createElementBlock("button", {
3486
+ })], 8, _hoisted_83)) : node.is_dir ? (openBlock(), createElementBlock("button", {
3213
3487
  key: 1,
3214
3488
  class: normalizeClass(["fl-action fl-arrow-end", { "fl-arrow-open": node.expanded }]),
3215
3489
  type: "button",
@@ -3219,24 +3493,24 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3219
3493
  }, [createVNode(_sfc_main$2, {
3220
3494
  name: "next",
3221
3495
  size: 18
3222
- })], 10, _hoisted_74)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
3496
+ })], 10, _hoisted_84)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
3223
3497
  key: 0,
3224
3498
  class: "fl-action fl-preview-btn",
3225
3499
  type: "button",
3226
3500
  "aria-label": `${t("preview")} ${node.name}`,
3227
3501
  title: t("preview"),
3228
3502
  onClick: ($event) => preview(node)
3229
- }, [createVNode(_sfc_main$2, { name: "eye" })], 8, _hoisted_75)) : createCommentVNode("v-if", true), createElementVNode("button", {
3503
+ }, [createVNode(_sfc_main$2, { name: "eye" })], 8, _hoisted_85)) : createCommentVNode("v-if", true), createElementVNode("button", {
3230
3504
  class: "fl-action fl-download",
3231
3505
  type: "button",
3232
3506
  "aria-label": `${t("download")} ${node.name}`,
3233
3507
  title: t("download"),
3234
3508
  onClick: ($event) => download(node)
3235
- }, [createVNode(_sfc_main$2, { name: "download" })], 8, _hoisted_76)], 64))])
3509
+ }, [createVNode(_sfc_main$2, { name: "download" })], 8, _hoisted_86)], 64))])
3236
3510
  ], 64))
3237
- ], 6))], 64);
3511
+ ], 14, _hoisted_56))], 64);
3238
3512
  }), 128)),
3239
- deepRow.value ? (openBlock(), createElementBlock("div", _hoisted_77, [createElementVNode("div", _hoisted_78, [deepRow.value === "running" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(t("deepRunning", { count: folderCounts.value.checked })) + " · ", 1), createElementVNode("button", {
3513
+ deepRow.value ? (openBlock(), createElementBlock("div", _hoisted_87, [createElementVNode("div", _hoisted_88, [deepRow.value === "running" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(t("deepRunning", { count: folderCounts.value.checked })) + " · ", 1), createElementVNode("button", {
3240
3514
  class: "fl-deep-link",
3241
3515
  type: "button",
3242
3516
  onClick: pauseDeepSearch
@@ -3248,9 +3522,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3248
3522
  class: "fl-deep-link",
3249
3523
  type: "button",
3250
3524
  onClick: deepSearch
3251
- }, toDisplayString(t("deepContinue")), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode(toDisplayString(deepSummary.value), 1)], 64))]), deepRow.value === "running" ? (openBlock(), createElementBlock("span", _hoisted_79)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
3252
- createElementVNode("div", _hoisted_80, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: unref(formatSize)(unref(totalSize)(allFiles.value)) })), 1)]),
3253
- toast.value ? (openBlock(), createElementBlock("div", _hoisted_81, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true),
3525
+ }, toDisplayString(t("deepContinue")), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode(toDisplayString(deepSummary.value), 1)], 64))]), deepRow.value === "running" ? (openBlock(), createElementBlock("span", _hoisted_89)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
3526
+ createElementVNode("div", _hoisted_90, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: unref(formatSize)(unref(totalSize)(allFiles.value)) })), 1)]),
3527
+ toast.value ? (openBlock(), createElementBlock("div", _hoisted_91, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true),
3254
3528
  createVNode(_sfc_main$3, {
3255
3529
  open: !!zipDialog.value,
3256
3530
  title: zipDialog.value?.title ?? "",
@@ -3259,7 +3533,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3259
3533
  "confirm-label": zipDialog.value?.confirm,
3260
3534
  "cancel-label": zipDialog.value?.cancel ?? "",
3261
3535
  onConfirm: confirmZip,
3262
- onClose: _cache[5] || (_cache[5] = ($event) => zipNotice.value = null)
3536
+ onClose: _cache[6] || (_cache[6] = ($event) => zipNotice.value = null)
3263
3537
  }, null, 8, [
3264
3538
  "open",
3265
3539
  "title",
@@ -3276,13 +3550,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
3276
3550
  viewer: previewViewer.value,
3277
3551
  resolving: previewResolving.value,
3278
3552
  error: previewError.value,
3279
- demo: demo.value,
3553
+ demo: demo.value && !!previewNode.value && !unref(isDemoFile)(previewNode.value.path),
3280
3554
  position: previewPosition.value,
3281
3555
  total: previewPosition.value ? previewList.value.length : 0,
3282
3556
  onClose: closePreview,
3283
- onPrev: _cache[6] || (_cache[6] = ($event) => stepPreview(-1)),
3284
- onNext: _cache[7] || (_cache[7] = ($event) => stepPreview(1)),
3285
- onDownload: _cache[8] || (_cache[8] = ($event) => previewNode.value && download(previewNode.value))
3557
+ onPrev: _cache[7] || (_cache[7] = ($event) => stepPreview(-1)),
3558
+ onNext: _cache[8] || (_cache[8] = ($event) => stepPreview(1)),
3559
+ onDownload: _cache[9] || (_cache[9] = ($event) => previewNode.value && download(previewNode.value))
3286
3560
  }, null, 8, [
3287
3561
  "open",
3288
3562
  "file",
@@ -3320,4 +3594,4 @@ function enhanceAppWithFileList({ app }) {
3320
3594
  if (!app._context.components.FileList) app.component("FileList", _sfc_main);
3321
3595
  if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
3322
3596
  }
3323
- export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileKind, fileListLocales, fillPreviewUrl, formatDate, formatLabel, formatSize, iframePreviewsFor, joinPath, previewKind, resolveLabels, totalSize, uniqueEntryName, zipEntryName, zipSegment };
3597
+ export { _sfc_main as FileList, _sfc_main as VPFileList, enhanceAppWithFileList, fileListLocales, formatLabel, resolveLabels };