vitepress-plugin-filelist 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/client/browser/index.d.ts +12 -0
- package/dist/client/browser/index.js +73 -13
- package/dist/client/ssr/index.d.ts +12 -0
- package/dist/client/ssr/index.js +50 -8
- package/dist/client/style.css +0 -4
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
## 功能
|
|
6
6
|
|
|
7
7
|
- 📁 树形目录,文件夹按需加载
|
|
8
|
-
- ✅
|
|
9
|
-
- 📦 批量打包 ZIP(基于 `fflate
|
|
8
|
+
- ✅ 勾选文件;选中文件夹会自动加载并选中其下所有层级的文件
|
|
9
|
+
- 📦 批量打包 ZIP(基于 `fflate`),带进度;保留目录结构,不同目录的同名文件不会互相覆盖
|
|
10
10
|
- ⬇️ 单文件下载与预览(`/d/`、`/p/`、`fs/get` 的 `raw_url`)
|
|
11
11
|
- 🔐 目录密码输入,可选只读 token
|
|
12
12
|
- 🔎 当前树过滤,按名称 / 大小 / 日期排序
|
|
@@ -99,8 +99,8 @@ export default {
|
|
|
99
99
|
|
|
100
100
|
- 目录路径挂载为根文件夹,默认折叠;`expanded` 可为全局或单个 source 打开
|
|
101
101
|
- 文件路径挂载为一条文件记录,直接预览/下载
|
|
102
|
-
-
|
|
103
|
-
- 每个 source 可单独设置 `title`、`password`
|
|
102
|
+
- 勾选根目录会加载并选中其下所有文件;ZIP 内以根节点名称(`title` 或路径末段)作为顶层文件夹,文件根保留原文件名
|
|
103
|
+
- 每个 source 可单独设置 `title`、`password`;未设置 `password` 的 source 使用组件的 `password` 或运行时输入的密码,遇到需要密码的目录会弹出密码输入框
|
|
104
104
|
- 根节点顺序按 `sources` 顺序,子项仍按名称/大小/日期排序
|
|
105
105
|
|
|
106
106
|
```ts
|
|
@@ -181,7 +181,7 @@ Deno 可以安装 npm 依赖,但目前用 Deno 构建 VitePress 会在 rolldow
|
|
|
181
181
|
## 说明
|
|
182
182
|
|
|
183
183
|
- 批量 ZIP 通过 `raw_url`(OpenList `/p/` 代理)下载,CORS 保持在 OpenList 源上
|
|
184
|
-
-
|
|
184
|
+
- 表头全选只统计已加载的文件,页脚会显示还有多少文件夹未展开;勾选单个文件夹则会递归加载其全部子目录(目录很深或很多时会逐个请求,可能较慢)
|
|
185
185
|
- 目录以 `per_page: 0` 请求全部条目;超大目录可能较慢,暂未实现分页
|
|
186
186
|
|
|
187
187
|
## 开发
|
|
@@ -190,7 +190,7 @@ Deno 可以安装 npm 依赖,但目前用 Deno 构建 VitePress 会在 rolldow
|
|
|
190
190
|
pnpm install
|
|
191
191
|
pnpm run build # 生成 dist/node、dist/client/ssr、dist/client/browser、style.css
|
|
192
192
|
pnpm run typecheck
|
|
193
|
-
pnpm test # Vitest:utils
|
|
193
|
+
pnpm test # Vitest:utils、locale helpers、FileList 组件
|
|
194
194
|
pnpm run pack:check
|
|
195
195
|
```
|
|
196
196
|
|
|
@@ -200,8 +200,8 @@ pnpm run pack:check
|
|
|
200
200
|
|
|
201
201
|
```bash
|
|
202
202
|
cd demo
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
pnpm install
|
|
204
|
+
pnpm run build
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
## License
|
|
@@ -171,6 +171,18 @@ export interface SortableNode {
|
|
|
171
171
|
export type SortKey = 'name' | 'size' | 'modified';
|
|
172
172
|
export declare function joinPath(parent: string, name: string): string;
|
|
173
173
|
export declare function encodePath(path: string): string;
|
|
174
|
+
/**
|
|
175
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
176
|
+
* no `.` / `..` traversal, no empty names.
|
|
177
|
+
*/
|
|
178
|
+
export declare function zipSegment(name: string): string;
|
|
179
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
180
|
+
export declare function zipEntryName(segments: string[]): string;
|
|
181
|
+
/**
|
|
182
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
183
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
184
|
+
*/
|
|
185
|
+
export declare function uniqueEntryName(name: string, used: Set<string>): string;
|
|
174
186
|
export declare function formatSize(size: number): string;
|
|
175
187
|
export declare function formatDate(iso: string): string;
|
|
176
188
|
export declare function extOf(name: string): string;
|
|
@@ -87,6 +87,41 @@ function joinPath(parent, name) {
|
|
|
87
87
|
function encodePath(path) {
|
|
88
88
|
return path.split("/").map(encodeURIComponent).join("/");
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
92
|
+
* no `.` / `..` traversal, no empty names.
|
|
93
|
+
*/
|
|
94
|
+
function zipSegment(name) {
|
|
95
|
+
const cleaned = name.replace(/[\\/]/g, "_").trim();
|
|
96
|
+
if (!cleaned || cleaned === "." || cleaned === "..") return "_";
|
|
97
|
+
return cleaned;
|
|
98
|
+
}
|
|
99
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
100
|
+
function zipEntryName(segments) {
|
|
101
|
+
return segments.map(zipSegment).join("/");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
105
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
106
|
+
*/
|
|
107
|
+
function uniqueEntryName(name, used) {
|
|
108
|
+
let candidate = name;
|
|
109
|
+
if (used.has(candidate)) {
|
|
110
|
+
const slash = name.lastIndexOf("/");
|
|
111
|
+
const dir = name.slice(0, slash + 1);
|
|
112
|
+
const base = name.slice(slash + 1);
|
|
113
|
+
const dot = base.lastIndexOf(".");
|
|
114
|
+
const stem = dot > 0 ? base.slice(0, dot) : base;
|
|
115
|
+
const ext = dot > 0 ? base.slice(dot) : "";
|
|
116
|
+
let index = 2;
|
|
117
|
+
do {
|
|
118
|
+
candidate = `${dir}${stem} (${index})${ext}`;
|
|
119
|
+
index += 1;
|
|
120
|
+
} while (used.has(candidate));
|
|
121
|
+
}
|
|
122
|
+
used.add(candidate);
|
|
123
|
+
return candidate;
|
|
124
|
+
}
|
|
90
125
|
function formatSize(size) {
|
|
91
126
|
if (!size || !Number.isFinite(size)) return "-";
|
|
92
127
|
const units = [
|
|
@@ -258,6 +293,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
258
293
|
function errorText(error) {
|
|
259
294
|
return error instanceof Error ? error.message : String(error);
|
|
260
295
|
}
|
|
296
|
+
function isPasswordError(error) {
|
|
297
|
+
return /password|密码/i.test(errorText(error));
|
|
298
|
+
}
|
|
261
299
|
const DEMO_TREE = {
|
|
262
300
|
"/": [
|
|
263
301
|
{
|
|
@@ -472,7 +510,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
472
510
|
nodes.sort((a, b) => compareNodes(a, b, sortKey.value, sortAsc.value));
|
|
473
511
|
for (const node of nodes) if (node.children.length) sortTree(node.children);
|
|
474
512
|
}
|
|
475
|
-
function toNodes(items, parent, depth, password = "") {
|
|
513
|
+
function toNodes(items, parent, depth, password = "", zipParent = []) {
|
|
476
514
|
return items.map((item) => ({
|
|
477
515
|
...item,
|
|
478
516
|
path: joinPath(parent, item.name),
|
|
@@ -481,7 +519,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
481
519
|
loaded: false,
|
|
482
520
|
loading: false,
|
|
483
521
|
children: [],
|
|
484
|
-
password
|
|
522
|
+
password,
|
|
523
|
+
zipPath: [...zipParent, item.name]
|
|
485
524
|
}));
|
|
486
525
|
}
|
|
487
526
|
function setSort(key) {
|
|
@@ -502,11 +541,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
502
541
|
if (node.loaded) return true;
|
|
503
542
|
node.loading = true;
|
|
504
543
|
try {
|
|
505
|
-
node.children = toNodes(await listDir(node.path, node.password), node.path, node.depth + 1, node.password);
|
|
544
|
+
node.children = toNodes(await listDir(node.path, node.password || activePassword.value), node.path, node.depth + 1, node.password, node.zipPath);
|
|
506
545
|
sortTree(node.children);
|
|
507
546
|
node.loaded = true;
|
|
508
547
|
return true;
|
|
509
548
|
} catch (error) {
|
|
549
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
510
550
|
showToast(t("folderFailed", { message: errorText(error) }));
|
|
511
551
|
return false;
|
|
512
552
|
} finally {
|
|
@@ -531,16 +571,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
531
571
|
} else try {
|
|
532
572
|
const data = await request("/api/fs/get", {
|
|
533
573
|
path,
|
|
534
|
-
password
|
|
574
|
+
password: password || activePassword.value
|
|
535
575
|
});
|
|
536
576
|
item = {
|
|
537
577
|
...item,
|
|
538
578
|
...data
|
|
539
579
|
};
|
|
540
580
|
} catch {}
|
|
581
|
+
const name = source.title || item.name || sourceName(path);
|
|
541
582
|
return {
|
|
542
583
|
...item,
|
|
543
|
-
name
|
|
584
|
+
name,
|
|
544
585
|
path,
|
|
545
586
|
depth: 0,
|
|
546
587
|
expanded: source.expanded ?? props.expanded,
|
|
@@ -548,7 +589,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
548
589
|
loading: false,
|
|
549
590
|
children: [],
|
|
550
591
|
password,
|
|
551
|
-
isRoot: true
|
|
592
|
+
isRoot: true,
|
|
593
|
+
zipPath: [item.is_dir ? name : item.name || sourceName(path)]
|
|
552
594
|
};
|
|
553
595
|
}
|
|
554
596
|
async function loadRoot() {
|
|
@@ -571,7 +613,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
571
613
|
downloadCache.clear();
|
|
572
614
|
} catch (error) {
|
|
573
615
|
const message = errorText(error);
|
|
574
|
-
if (
|
|
616
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
575
617
|
else errorMsg.value = message;
|
|
576
618
|
} finally {
|
|
577
619
|
loadingRoot.value = false;
|
|
@@ -613,10 +655,27 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
613
655
|
const hit = files.filter((file) => selected.value.has(file.path)).length;
|
|
614
656
|
return hit > 0 && hit < files.length;
|
|
615
657
|
}
|
|
616
|
-
|
|
617
|
-
|
|
658
|
+
/** Load a directory and all of its sub-directories. */
|
|
659
|
+
async function loadTree(node) {
|
|
660
|
+
if (!node.is_dir) return true;
|
|
661
|
+
if (!await loadChildren(node)) return false;
|
|
662
|
+
for (const child of node.children) if (child.is_dir && !await loadTree(child)) return false;
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
async function toggleCheck(node, event) {
|
|
666
|
+
const input = event?.target;
|
|
667
|
+
if (node.is_dir && !isChecked(node)) {
|
|
668
|
+
if (await loadTree(node)) node.expanded = true;
|
|
669
|
+
else {
|
|
670
|
+
if (input) input.checked = isChecked(node);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
618
674
|
const files = descendantFiles(node);
|
|
619
|
-
if (!files.length)
|
|
675
|
+
if (!files.length) {
|
|
676
|
+
if (input) input.checked = false;
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
620
679
|
const next = new Set(selected.value);
|
|
621
680
|
if (files.every((file) => next.has(file.path))) files.forEach((file) => next.delete(file.path));
|
|
622
681
|
else files.forEach((file) => next.add(file.path));
|
|
@@ -696,6 +755,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
696
755
|
batchProgress.value = 0;
|
|
697
756
|
try {
|
|
698
757
|
const entries = {};
|
|
758
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
699
759
|
const queue = [...files];
|
|
700
760
|
let done = 0;
|
|
701
761
|
const worker = async () => {
|
|
@@ -704,7 +764,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
704
764
|
if (!file) break;
|
|
705
765
|
const response = await fetch(await resolveUrl(file));
|
|
706
766
|
if (!response.ok) throw new Error(`${file.name}:HTTP ${response.status}`);
|
|
707
|
-
entries[file.
|
|
767
|
+
entries[uniqueEntryName(zipEntryName(file.zipPath), usedNames)] = new Uint8Array(await response.arrayBuffer());
|
|
708
768
|
done += 1;
|
|
709
769
|
batchProgress.value = Math.round(done / files.length * 90);
|
|
710
770
|
}
|
|
@@ -816,7 +876,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
816
876
|
type: "checkbox",
|
|
817
877
|
checked: isChecked(node),
|
|
818
878
|
".indeterminate": isIndeterminate(node),
|
|
819
|
-
onChange: ($event) => toggleCheck(node)
|
|
879
|
+
onChange: ($event) => toggleCheck(node, $event)
|
|
820
880
|
}, null, 40, _hoisted_23)]),
|
|
821
881
|
createElementVNode("span", {
|
|
822
882
|
class: "fl-cell fl-cell-name",
|
|
@@ -906,4 +966,4 @@ function enhanceAppWithFileList({ app }) {
|
|
|
906
966
|
if (!app._context.components.FileList) app.component("FileList", _sfc_main);
|
|
907
967
|
if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
|
|
908
968
|
}
|
|
909
|
-
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels };
|
|
969
|
+
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, uniqueEntryName, zipEntryName, zipSegment };
|
|
@@ -171,6 +171,18 @@ export interface SortableNode {
|
|
|
171
171
|
export type SortKey = 'name' | 'size' | 'modified';
|
|
172
172
|
export declare function joinPath(parent: string, name: string): string;
|
|
173
173
|
export declare function encodePath(path: string): string;
|
|
174
|
+
/**
|
|
175
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
176
|
+
* no `.` / `..` traversal, no empty names.
|
|
177
|
+
*/
|
|
178
|
+
export declare function zipSegment(name: string): string;
|
|
179
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
180
|
+
export declare function zipEntryName(segments: string[]): string;
|
|
181
|
+
/**
|
|
182
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
183
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
184
|
+
*/
|
|
185
|
+
export declare function uniqueEntryName(name: string, used: Set<string>): string;
|
|
174
186
|
export declare function formatSize(size: number): string;
|
|
175
187
|
export declare function formatDate(iso: string): string;
|
|
176
188
|
export declare function extOf(name: string): string;
|
package/dist/client/ssr/index.js
CHANGED
|
@@ -87,6 +87,41 @@ function joinPath(parent, name) {
|
|
|
87
87
|
function encodePath(path) {
|
|
88
88
|
return path.split("/").map(encodeURIComponent).join("/");
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Make one path segment safe as a ZIP entry segment: no separators,
|
|
92
|
+
* no `.` / `..` traversal, no empty names.
|
|
93
|
+
*/
|
|
94
|
+
function zipSegment(name) {
|
|
95
|
+
const cleaned = name.replace(/[\\/]/g, "_").trim();
|
|
96
|
+
if (!cleaned || cleaned === "." || cleaned === "..") return "_";
|
|
97
|
+
return cleaned;
|
|
98
|
+
}
|
|
99
|
+
/** Join path segments into a ZIP entry name, sanitising each segment. */
|
|
100
|
+
function zipEntryName(segments) {
|
|
101
|
+
return segments.map(zipSegment).join("/");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Return `name`, or `name (2)`, `name (3)`... when it is already in `used`.
|
|
105
|
+
* The suffix goes before the extension of the last segment. Adds the result to `used`.
|
|
106
|
+
*/
|
|
107
|
+
function uniqueEntryName(name, used) {
|
|
108
|
+
let candidate = name;
|
|
109
|
+
if (used.has(candidate)) {
|
|
110
|
+
const slash = name.lastIndexOf("/");
|
|
111
|
+
const dir = name.slice(0, slash + 1);
|
|
112
|
+
const base = name.slice(slash + 1);
|
|
113
|
+
const dot = base.lastIndexOf(".");
|
|
114
|
+
const stem = dot > 0 ? base.slice(0, dot) : base;
|
|
115
|
+
const ext = dot > 0 ? base.slice(dot) : "";
|
|
116
|
+
let index = 2;
|
|
117
|
+
do {
|
|
118
|
+
candidate = `${dir}${stem} (${index})${ext}`;
|
|
119
|
+
index += 1;
|
|
120
|
+
} while (used.has(candidate));
|
|
121
|
+
}
|
|
122
|
+
used.add(candidate);
|
|
123
|
+
return candidate;
|
|
124
|
+
}
|
|
90
125
|
function formatSize(size) {
|
|
91
126
|
if (!size || !Number.isFinite(size)) return "-";
|
|
92
127
|
const units = [
|
|
@@ -181,6 +216,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
181
216
|
function errorText(error) {
|
|
182
217
|
return error instanceof Error ? error.message : String(error);
|
|
183
218
|
}
|
|
219
|
+
function isPasswordError(error) {
|
|
220
|
+
return /password|密码/i.test(errorText(error));
|
|
221
|
+
}
|
|
184
222
|
const DEMO_TREE = {
|
|
185
223
|
"/": [
|
|
186
224
|
{
|
|
@@ -364,7 +402,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
364
402
|
nodes.sort((a, b) => compareNodes(a, b, sortKey.value, sortAsc.value));
|
|
365
403
|
for (const node of nodes) if (node.children.length) sortTree(node.children);
|
|
366
404
|
}
|
|
367
|
-
function toNodes(items, parent, depth, password = "") {
|
|
405
|
+
function toNodes(items, parent, depth, password = "", zipParent = []) {
|
|
368
406
|
return items.map((item) => ({
|
|
369
407
|
...item,
|
|
370
408
|
path: joinPath(parent, item.name),
|
|
@@ -373,7 +411,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
373
411
|
loaded: false,
|
|
374
412
|
loading: false,
|
|
375
413
|
children: [],
|
|
376
|
-
password
|
|
414
|
+
password,
|
|
415
|
+
zipPath: [...zipParent, item.name]
|
|
377
416
|
}));
|
|
378
417
|
}
|
|
379
418
|
function sourceName(path) {
|
|
@@ -384,11 +423,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
384
423
|
if (node.loaded) return true;
|
|
385
424
|
node.loading = true;
|
|
386
425
|
try {
|
|
387
|
-
node.children = toNodes(await listDir(node.path, node.password), node.path, node.depth + 1, node.password);
|
|
426
|
+
node.children = toNodes(await listDir(node.path, node.password || activePassword.value), node.path, node.depth + 1, node.password, node.zipPath);
|
|
388
427
|
sortTree(node.children);
|
|
389
428
|
node.loaded = true;
|
|
390
429
|
return true;
|
|
391
430
|
} catch (error) {
|
|
431
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
392
432
|
showToast(t("folderFailed", { message: errorText(error) }));
|
|
393
433
|
return false;
|
|
394
434
|
} finally {
|
|
@@ -413,16 +453,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
413
453
|
} else try {
|
|
414
454
|
const data = await request("/api/fs/get", {
|
|
415
455
|
path,
|
|
416
|
-
password
|
|
456
|
+
password: password || activePassword.value
|
|
417
457
|
});
|
|
418
458
|
item = {
|
|
419
459
|
...item,
|
|
420
460
|
...data
|
|
421
461
|
};
|
|
422
462
|
} catch {}
|
|
463
|
+
const name = source.title || item.name || sourceName(path);
|
|
423
464
|
return {
|
|
424
465
|
...item,
|
|
425
|
-
name
|
|
466
|
+
name,
|
|
426
467
|
path,
|
|
427
468
|
depth: 0,
|
|
428
469
|
expanded: source.expanded ?? props.expanded,
|
|
@@ -430,7 +471,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
430
471
|
loading: false,
|
|
431
472
|
children: [],
|
|
432
473
|
password,
|
|
433
|
-
isRoot: true
|
|
474
|
+
isRoot: true,
|
|
475
|
+
zipPath: [item.is_dir ? name : item.name || sourceName(path)]
|
|
434
476
|
};
|
|
435
477
|
}
|
|
436
478
|
async function loadRoot() {
|
|
@@ -453,7 +495,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
453
495
|
downloadCache.clear();
|
|
454
496
|
} catch (error) {
|
|
455
497
|
const message = errorText(error);
|
|
456
|
-
if (
|
|
498
|
+
if (isPasswordError(error)) needsPassword.value = true;
|
|
457
499
|
else errorMsg.value = message;
|
|
458
500
|
} finally {
|
|
459
501
|
loadingRoot.value = false;
|
|
@@ -588,4 +630,4 @@ function enhanceAppWithFileList({ app }) {
|
|
|
588
630
|
if (!app._context.components.FileList) app.component("FileList", _sfc_main);
|
|
589
631
|
if (!app._context.components.VPFileList) app.component("VPFileList", _sfc_main);
|
|
590
632
|
}
|
|
591
|
-
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels };
|
|
633
|
+
export { _sfc_main as FileList, _sfc_main as VPFileList, compareNodes, encodePath, enhanceAppWithFileList, extOf, fileListLocales, formatDate, formatLabel, formatSize, joinPath, resolveLabels, uniqueEntryName, zipEntryName, zipSegment };
|
package/dist/client/style.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitepress-plugin-filelist",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"packageManager": "pnpm@11.25.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "OpenList file browser for VitePress: tree view, batch ZIP download, i18n, password and token support.",
|
|
@@ -54,6 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/node": "^22.10.0",
|
|
57
|
+
"@vue/test-utils": "^2.5.1",
|
|
58
|
+
"happy-dom": "^21.0.4",
|
|
57
59
|
"tsdown": "^0.23.7",
|
|
58
60
|
"typescript": "^5.6.0",
|
|
59
61
|
"unplugin-vue": "^8.0.1",
|