@huyooo/file-explorer-frontend-react 0.4.18 → 0.4.21

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.
Files changed (44) hide show
  1. package/dist/index.css +0 -1
  2. package/dist/index.js +1 -3456
  3. package/package.json +4 -4
  4. package/dist/index.css.map +0 -1
  5. package/dist/index.js.map +0 -1
  6. package/src/components/Breadcrumb.css +0 -61
  7. package/src/components/Breadcrumb.tsx +0 -38
  8. package/src/components/CompressDialog.css +0 -267
  9. package/src/components/CompressDialog.tsx +0 -222
  10. package/src/components/ContextMenu.css +0 -155
  11. package/src/components/ContextMenu.tsx +0 -375
  12. package/src/components/FileGrid.css +0 -239
  13. package/src/components/FileGrid.tsx +0 -278
  14. package/src/components/FileIcon.css +0 -41
  15. package/src/components/FileIcon.tsx +0 -86
  16. package/src/components/FileInfoDialog.css +0 -214
  17. package/src/components/FileInfoDialog.tsx +0 -202
  18. package/src/components/FileList.css +0 -169
  19. package/src/components/FileList.tsx +0 -228
  20. package/src/components/FileListView.css +0 -36
  21. package/src/components/FileListView.tsx +0 -355
  22. package/src/components/FileSidebar.css +0 -94
  23. package/src/components/FileSidebar.tsx +0 -66
  24. package/src/components/ProgressDialog.css +0 -211
  25. package/src/components/ProgressDialog.tsx +0 -183
  26. package/src/components/SortIndicator.css +0 -7
  27. package/src/components/SortIndicator.tsx +0 -19
  28. package/src/components/StatusBar.css +0 -20
  29. package/src/components/StatusBar.tsx +0 -21
  30. package/src/components/Toolbar.css +0 -150
  31. package/src/components/Toolbar.tsx +0 -127
  32. package/src/components/Window.css +0 -246
  33. package/src/components/Window.tsx +0 -335
  34. package/src/hooks/useApplicationIcon.ts +0 -80
  35. package/src/hooks/useDragAndDrop.ts +0 -104
  36. package/src/hooks/useMediaPlayer.ts +0 -164
  37. package/src/hooks/useSelection.ts +0 -112
  38. package/src/hooks/useWindowDrag.ts +0 -60
  39. package/src/hooks/useWindowResize.ts +0 -126
  40. package/src/index.css +0 -184
  41. package/src/index.ts +0 -37
  42. package/src/types/index.ts +0 -274
  43. package/src/utils/fileTypeIcon.ts +0 -309
  44. package/src/utils/folderTypeIcon.ts +0 -132
package/dist/index.js CHANGED
@@ -1,3456 +1 @@
1
- // src/types/index.ts
2
- var FileType = {
3
- FOLDER: "folder",
4
- FILE: "file",
5
- IMAGE: "image",
6
- VIDEO: "video",
7
- MUSIC: "music",
8
- DOCUMENT: "document",
9
- CODE: "code",
10
- TEXT: "text",
11
- PDF: "pdf",
12
- ARCHIVE: "archive",
13
- APPLICATION: "application",
14
- UNKNOWN: "unknown"
15
- };
16
-
17
- // src/components/FileListView.tsx
18
- import { useState, useCallback, useImperativeHandle, forwardRef } from "react";
19
- import { Icon as Icon3 } from "@iconify/react";
20
-
21
- // src/components/FileGrid.tsx
22
- import { useRef, useMemo as useMemo2 } from "react";
23
-
24
- // src/components/FileIcon.tsx
25
- import { useMemo } from "react";
26
- import { Icon } from "@iconify/react";
27
-
28
- // src/utils/fileTypeIcon.ts
29
- var KNOWN_TYPES = /* @__PURE__ */ new Set([
30
- "3d",
31
- "actionscript",
32
- "ada",
33
- "adobe-illustrator",
34
- "adobe-photoshop",
35
- "android",
36
- "angular",
37
- "applescript",
38
- "arduino",
39
- "asciidoc",
40
- "assembly",
41
- "astro",
42
- "audio",
43
- "aurelia",
44
- "babel",
45
- "ballerina",
46
- "bazel",
47
- "biome",
48
- "blender",
49
- "bower",
50
- "bun",
51
- "c",
52
- "cabal",
53
- "caddy",
54
- "cake",
55
- "certificate",
56
- "changelog",
57
- "circleci",
58
- "claude",
59
- "clojure",
60
- "cmake",
61
- "cobol",
62
- "coffee",
63
- "command",
64
- "conduct",
65
- "contributing",
66
- "controller",
67
- "copilot",
68
- "cpp",
69
- "crystal",
70
- "csharp",
71
- "css",
72
- "css-map",
73
- "cucumber",
74
- "cuda",
75
- "cursor",
76
- "cypress",
77
- "d",
78
- "dart",
79
- "database",
80
- "deno",
81
- "dependabot",
82
- "diff",
83
- "django",
84
- "docker",
85
- "document",
86
- "drawio",
87
- "drizzle",
88
- "editorconfig",
89
- "ejs",
90
- "elixir",
91
- "elm",
92
- "email",
93
- "ember",
94
- "epub",
95
- "erlang",
96
- "esbuild",
97
- "eslint",
98
- "excalidraw",
99
- "exe",
100
- "favicon",
101
- "figma",
102
- "firebase",
103
- "flash",
104
- "flow",
105
- "font",
106
- "forth",
107
- "fortran",
108
- "freemarker",
109
- "fsharp",
110
- "gamemaker",
111
- "gatsby",
112
- "gcp",
113
- "gemfile",
114
- "gemini",
115
- "git",
116
- "gitlab",
117
- "gleam",
118
- "go",
119
- "go-mod",
120
- "godot",
121
- "gradle",
122
- "graphql",
123
- "groovy",
124
- "grunt",
125
- "gulp",
126
- "h",
127
- "haml",
128
- "handlebars",
129
- "hardhat",
130
- "haskell",
131
- "haxe",
132
- "hcl",
133
- "helm",
134
- "hjson",
135
- "hosts",
136
- "hpp",
137
- "html",
138
- "http",
139
- "husky",
140
- "i18n",
141
- "image",
142
- "imba",
143
- "ionic",
144
- "jar",
145
- "java",
146
- "javaclass",
147
- "javascript",
148
- "javascript-map",
149
- "jenkins",
150
- "jest",
151
- "jinja",
152
- "jsconfig",
153
- "json",
154
- "julia",
155
- "jupyter",
156
- "just",
157
- "karma",
158
- "key",
159
- "kotlin",
160
- "kubernetes",
161
- "laravel",
162
- "lean",
163
- "lefthook",
164
- "lerna",
165
- "less",
166
- "lib",
167
- "license",
168
- "lighthouse",
169
- "liquid",
170
- "lisp",
171
- "livescript",
172
- "lock",
173
- "log",
174
- "lua",
175
- "luau",
176
- "makefile",
177
- "markdown",
178
- "markdownlint",
179
- "matlab",
180
- "maven",
181
- "mdx",
182
- "mercurial",
183
- "mermaid",
184
- "meson",
185
- "minecraft",
186
- "mjml",
187
- "mocha",
188
- "mojo",
189
- "nest",
190
- "netlify",
191
- "next",
192
- "nginx",
193
- "nim",
194
- "nix",
195
- "nodejs",
196
- "nodemon",
197
- "npm",
198
- "nuget",
199
- "nunjucks",
200
- "nuxt",
201
- "nx",
202
- "objective-c",
203
- "objective-cpp",
204
- "ocaml",
205
- "odin",
206
- "openapi",
207
- "opentofu",
208
- "pascal",
209
- "pdf",
210
- "perl",
211
- "php",
212
- "phpstan",
213
- "phpunit",
214
- "pipeline",
215
- "playwright",
216
- "pnpm",
217
- "postcss",
218
- "powerpoint",
219
- "powershell",
220
- "prettier",
221
- "prisma",
222
- "processing",
223
- "prolog",
224
- "proto",
225
- "pug",
226
- "puppet",
227
- "purescript",
228
- "python",
229
- "pytorch",
230
- "quasar",
231
- "r",
232
- "racket",
233
- "razor",
234
- "react",
235
- "react-ts",
236
- "readme",
237
- "reason",
238
- "remark",
239
- "remix",
240
- "renovate",
241
- "replit",
242
- "rescript",
243
- "riot",
244
- "roadmap",
245
- "robot",
246
- "robots",
247
- "rollup",
248
- "routing",
249
- "rspec",
250
- "rubocop",
251
- "ruby",
252
- "ruff",
253
- "rust",
254
- "salt",
255
- "san",
256
- "sas",
257
- "sass",
258
- "sbt",
259
- "scala",
260
- "scheme",
261
- "search",
262
- "sentry",
263
- "sequelize",
264
- "serverless",
265
- "settings",
266
- "shader",
267
- "shellcheck",
268
- "sketch",
269
- "slim",
270
- "slint",
271
- "smarty",
272
- "snakemake",
273
- "snapcraft",
274
- "snyk",
275
- "solidity",
276
- "spwn",
277
- "stackblitz",
278
- "stan",
279
- "stencil",
280
- "storybook",
281
- "stryker",
282
- "stylelint",
283
- "stylus",
284
- "sublime",
285
- "subtitles",
286
- "supabase",
287
- "svelte",
288
- "svg",
289
- "svgo",
290
- "swagger",
291
- "swc",
292
- "swift",
293
- "tailwindcss",
294
- "taskfile",
295
- "tauri",
296
- "tcl",
297
- "teal",
298
- "templ",
299
- "template",
300
- "terraform",
301
- "test-js",
302
- "test-jsx",
303
- "test-ts",
304
- "tex",
305
- "todo",
306
- "toml",
307
- "travis",
308
- "tree",
309
- "tsconfig",
310
- "tsdoc",
311
- "turborepo",
312
- "twig",
313
- "typescript",
314
- "typescript-def",
315
- "unity",
316
- "unocss",
317
- "vagrant",
318
- "vanilla-extract",
319
- "vercel",
320
- "verilog",
321
- "video",
322
- "vim",
323
- "vite",
324
- "vitest",
325
- "vlang",
326
- "vscode",
327
- "vue",
328
- "vue-config",
329
- "wakatime",
330
- "wallaby",
331
- "webassembly",
332
- "webhint",
333
- "webpack",
334
- "windicss",
335
- "word",
336
- "wrangler",
337
- "wxt",
338
- "xaml",
339
- "xmake",
340
- "xml",
341
- "yaml",
342
- "yarn",
343
- "zig",
344
- "zip"
345
- ]);
346
- var EXT_MAP = {
347
- // JavaScript/TypeScript
348
- "js": "javascript",
349
- "mjs": "javascript",
350
- "cjs": "javascript",
351
- "jsx": "react",
352
- "ts": "typescript",
353
- "mts": "typescript",
354
- "cts": "typescript",
355
- "tsx": "react-ts",
356
- // 前端框架
357
- "vue": "vue",
358
- "svelte": "svelte",
359
- "astro": "astro",
360
- // 后端语言
361
- "py": "python",
362
- "pyw": "python",
363
- "pyi": "python",
364
- "pyc": "python",
365
- "java": "java",
366
- "class": "javaclass",
367
- "jar": "jar",
368
- "c": "c",
369
- "h": "h",
370
- "cpp": "cpp",
371
- "cc": "cpp",
372
- "cxx": "cpp",
373
- "hpp": "hpp",
374
- "hh": "hpp",
375
- "hxx": "hpp",
376
- "cs": "csharp",
377
- "csx": "csharp",
378
- "go": "go",
379
- "rs": "rust",
380
- "php": "php",
381
- "phtml": "php",
382
- "rb": "ruby",
383
- "rake": "ruby",
384
- "swift": "swift",
385
- "kt": "kotlin",
386
- "kts": "kotlin",
387
- "scala": "scala",
388
- "dart": "dart",
389
- "lua": "lua",
390
- "luau": "luau",
391
- "r": "r",
392
- "rdata": "r",
393
- "rds": "r",
394
- "pl": "perl",
395
- "pm": "perl",
396
- "sh": "command",
397
- "bash": "command",
398
- "zsh": "command",
399
- "fish": "command",
400
- "ps1": "powershell",
401
- "psm1": "powershell",
402
- "psd1": "powershell",
403
- "bat": "command",
404
- "cmd": "command",
405
- // 样式
406
- "css": "css",
407
- "scss": "sass",
408
- "sass": "sass",
409
- "less": "less",
410
- "styl": "stylus",
411
- // 标记/配置
412
- "html": "html",
413
- "htm": "html",
414
- "xhtml": "html",
415
- "xml": "xml",
416
- "xsl": "xml",
417
- "xslt": "xml",
418
- "json": "json",
419
- "jsonc": "json",
420
- "json5": "json",
421
- "yaml": "yaml",
422
- "yml": "yaml",
423
- "toml": "toml",
424
- "ini": "settings",
425
- "conf": "settings",
426
- "config": "settings",
427
- // 文档
428
- "md": "markdown",
429
- "markdown": "markdown",
430
- "mdx": "mdx",
431
- "txt": "document",
432
- "pdf": "pdf",
433
- "doc": "word",
434
- "docx": "word",
435
- "dot": "word",
436
- "dotx": "word",
437
- "odt": "word",
438
- "xls": "table",
439
- "xlsx": "table",
440
- "xlsm": "table",
441
- "ods": "table",
442
- "csv": "table",
443
- "ppt": "powerpoint",
444
- "pptx": "powerpoint",
445
- "odp": "powerpoint",
446
- // 图片
447
- "jpg": "image",
448
- "jpeg": "image",
449
- "png": "image",
450
- "gif": "image",
451
- "webp": "image",
452
- "ico": "image",
453
- "bmp": "image",
454
- "tiff": "image",
455
- "tif": "image",
456
- "heic": "image",
457
- "heif": "image",
458
- "svg": "svg",
459
- "psd": "adobe-photoshop",
460
- "ai": "adobe-illustrator",
461
- "sketch": "sketch",
462
- "fig": "figma",
463
- "figma": "figma",
464
- // 视频/音频
465
- "mp4": "video",
466
- "mov": "video",
467
- "avi": "video",
468
- "mkv": "video",
469
- "webm": "video",
470
- "flv": "video",
471
- "wmv": "video",
472
- "m4v": "video",
473
- "3gp": "video",
474
- "mpeg": "video",
475
- "mpg": "video",
476
- "mp3": "audio",
477
- "wav": "audio",
478
- "flac": "audio",
479
- "aac": "audio",
480
- "ogg": "audio",
481
- "wma": "audio",
482
- "m4a": "audio",
483
- "aiff": "audio",
484
- // 压缩
485
- "zip": "zip",
486
- "rar": "zip",
487
- "7z": "zip",
488
- "tar": "zip",
489
- "gz": "zip",
490
- "bz2": "zip",
491
- "xz": "zip",
492
- "tgz": "zip",
493
- "tbz2": "zip",
494
- // 数据库
495
- "sql": "database",
496
- "db": "database",
497
- "sqlite": "database",
498
- "sqlite3": "database",
499
- "prisma": "prisma",
500
- // 其他
501
- "log": "log",
502
- "lock": "lock",
503
- "env": "settings",
504
- "graphql": "graphql",
505
- "gql": "graphql",
506
- "proto": "proto",
507
- "wasm": "webassembly",
508
- "zig": "zig",
509
- "nim": "nim",
510
- "nix": "nix",
511
- "hcl": "hcl",
512
- "tf": "terraform",
513
- "sol": "solidity",
514
- "ex": "elixir",
515
- "exs": "elixir",
516
- "erl": "erlang",
517
- "hrl": "erlang",
518
- "hs": "haskell",
519
- "lhs": "haskell",
520
- "ml": "ocaml",
521
- "mli": "ocaml",
522
- "clj": "clojure",
523
- "cljs": "clojure",
524
- "cljc": "clojure",
525
- "lisp": "lisp",
526
- "lsp": "lisp",
527
- "el": "lisp",
528
- "vim": "vim",
529
- "dockerfile": "docker"
530
- };
531
- var SPECIAL_FILES = {
532
- // Git
533
- ".gitignore": "git",
534
- ".gitattributes": "git",
535
- ".gitmodules": "git",
536
- ".gitkeep": "git",
537
- // 环境
538
- ".env": "settings",
539
- ".env.local": "settings",
540
- ".env.development": "settings",
541
- ".env.production": "settings",
542
- ".env.test": "settings",
543
- ".env.example": "settings",
544
- // Node/包管理
545
- "package.json": "nodejs",
546
- "package-lock.json": "npm",
547
- "yarn.lock": "yarn",
548
- ".yarnrc": "yarn",
549
- ".yarnrc.yml": "yarn",
550
- "pnpm-lock.yaml": "pnpm",
551
- ".pnpmfile.cjs": "pnpm",
552
- "bun.lockb": "bun",
553
- "bunfig.toml": "bun",
554
- // Python
555
- "requirements.txt": "python",
556
- "pipfile": "python",
557
- "pipfile.lock": "python",
558
- "pyproject.toml": "python",
559
- "poetry.lock": "python",
560
- "setup.py": "python",
561
- // Rust
562
- "cargo.toml": "rust",
563
- "cargo.lock": "rust",
564
- // Go
565
- "go.mod": "go-mod",
566
- "go.sum": "go-mod",
567
- "go.work": "go-mod",
568
- // PHP
569
- "composer.json": "php",
570
- "composer.lock": "php",
571
- // Ruby
572
- "gemfile": "gemfile",
573
- "gemfile.lock": "gemfile",
574
- "rakefile": "ruby",
575
- // Docker
576
- "dockerfile": "docker",
577
- "docker-compose.yml": "docker",
578
- "docker-compose.yaml": "docker",
579
- ".dockerignore": "docker",
580
- // 构建工具
581
- "makefile": "makefile",
582
- "gnumakefile": "makefile",
583
- "cmakelists.txt": "cmake",
584
- "build.gradle": "gradle",
585
- "build.gradle.kts": "gradle",
586
- "settings.gradle": "gradle",
587
- "pom.xml": "maven",
588
- // 配置
589
- "tsconfig.json": "tsconfig",
590
- "jsconfig.json": "jsconfig",
591
- ".prettierrc": "prettier",
592
- ".prettierrc.json": "prettier",
593
- ".prettierrc.js": "prettier",
594
- ".prettierignore": "prettier",
595
- "prettier.config.js": "prettier",
596
- ".eslintrc": "eslint",
597
- ".eslintrc.json": "eslint",
598
- ".eslintrc.js": "eslint",
599
- ".eslintignore": "eslint",
600
- "eslint.config.js": "eslint",
601
- "eslint.config.mjs": "eslint",
602
- ".editorconfig": "editorconfig",
603
- "vite.config.ts": "vite",
604
- "vite.config.js": "vite",
605
- "webpack.config.js": "webpack",
606
- "webpack.config.ts": "webpack",
607
- "rollup.config.js": "rollup",
608
- "rollup.config.ts": "rollup",
609
- "esbuild.config.js": "esbuild",
610
- "tailwind.config.js": "tailwindcss",
611
- "tailwind.config.ts": "tailwindcss",
612
- "postcss.config.js": "postcss",
613
- "postcss.config.cjs": "postcss",
614
- "babel.config.js": "babel",
615
- ".babelrc": "babel",
616
- "jest.config.js": "jest",
617
- "jest.config.ts": "jest",
618
- "vitest.config.ts": "vitest",
619
- "vitest.config.js": "vitest",
620
- "playwright.config.ts": "playwright",
621
- "playwright.config.js": "playwright",
622
- "cypress.config.ts": "cypress",
623
- "cypress.config.js": "cypress",
624
- ".swcrc": "swc",
625
- "swc.config.js": "swc",
626
- "turbo.json": "turborepo",
627
- "nx.json": "nx",
628
- "biome.json": "biome",
629
- ".nvmrc": "nodejs",
630
- ".node-version": "nodejs",
631
- // 框架配置
632
- "nuxt.config.ts": "nuxt",
633
- "nuxt.config.js": "nuxt",
634
- "next.config.js": "next",
635
- "next.config.mjs": "next",
636
- "next.config.ts": "next",
637
- "svelte.config.js": "svelte",
638
- "astro.config.mjs": "astro",
639
- "astro.config.ts": "astro",
640
- "vue.config.js": "vue-config",
641
- "angular.json": "angular",
642
- "nest-cli.json": "nest",
643
- "tauri.conf.json": "tauri",
644
- // CI/CD
645
- ".travis.yml": "travis",
646
- ".gitlab-ci.yml": "gitlab",
647
- "vercel.json": "vercel",
648
- "netlify.toml": "netlify",
649
- // 其他
650
- "license": "license",
651
- "license.md": "license",
652
- "license.txt": "license",
653
- "readme": "readme",
654
- "readme.md": "readme",
655
- "readme.txt": "readme",
656
- "changelog": "changelog",
657
- "changelog.md": "changelog",
658
- ".npmrc": "npm",
659
- ".npmignore": "npm",
660
- "robots.txt": "robots",
661
- ".htaccess": "nginx",
662
- "vagrantfile": "vagrant",
663
- ".stylelintrc": "stylelint",
664
- ".stylelintrc.json": "stylelint",
665
- "nodemon.json": "nodemon",
666
- ".huskyrc": "husky",
667
- "renovate.json": "renovate",
668
- ".snyk": "snyk",
669
- "deno.json": "deno",
670
- "deno.jsonc": "deno"
671
- };
672
- function getFileTypeIcon(fileName, fallbackType) {
673
- const lowerName = fileName.toLowerCase();
674
- if (SPECIAL_FILES[lowerName]) {
675
- const type = SPECIAL_FILES[lowerName];
676
- if (KNOWN_TYPES.has(type)) {
677
- return `material-icon-theme:${type}`;
678
- }
679
- }
680
- if (lowerName === "dockerfile" || lowerName.startsWith("dockerfile.")) {
681
- return "material-icon-theme:docker";
682
- }
683
- if (lowerName === ".env" || lowerName.startsWith(".env.")) {
684
- return "material-icon-theme:settings";
685
- }
686
- const lastDotIndex = fileName.lastIndexOf(".");
687
- const ext = lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1).toLowerCase() : "";
688
- if (ext === "ts" || ext === "js") {
689
- const baseName = fileName.substring(0, lastDotIndex).toLowerCase();
690
- if (baseName.endsWith(".d")) {
691
- return "material-icon-theme:typescript-def";
692
- }
693
- if (baseName.endsWith(".test") || baseName.endsWith(".spec")) {
694
- return ext === "ts" ? "material-icon-theme:test-ts" : "material-icon-theme:test-js";
695
- }
696
- }
697
- if (ext === "jsx" || ext === "tsx") {
698
- const baseName = fileName.substring(0, lastDotIndex).toLowerCase();
699
- if (baseName.endsWith(".test") || baseName.endsWith(".spec")) {
700
- return ext === "tsx" ? "material-icon-theme:test-ts" : "material-icon-theme:test-jsx";
701
- }
702
- }
703
- if (ext && EXT_MAP[ext]) {
704
- const type = EXT_MAP[ext];
705
- if (KNOWN_TYPES.has(type)) {
706
- return `material-icon-theme:${type}`;
707
- }
708
- }
709
- if (fallbackType) {
710
- return getFallbackIcon(fallbackType);
711
- }
712
- return "material-icon-theme:document";
713
- }
714
- function getFallbackIcon(type) {
715
- switch (type) {
716
- case FileType.IMAGE:
717
- return "material-icon-theme:image";
718
- case FileType.VIDEO:
719
- return "material-icon-theme:video";
720
- case FileType.MUSIC:
721
- return "material-icon-theme:audio";
722
- case FileType.CODE:
723
- return "material-icon-theme:javascript";
724
- case FileType.TEXT:
725
- return "material-icon-theme:document";
726
- case FileType.DOCUMENT:
727
- return "material-icon-theme:word";
728
- case FileType.PDF:
729
- return "material-icon-theme:pdf";
730
- case FileType.ARCHIVE:
731
- return "material-icon-theme:zip";
732
- case FileType.APPLICATION:
733
- return "material-icon-theme:exe";
734
- default:
735
- return "material-icon-theme:document";
736
- }
737
- }
738
-
739
- // src/utils/folderTypeIcon.ts
740
- var KNOWN_TYPES2 = /* @__PURE__ */ new Set([
741
- "admin",
742
- "android",
743
- "angular",
744
- "animation",
745
- "ansible",
746
- "api",
747
- "apollo",
748
- "app",
749
- "archive",
750
- "astro",
751
- "atom",
752
- "attachment",
753
- "audio",
754
- "aurelia",
755
- "aws",
756
- "azure-pipelines",
757
- "backup",
758
- "base",
759
- "batch",
760
- "benchmark",
761
- "bibliography",
762
- "bicep",
763
- "blender",
764
- "bloc",
765
- "bower",
766
- "buildkite",
767
- "cart",
768
- "changesets",
769
- "ci",
770
- "circleci",
771
- "class",
772
- "claude",
773
- "client",
774
- "cline",
775
- "cloud-functions",
776
- "cloudflare",
777
- "cluster",
778
- "cobol",
779
- "command",
780
- "components",
781
- "config",
782
- "connection",
783
- "console",
784
- "constant",
785
- "container",
786
- "content",
787
- "context",
788
- "contract",
789
- "controller",
790
- "core",
791
- "coverage",
792
- "css",
793
- "cue",
794
- "cursor",
795
- "custom",
796
- "cypress",
797
- "dal",
798
- "dart",
799
- "database",
800
- "debug",
801
- "decorators",
802
- "delta",
803
- "desktop",
804
- "directive",
805
- "dist",
806
- "docker",
807
- "docs",
808
- "download",
809
- "drizzle",
810
- "dump",
811
- "element",
812
- "enum",
813
- "environment",
814
- "error",
815
- "eslint",
816
- "event",
817
- "examples",
818
- "expo",
819
- "export",
820
- "fastlane",
821
- "favicon",
822
- "features",
823
- "filter",
824
- "firebase",
825
- "firestore",
826
- "flow",
827
- "flutter",
828
- "font",
829
- "forgejo",
830
- "functions",
831
- "gamemaker",
832
- "generator",
833
- "gh-workflows",
834
- "git",
835
- "gitea",
836
- "github",
837
- "gitlab",
838
- "global",
839
- "godot",
840
- "gradle",
841
- "graphql",
842
- "guard",
843
- "gulp",
844
- "helm",
845
- "helper",
846
- "home",
847
- "hook",
848
- "husky",
849
- "i18n",
850
- "images",
851
- "import",
852
- "include",
853
- "input",
854
- "intellij",
855
- "interceptor",
856
- "interface",
857
- "ios",
858
- "java",
859
- "javascript",
860
- "jinja",
861
- "job",
862
- "json",
863
- "jupyter",
864
- "keys",
865
- "kubernetes",
866
- "kusto",
867
- "layout",
868
- "lefthook",
869
- "less",
870
- "lib",
871
- "license",
872
- "link",
873
- "linux",
874
- "liquibase",
875
- "log",
876
- "lottie",
877
- "lua",
878
- "luau",
879
- "macos",
880
- "mail",
881
- "mappings",
882
- "markdown",
883
- "mercurial",
884
- "messages",
885
- "meta",
886
- "metro",
887
- "middleware",
888
- "migrations",
889
- "mjml",
890
- "mobile",
891
- "mock",
892
- "mojo",
893
- "molecule",
894
- "moon",
895
- "netlify",
896
- "next",
897
- "ngrx-store",
898
- "node",
899
- "nuxt",
900
- "obsidian",
901
- "organism",
902
- "other",
903
- "packages",
904
- "pdf",
905
- "pdm",
906
- "php",
907
- "phpmailer",
908
- "pipe",
909
- "plastic",
910
- "plugin",
911
- "policy",
912
- "powershell",
913
- "prisma",
914
- "private",
915
- "project",
916
- "prompts",
917
- "proto",
918
- "public",
919
- "python",
920
- "pytorch",
921
- "quasar",
922
- "queue",
923
- "react-components",
924
- "redux-reducer",
925
- "repository",
926
- "resolver",
927
- "resource",
928
- "review",
929
- "robot",
930
- "routes",
931
- "rules",
932
- "rust",
933
- "salt",
934
- "sandbox",
935
- "sass",
936
- "scala",
937
- "scons",
938
- "scripts",
939
- "secure",
940
- "seeders",
941
- "server",
942
- "serverless",
943
- "shader",
944
- "shared",
945
- "simulations",
946
- "snapcraft",
947
- "snippet",
948
- "src",
949
- "src-tauri",
950
- "stack",
951
- "stencil",
952
- "store",
953
- "storybook",
954
- "stylus",
955
- "sublime",
956
- "supabase",
957
- "svelte",
958
- "svg",
959
- "syntax",
960
- "target",
961
- "taskfile",
962
- "tasks",
963
- "television",
964
- "temp",
965
- "template",
966
- "terraform",
967
- "test",
968
- "theme",
969
- "toc",
970
- "tools",
971
- "trash",
972
- "trigger",
973
- "turborepo",
974
- "typescript",
975
- "ui",
976
- "unity",
977
- "update",
978
- "upload",
979
- "utils",
980
- "vercel",
981
- "verdaccio",
982
- "video",
983
- "views",
984
- "vm",
985
- "vscode",
986
- "vue",
987
- "vue-directives",
988
- "vuepress",
989
- "vuex-store",
990
- "wakatime",
991
- "webpack",
992
- "windows",
993
- "wordpress",
994
- "yarn",
995
- "zeabur"
996
- ]);
997
- var ALIASES = {
998
- // 复数/变体
999
- "tests": "test",
1000
- "__tests__": "test",
1001
- "__test__": "test",
1002
- "spec": "test",
1003
- "specs": "test",
1004
- "script": "scripts",
1005
- "configs": "config",
1006
- "configuration": "config",
1007
- "configurations": "config",
1008
- "route": "routes",
1009
- "routing": "routes",
1010
- "stories": "storybook",
1011
- "story": "storybook",
1012
- "templates": "template",
1013
- "themes": "theme",
1014
- "videos": "video",
1015
- "imgs": "images",
1016
- "img": "images",
1017
- "image": "images",
1018
- "fonts": "font",
1019
- "styles": "css",
1020
- "style": "css",
1021
- "styling": "css",
1022
- "stylesheets": "css",
1023
- "view": "views",
1024
- "pages": "views",
1025
- "page": "views",
1026
- "layouts": "layout",
1027
- "models": "database",
1028
- "model": "database",
1029
- "modules": "lib",
1030
- "module": "lib",
1031
- "mods": "lib",
1032
- "plugins": "plugin",
1033
- "addons": "plugin",
1034
- "extensions": "plugin",
1035
- "middlewares": "middleware",
1036
- "helpers": "helper",
1037
- "utilities": "utils",
1038
- "util": "utils",
1039
- "tool": "tools",
1040
- "tooling": "tools",
1041
- "resources": "resource",
1042
- "res": "resource",
1043
- "assets": "resource",
1044
- "asset": "resource",
1045
- "hooks": "hook",
1046
- "composables": "hook",
1047
- "mocks": "mock",
1048
- "__mocks__": "mock",
1049
- "fixtures": "mock",
1050
- "__fixtures__": "mock",
1051
- "logs": "log",
1052
- "uploads": "upload",
1053
- "function": "functions",
1054
- "func": "functions",
1055
- "fns": "functions",
1056
- "services": "server",
1057
- "service": "server",
1058
- "component": "components",
1059
- "comp": "components",
1060
- "comps": "components",
1061
- "controllers": "controller",
1062
- // 常见变体
1063
- "source": "src",
1064
- "sources": "src",
1065
- "distribution": "dist",
1066
- "build": "dist",
1067
- "builds": "dist",
1068
- "out": "dist",
1069
- "output": "dist",
1070
- "documentation": "docs",
1071
- "doc": "docs",
1072
- "document": "docs",
1073
- "documents": "docs",
1074
- "static": "public",
1075
- "statics": "public",
1076
- "publics": "public",
1077
- "libs": "lib",
1078
- "library": "lib",
1079
- "vendor": "lib",
1080
- "vendors": "lib",
1081
- "bin": "scripts",
1082
- "binaries": "scripts",
1083
- "tmp": "temp",
1084
- "temporary": "temp",
1085
- "cache": "temp",
1086
- "caches": "temp",
1087
- ".cache": "temp",
1088
- ".turbo": "temp",
1089
- "types": "typescript",
1090
- "@types": "typescript",
1091
- "typings": "typescript",
1092
- "dts": "typescript",
1093
- "locales": "i18n",
1094
- "locale": "i18n",
1095
- "lang": "i18n",
1096
- "languages": "i18n",
1097
- "translations": "i18n",
1098
- "db": "database",
1099
- "databases": "database",
1100
- "sql": "database",
1101
- "queries": "database",
1102
- "migration": "migrations",
1103
- "seeds": "seeders",
1104
- "seed": "seeders",
1105
- // 技术栈
1106
- ".vscode": "vscode",
1107
- ".github": "github",
1108
- ".gitlab": "gitlab",
1109
- ".circleci": "circleci",
1110
- ".husky": "husky",
1111
- ".docker": "docker",
1112
- "node_modules": "node",
1113
- "scss": "sass",
1114
- "renderer": "client",
1115
- "frontend": "client",
1116
- "web": "client",
1117
- "webapp": "client",
1118
- "website": "client",
1119
- "backend": "server",
1120
- "main": "server",
1121
- "preload": "scripts",
1122
- ".idea": "intellij",
1123
- ".git": "git",
1124
- "k8s": "kubernetes",
1125
- "kube": "kubernetes",
1126
- "mongo": "database",
1127
- "mongodb": "database",
1128
- "mysql": "database",
1129
- "postgres": "database",
1130
- "api": "api",
1131
- "apis": "api",
1132
- "interfaces": "interface",
1133
- "notebook": "jupyter",
1134
- "notebooks": "jupyter",
1135
- "ipynb": "jupyter",
1136
- "notification": "messages",
1137
- "notifications": "messages",
1138
- "env": "environment",
1139
- "envs": "environment",
1140
- "redux": "redux-reducer",
1141
- "store": "store",
1142
- "stores": "store",
1143
- "electron": "desktop",
1144
- "tauri": "src-tauri"
1145
- };
1146
- function getFolderTypeIcon(folderName) {
1147
- const name = (folderName || "").trim();
1148
- if (!name) return void 0;
1149
- const lower = name.replace(/[\\/]+$/, "").toLowerCase();
1150
- const standardName = ALIASES[lower] ?? lower;
1151
- if (KNOWN_TYPES2.has(standardName)) {
1152
- return `material-icon-theme:folder-${standardName}`;
1153
- }
1154
- return void 0;
1155
- }
1156
-
1157
- // src/components/FileIcon.tsx
1158
- import { jsx } from "react/jsx-runtime";
1159
- function FileIcon({ type, name, className = "", size = 24 }) {
1160
- const iconName = useMemo(() => {
1161
- if (type === FileType.FOLDER) {
1162
- const folderIcon = name ? getFolderTypeIcon(name) : void 0;
1163
- return folderIcon ?? "ic:round-folder";
1164
- }
1165
- if (name) {
1166
- return getFileTypeIcon(name, type);
1167
- }
1168
- switch (type) {
1169
- case FileType.IMAGE:
1170
- return "material-icon-theme:image";
1171
- case FileType.TEXT:
1172
- return "material-icon-theme:document";
1173
- case FileType.CODE:
1174
- return "material-icon-theme:javascript";
1175
- case FileType.MUSIC:
1176
- return "material-icon-theme:audio";
1177
- case FileType.VIDEO:
1178
- return "material-icon-theme:video";
1179
- case FileType.PDF:
1180
- return "material-icon-theme:pdf";
1181
- case FileType.DOCUMENT:
1182
- return "material-icon-theme:word";
1183
- case FileType.APPLICATION:
1184
- return "material-icon-theme:exe";
1185
- case FileType.ARCHIVE:
1186
- return "material-icon-theme:zip";
1187
- default:
1188
- return "material-icon-theme:document";
1189
- }
1190
- }, [type, name]);
1191
- const iconClass = useMemo(() => {
1192
- const base = "file-icon";
1193
- switch (type) {
1194
- case FileType.FOLDER:
1195
- return `${base} file-icon--folder`;
1196
- case FileType.IMAGE:
1197
- return `${base} file-icon--image`;
1198
- case FileType.TEXT:
1199
- return `${base} file-icon--text`;
1200
- case FileType.CODE:
1201
- return `${base} file-icon--code`;
1202
- case FileType.MUSIC:
1203
- return `${base} file-icon--music`;
1204
- case FileType.VIDEO:
1205
- return `${base} file-icon--video`;
1206
- case FileType.PDF:
1207
- case FileType.DOCUMENT:
1208
- return `${base} file-icon--pdf`;
1209
- case FileType.APPLICATION:
1210
- return `${base} file-icon--application`;
1211
- case FileType.ARCHIVE:
1212
- return `${base} file-icon--archive`;
1213
- default:
1214
- return `${base} file-icon--default`;
1215
- }
1216
- }, [type]);
1217
- return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(Icon, { icon: iconName, width: size, height: size, className: iconClass }) });
1218
- }
1219
-
1220
- // src/components/FileGrid.tsx
1221
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
1222
- function splitFileName(name, isFolder) {
1223
- if (isFolder) {
1224
- return { baseName: name, ext: "" };
1225
- }
1226
- const lastDot = name.lastIndexOf(".");
1227
- if (lastDot <= 0) {
1228
- return { baseName: name, ext: "" };
1229
- }
1230
- return {
1231
- baseName: name.substring(0, lastDot),
1232
- ext: name.substring(lastDot)
1233
- // 包含点号
1234
- };
1235
- }
1236
- function FileName({
1237
- name,
1238
- isFolder,
1239
- isSelected,
1240
- onClick
1241
- }) {
1242
- const { baseName, ext } = useMemo2(() => splitFileName(name, isFolder), [name, isFolder]);
1243
- return /* @__PURE__ */ jsx2(
1244
- "span",
1245
- {
1246
- onClick,
1247
- className: `file-grid-item-name ${isSelected ? "file-grid-item-name--selected" : ""}`,
1248
- title: name,
1249
- children: ext ? /* @__PURE__ */ jsxs(Fragment, { children: [
1250
- /* @__PURE__ */ jsx2("span", { className: "file-grid-item-name-base", children: baseName }),
1251
- /* @__PURE__ */ jsx2("span", { className: "file-grid-item-name-ext", children: ext })
1252
- ] }) : (
1253
- // 无扩展名(包含文件夹/无扩展名文件/隐藏文件等):允许两行并省略
1254
- /* @__PURE__ */ jsx2("span", { className: "file-grid-item-name-base file-grid-item-name-base--two-lines", children: baseName })
1255
- )
1256
- }
1257
- );
1258
- }
1259
- function FileGrid({
1260
- items,
1261
- selectedIds,
1262
- editingId,
1263
- dragOverId,
1264
- getAppIconUrl,
1265
- onSelect,
1266
- onOpen,
1267
- onContextMenu,
1268
- onContextMenuEmpty,
1269
- onNameClick,
1270
- onRename,
1271
- onRenameCancel,
1272
- onDragStart,
1273
- onDragOver,
1274
- onDragLeave,
1275
- onDrop,
1276
- onThumbnailError
1277
- }) {
1278
- const renameInputRef = useRef(null);
1279
- const handleEmptyContextMenu = (e) => {
1280
- const target = e.target;
1281
- if (!target.closest(".file-grid-item")) {
1282
- onContextMenuEmpty?.(e);
1283
- }
1284
- };
1285
- const hasThumbnail = (item) => {
1286
- if (item.type === FileType.APPLICATION && getAppIconUrl?.(item)) {
1287
- return true;
1288
- }
1289
- if (item.type === FileType.IMAGE) {
1290
- return !!item.thumbnailUrl;
1291
- }
1292
- if (item.type === FileType.VIDEO) {
1293
- return !!item.thumbnailUrl;
1294
- }
1295
- return false;
1296
- };
1297
- const handleVideoHover = (e, isHover) => {
1298
- const video = e.currentTarget;
1299
- if (isHover) {
1300
- video.play().catch(() => {
1301
- });
1302
- } else {
1303
- video.pause();
1304
- video.currentTime = 0;
1305
- }
1306
- };
1307
- const handleRename = (item, e) => {
1308
- const input = e.target;
1309
- const newName = input.value.trim();
1310
- if (newName && newName !== item.name) {
1311
- onRename?.(item, newName);
1312
- } else {
1313
- onRenameCancel?.(item);
1314
- }
1315
- };
1316
- const handleEnterKey = (e) => {
1317
- e.currentTarget.blur();
1318
- };
1319
- const handleEscapeKey = (e) => {
1320
- const input = e.currentTarget;
1321
- const item = items.find((i) => i.id === editingId);
1322
- if (item) {
1323
- input.value = item.name;
1324
- }
1325
- input.blur();
1326
- };
1327
- return /* @__PURE__ */ jsx2("div", { className: "file-grid", onContextMenu: (e) => {
1328
- e.preventDefault();
1329
- handleEmptyContextMenu(e);
1330
- }, children: items.map((item) => {
1331
- const isSelected = selectedIds.has(item.id);
1332
- const isEditing = editingId === item.id;
1333
- const isDragOver = dragOverId === item.id;
1334
- const hasThumb = hasThumbnail(item);
1335
- const appIconUrl = item.type === FileType.APPLICATION ? getAppIconUrl?.(item) : void 0;
1336
- let itemClassName = "file-grid-item";
1337
- if (isSelected && !isEditing) {
1338
- itemClassName += " file-grid-item--selected";
1339
- } else if (isDragOver) {
1340
- itemClassName += " file-grid-item--drag-over";
1341
- } else {
1342
- itemClassName += " file-grid-item--normal";
1343
- }
1344
- return /* @__PURE__ */ jsxs(
1345
- "div",
1346
- {
1347
- draggable: !isEditing,
1348
- onDragStart: (e) => onDragStart?.(e, item),
1349
- onDragOver: (e) => {
1350
- e.preventDefault();
1351
- onDragOver?.(e, item);
1352
- },
1353
- onDragLeave: (e) => onDragLeave?.(e),
1354
- onDrop: (e) => {
1355
- e.preventDefault();
1356
- onDrop?.(e, item);
1357
- },
1358
- onClick: (e) => {
1359
- e.stopPropagation();
1360
- onSelect?.(item, e);
1361
- },
1362
- onDoubleClick: (e) => {
1363
- e.stopPropagation();
1364
- onOpen?.(item);
1365
- },
1366
- onContextMenu: (e) => {
1367
- e.preventDefault();
1368
- e.stopPropagation();
1369
- onContextMenu?.(item, e);
1370
- },
1371
- className: itemClassName,
1372
- children: [
1373
- /* @__PURE__ */ jsxs("div", { className: "file-grid-item-icon", children: [
1374
- appIconUrl && /* @__PURE__ */ jsx2(
1375
- "img",
1376
- {
1377
- src: appIconUrl,
1378
- alt: item.name,
1379
- className: `file-grid-item-thumbnail file-grid-item-thumbnail--application ${isSelected && !isEditing ? "file-grid-item-thumbnail--selected" : ""}`
1380
- }
1381
- ),
1382
- !appIconUrl && item.type === FileType.VIDEO && item.thumbnailUrl && hasThumb && /* @__PURE__ */ jsxs("div", { className: "file-grid-item-thumbnail file-grid-item-thumbnail--video", children: [
1383
- /* @__PURE__ */ jsx2(
1384
- "img",
1385
- {
1386
- src: item.thumbnailUrl,
1387
- alt: item.name,
1388
- className: "file-grid-item-thumbnail",
1389
- onError: (e) => onThumbnailError?.(item, e)
1390
- }
1391
- ),
1392
- /* @__PURE__ */ jsx2("div", { className: "file-grid-item-video-play", children: /* @__PURE__ */ jsx2("div", { className: "file-grid-item-video-play-icon" }) })
1393
- ] }),
1394
- !appIconUrl && item.type === FileType.IMAGE && item.thumbnailUrl && hasThumb && /* @__PURE__ */ jsx2(
1395
- "img",
1396
- {
1397
- src: item.thumbnailUrl,
1398
- alt: item.name,
1399
- className: "file-grid-item-thumbnail",
1400
- onError: (e) => onThumbnailError?.(item, e)
1401
- }
1402
- ),
1403
- !appIconUrl && !hasThumb && /* @__PURE__ */ jsx2(FileIcon, { type: item.type, name: item.name, size: 48 })
1404
- ] }),
1405
- /* @__PURE__ */ jsx2("div", { className: "file-grid-item-name-wrapper", children: isEditing ? /* @__PURE__ */ jsx2(
1406
- "input",
1407
- {
1408
- ref: renameInputRef,
1409
- type: "text",
1410
- className: "file-grid-item-rename-input",
1411
- defaultValue: item.name,
1412
- onBlur: (e) => handleRename(item, e),
1413
- onKeyDown: (e) => {
1414
- if (e.key === "Enter") {
1415
- handleEnterKey(e);
1416
- } else if (e.key === "Escape") {
1417
- handleEscapeKey(e);
1418
- }
1419
- },
1420
- autoFocus: true
1421
- }
1422
- ) : /* @__PURE__ */ jsx2(
1423
- FileName,
1424
- {
1425
- name: item.name,
1426
- isFolder: item.type === FileType.FOLDER,
1427
- isSelected,
1428
- onClick: (e) => {
1429
- e.stopPropagation();
1430
- onNameClick?.(item, e);
1431
- }
1432
- }
1433
- ) })
1434
- ]
1435
- },
1436
- item.id
1437
- );
1438
- }) });
1439
- }
1440
-
1441
- // src/components/FileList.tsx
1442
- import { useRef as useRef2 } from "react";
1443
-
1444
- // src/components/SortIndicator.tsx
1445
- import { Icon as Icon2 } from "@iconify/react";
1446
- import { jsx as jsx3 } from "react/jsx-runtime";
1447
- function SortIndicator({ direction }) {
1448
- return /* @__PURE__ */ jsx3("span", { className: "sort-indicator", children: /* @__PURE__ */ jsx3(
1449
- Icon2,
1450
- {
1451
- icon: direction === "asc" ? "lucide:chevron-up" : "lucide:chevron-down",
1452
- width: 12,
1453
- height: 12
1454
- }
1455
- ) });
1456
- }
1457
-
1458
- // src/components/FileList.tsx
1459
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1460
- function getTypeLabel(type) {
1461
- const labels = {
1462
- [FileType.FOLDER]: "\u6587\u4EF6\u5939",
1463
- [FileType.FILE]: "\u6587\u4EF6",
1464
- [FileType.IMAGE]: "\u56FE\u7247",
1465
- [FileType.VIDEO]: "\u89C6\u9891",
1466
- [FileType.MUSIC]: "\u97F3\u9891",
1467
- [FileType.DOCUMENT]: "\u6587\u6863",
1468
- [FileType.CODE]: "\u4EE3\u7801",
1469
- [FileType.TEXT]: "\u6587\u672C",
1470
- [FileType.PDF]: "PDF",
1471
- [FileType.ARCHIVE]: "\u538B\u7F29\u5305",
1472
- [FileType.APPLICATION]: "\u5E94\u7528\u7A0B\u5E8F",
1473
- [FileType.UNKNOWN]: "\u672A\u77E5"
1474
- };
1475
- return labels[type] || type;
1476
- }
1477
- function FileList({
1478
- items,
1479
- selectedIds,
1480
- sortConfig,
1481
- editingId,
1482
- dragOverId,
1483
- onSelect,
1484
- onOpen,
1485
- onContextMenu,
1486
- onContextMenuEmpty,
1487
- onNameClick,
1488
- onRename,
1489
- onRenameCancel,
1490
- onSort,
1491
- onDragStart,
1492
- onDragOver,
1493
- onDragLeave,
1494
- onDrop
1495
- }) {
1496
- const renameInputRef = useRef2(null);
1497
- const handleEmptyContextMenu = (e) => {
1498
- const target = e.target;
1499
- if (!target.closest("tr")) {
1500
- onContextMenuEmpty?.(e);
1501
- }
1502
- };
1503
- const handleRename = (item, e) => {
1504
- const input = e.target;
1505
- const newName = input.value.trim();
1506
- if (newName && newName !== item.name) {
1507
- onRename?.(item, newName);
1508
- } else {
1509
- onRenameCancel?.(item);
1510
- }
1511
- };
1512
- const handleEnterKey = (e) => {
1513
- e.currentTarget.blur();
1514
- };
1515
- const handleEscapeKey = (e) => {
1516
- const input = e.currentTarget;
1517
- const item = items.find((i) => i.id === editingId);
1518
- if (item) {
1519
- input.value = item.name;
1520
- }
1521
- input.blur();
1522
- };
1523
- return /* @__PURE__ */ jsx4("div", { className: "file-list", onContextMenu: (e) => {
1524
- e.preventDefault();
1525
- handleEmptyContextMenu(e);
1526
- }, children: /* @__PURE__ */ jsxs2("table", { className: "file-list-table", children: [
1527
- /* @__PURE__ */ jsx4("thead", { className: "file-list-header", children: /* @__PURE__ */ jsxs2("tr", { children: [
1528
- /* @__PURE__ */ jsxs2(
1529
- "th",
1530
- {
1531
- className: "file-list-header-cell file-list-header-cell--name",
1532
- onClick: () => onSort?.("name"),
1533
- children: [
1534
- "\u540D\u79F0",
1535
- sortConfig?.field === "name" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1536
- ]
1537
- }
1538
- ),
1539
- /* @__PURE__ */ jsxs2(
1540
- "th",
1541
- {
1542
- className: "file-list-header-cell",
1543
- onClick: () => onSort?.("dateModified"),
1544
- children: [
1545
- "\u4FEE\u6539\u65E5\u671F",
1546
- sortConfig?.field === "dateModified" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1547
- ]
1548
- }
1549
- ),
1550
- /* @__PURE__ */ jsxs2(
1551
- "th",
1552
- {
1553
- className: "file-list-header-cell",
1554
- onClick: () => onSort?.("size"),
1555
- children: [
1556
- "\u5927\u5C0F",
1557
- sortConfig?.field === "size" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1558
- ]
1559
- }
1560
- ),
1561
- /* @__PURE__ */ jsxs2(
1562
- "th",
1563
- {
1564
- className: "file-list-header-cell",
1565
- onClick: () => onSort?.("type"),
1566
- children: [
1567
- "\u7C7B\u578B",
1568
- sortConfig?.field === "type" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1569
- ]
1570
- }
1571
- )
1572
- ] }) }),
1573
- /* @__PURE__ */ jsx4("tbody", { className: "file-list-body", children: items.map((item, index) => {
1574
- const isSelected = selectedIds.has(item.id);
1575
- const isEditing = editingId === item.id;
1576
- const isDragOver = dragOverId === item.id;
1577
- let rowClassName = "file-list-row";
1578
- if (isSelected) {
1579
- rowClassName += " file-list-row--selected";
1580
- } else if (isDragOver) {
1581
- rowClassName += " file-list-row--drag-over";
1582
- } else if (index % 2 === 0) {
1583
- rowClassName += " file-list-row--even";
1584
- } else {
1585
- rowClassName += " file-list-row--odd";
1586
- }
1587
- return /* @__PURE__ */ jsxs2(
1588
- "tr",
1589
- {
1590
- draggable: !isEditing,
1591
- onDragStart: (e) => onDragStart?.(e, item),
1592
- onDragOver: (e) => {
1593
- e.preventDefault();
1594
- onDragOver?.(e, item);
1595
- },
1596
- onDragLeave: (e) => onDragLeave?.(e),
1597
- onDrop: (e) => {
1598
- e.preventDefault();
1599
- onDrop?.(e, item);
1600
- },
1601
- onClick: (e) => {
1602
- e.stopPropagation();
1603
- onSelect?.(item, e);
1604
- },
1605
- onDoubleClick: (e) => {
1606
- e.stopPropagation();
1607
- onOpen?.(item);
1608
- },
1609
- onContextMenu: (e) => {
1610
- e.preventDefault();
1611
- e.stopPropagation();
1612
- onContextMenu?.(item, e);
1613
- },
1614
- className: rowClassName,
1615
- children: [
1616
- /* @__PURE__ */ jsxs2("td", { className: `file-list-cell file-list-cell--name ${isSelected ? "file-list-cell--selected" : ""}`, children: [
1617
- /* @__PURE__ */ jsx4(FileIcon, { type: item.type, name: item.name, size: 16 }),
1618
- isEditing ? /* @__PURE__ */ jsx4(
1619
- "input",
1620
- {
1621
- ref: renameInputRef,
1622
- type: "text",
1623
- className: "file-list-rename-input",
1624
- defaultValue: item.name,
1625
- onBlur: (e) => handleRename(item, e),
1626
- onKeyDown: (e) => {
1627
- if (e.key === "Enter") {
1628
- handleEnterKey(e);
1629
- } else if (e.key === "Escape") {
1630
- handleEscapeKey(e);
1631
- }
1632
- },
1633
- autoFocus: true
1634
- }
1635
- ) : /* @__PURE__ */ jsx4(
1636
- "span",
1637
- {
1638
- onClick: (e) => {
1639
- e.stopPropagation();
1640
- onNameClick?.(item, e);
1641
- },
1642
- className: `file-list-name ${isSelected ? "file-list-name--selected" : ""}`,
1643
- children: item.name
1644
- }
1645
- )
1646
- ] }),
1647
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell ${isSelected ? "file-list-cell--selected" : ""}`, children: item.dateModified || "--" }),
1648
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell file-list-cell--size ${isSelected ? "file-list-cell--selected" : ""}`, children: item.size || "--" }),
1649
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell ${isSelected ? "file-list-cell--selected" : ""}`, children: getTypeLabel(item.type) })
1650
- ]
1651
- },
1652
- item.id
1653
- );
1654
- }) })
1655
- ] }) });
1656
- }
1657
-
1658
- // src/components/FileListView.tsx
1659
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1660
- var FileListView = forwardRef(
1661
- ({
1662
- items,
1663
- viewMode = "grid",
1664
- loading = false,
1665
- adapter,
1666
- currentPath,
1667
- getAppIconUrl,
1668
- onOpen,
1669
- onSelectionChange,
1670
- onContextMenu,
1671
- onContextMenuEmpty,
1672
- onRename,
1673
- onSortChange,
1674
- onMove
1675
- }, ref) => {
1676
- const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
1677
- const [editingId, setEditingId] = useState(null);
1678
- const [dragOverId, setDragOverId] = useState(null);
1679
- const [sortConfig, setSortConfig] = useState({
1680
- field: "name",
1681
- direction: "asc"
1682
- });
1683
- const selectedItems = items.filter((item) => selectedIds.has(item.id));
1684
- const handleSelect = useCallback(
1685
- (item, e) => {
1686
- if (e.metaKey || e.ctrlKey) {
1687
- setSelectedIds((prev) => {
1688
- const newSet = new Set(prev);
1689
- if (newSet.has(item.id)) {
1690
- newSet.delete(item.id);
1691
- } else {
1692
- newSet.add(item.id);
1693
- }
1694
- const newItems = items.filter((i) => newSet.has(i.id));
1695
- onSelectionChange?.(newSet, newItems);
1696
- return newSet;
1697
- });
1698
- } else if (e.shiftKey && selectedIds.size > 0) {
1699
- const lastId = Array.from(selectedIds).pop();
1700
- const lastIndex = items.findIndex((i) => i.id === lastId);
1701
- const currentIndex = items.findIndex((i) => i.id === item.id);
1702
- const start = Math.min(lastIndex, currentIndex);
1703
- const end = Math.max(lastIndex, currentIndex);
1704
- const newSet = /* @__PURE__ */ new Set();
1705
- for (let i = start; i <= end; i++) {
1706
- newSet.add(items[i].id);
1707
- }
1708
- setSelectedIds(newSet);
1709
- const newItems = items.filter((i) => newSet.has(i.id));
1710
- onSelectionChange?.(newSet, newItems);
1711
- } else {
1712
- const newSet = /* @__PURE__ */ new Set([item.id]);
1713
- setSelectedIds(newSet);
1714
- onSelectionChange?.(newSet, [item]);
1715
- }
1716
- },
1717
- [items, selectedIds, onSelectionChange]
1718
- );
1719
- const handleEmptyClick = useCallback(
1720
- (e) => {
1721
- if (e.target === e.currentTarget) {
1722
- clearSelection();
1723
- }
1724
- },
1725
- []
1726
- );
1727
- const clearSelection = useCallback(() => {
1728
- setSelectedIds(/* @__PURE__ */ new Set());
1729
- onSelectionChange?.(/* @__PURE__ */ new Set(), []);
1730
- }, [onSelectionChange]);
1731
- const handleOpen = useCallback(
1732
- (item) => {
1733
- onOpen?.(item);
1734
- },
1735
- [onOpen]
1736
- );
1737
- const handleContextMenu = useCallback(
1738
- (item, e) => {
1739
- if (!selectedIds.has(item.id)) {
1740
- const newSet = /* @__PURE__ */ new Set([item.id]);
1741
- setSelectedIds(newSet);
1742
- onSelectionChange?.(newSet, [item]);
1743
- }
1744
- onContextMenu?.(e, item);
1745
- },
1746
- [selectedIds, onSelectionChange, onContextMenu]
1747
- );
1748
- const handleEmptyContextMenu = useCallback(
1749
- (e) => {
1750
- const target = e.target;
1751
- if (!target.closest(".file-grid-item") && !target.closest(".file-list-row")) {
1752
- clearSelection();
1753
- onContextMenuEmpty?.(e);
1754
- }
1755
- },
1756
- [clearSelection, onContextMenuEmpty]
1757
- );
1758
- const handleEmptyContextMenuFromChild = useCallback(
1759
- (e) => {
1760
- clearSelection();
1761
- onContextMenuEmpty?.(e);
1762
- },
1763
- [clearSelection, onContextMenuEmpty]
1764
- );
1765
- const handleNameClick = useCallback(
1766
- (item, e) => {
1767
- if (selectedIds.has(item.id) && selectedIds.size === 1) {
1768
- setTimeout(() => {
1769
- if (selectedIds.has(item.id)) {
1770
- setEditingId(item.id);
1771
- }
1772
- }, 500);
1773
- }
1774
- },
1775
- [selectedIds]
1776
- );
1777
- const handleRename = useCallback(
1778
- (item, newName) => {
1779
- if (newName && newName !== item.name) {
1780
- onRename?.(item, newName);
1781
- }
1782
- setEditingId(null);
1783
- },
1784
- [onRename]
1785
- );
1786
- const handleRenameCancel = useCallback(() => {
1787
- setEditingId(null);
1788
- }, []);
1789
- const handleSort = useCallback(
1790
- (field) => {
1791
- setSortConfig((prev) => {
1792
- const newConfig = prev.field === field ? { ...prev, direction: prev.direction === "asc" ? "desc" : "asc" } : { field, direction: "asc" };
1793
- onSortChange?.(newConfig);
1794
- return newConfig;
1795
- });
1796
- },
1797
- [onSortChange]
1798
- );
1799
- const handleDragStart = useCallback(
1800
- (e, item) => {
1801
- if (!selectedIds.has(item.id)) {
1802
- const newSet = /* @__PURE__ */ new Set([item.id]);
1803
- setSelectedIds(newSet);
1804
- onSelectionChange?.(newSet, [item]);
1805
- }
1806
- e.dataTransfer.setData(
1807
- "text/plain",
1808
- JSON.stringify([...selectedIds])
1809
- );
1810
- },
1811
- [selectedIds, onSelectionChange]
1812
- );
1813
- const handleDragOver = useCallback(
1814
- (e, item) => {
1815
- if (item.type === FileType.FOLDER && !selectedIds.has(item.id)) {
1816
- setDragOverId(item.id);
1817
- }
1818
- },
1819
- [selectedIds]
1820
- );
1821
- const handleDragLeave = useCallback(() => {
1822
- setDragOverId(null);
1823
- }, []);
1824
- const handleDrop = useCallback(
1825
- (e, targetItem) => {
1826
- setDragOverId(null);
1827
- if (targetItem.type !== FileType.FOLDER) return;
1828
- const data = e.dataTransfer.getData("text/plain");
1829
- if (!data) return;
1830
- try {
1831
- const draggedIds = JSON.parse(data);
1832
- if (draggedIds.includes(targetItem.id)) return;
1833
- onMove?.(draggedIds, targetItem.id);
1834
- clearSelection();
1835
- } catch (error) {
1836
- console.error("\u62D6\u62FD\u89E3\u6790\u5931\u8D25:", error);
1837
- }
1838
- },
1839
- [onMove, clearSelection]
1840
- );
1841
- const startRename = useCallback((id) => {
1842
- setEditingId(id);
1843
- }, []);
1844
- const selectAll = useCallback(() => {
1845
- const newSet = new Set(items.map((i) => i.id));
1846
- setSelectedIds(newSet);
1847
- onSelectionChange?.(newSet, items);
1848
- }, [items, onSelectionChange]);
1849
- useImperativeHandle(
1850
- ref,
1851
- () => ({
1852
- clearSelection,
1853
- startRename,
1854
- selectAll,
1855
- selectedIds,
1856
- selectedItems
1857
- }),
1858
- [selectedIds, selectedItems, clearSelection, startRename, selectAll]
1859
- );
1860
- return /* @__PURE__ */ jsxs3(
1861
- "div",
1862
- {
1863
- className: "file-list-view",
1864
- onClick: handleEmptyClick,
1865
- onContextMenu: (e) => {
1866
- e.preventDefault();
1867
- handleEmptyContextMenu(e);
1868
- },
1869
- children: [
1870
- loading && /* @__PURE__ */ jsxs3("div", { className: "file-list-view-loading", children: [
1871
- /* @__PURE__ */ jsx5("div", { className: "file-list-view-spinner" }),
1872
- /* @__PURE__ */ jsx5("p", { children: "\u52A0\u8F7D\u4E2D..." })
1873
- ] }),
1874
- !loading && items.length === 0 && /* @__PURE__ */ jsxs3("div", { className: "file-list-view-empty", children: [
1875
- /* @__PURE__ */ jsx5(Icon3, { icon: "lucide:folder-open", width: 64, height: 64, className: "file-list-view-empty-icon" }),
1876
- /* @__PURE__ */ jsx5("p", { children: "\u6587\u4EF6\u5939\u4E3A\u7A7A" })
1877
- ] }),
1878
- !loading && items.length > 0 && viewMode === "grid" && /* @__PURE__ */ jsx5(
1879
- FileGrid,
1880
- {
1881
- items,
1882
- selectedIds,
1883
- editingId,
1884
- dragOverId,
1885
- getAppIconUrl,
1886
- onSelect: handleSelect,
1887
- onOpen: handleOpen,
1888
- onContextMenu: handleContextMenu,
1889
- onContextMenuEmpty: handleEmptyContextMenuFromChild,
1890
- onNameClick: handleNameClick,
1891
- onRename: handleRename,
1892
- onRenameCancel: handleRenameCancel,
1893
- onDragStart: handleDragStart,
1894
- onDragOver: handleDragOver,
1895
- onDragLeave: handleDragLeave,
1896
- onDrop: handleDrop
1897
- }
1898
- ),
1899
- !loading && items.length > 0 && viewMode === "list" && /* @__PURE__ */ jsx5(
1900
- FileList,
1901
- {
1902
- items,
1903
- selectedIds,
1904
- editingId,
1905
- dragOverId,
1906
- sortConfig,
1907
- onSelect: handleSelect,
1908
- onOpen: handleOpen,
1909
- onContextMenu: handleContextMenu,
1910
- onContextMenuEmpty: handleEmptyContextMenuFromChild,
1911
- onNameClick: handleNameClick,
1912
- onRename: handleRename,
1913
- onRenameCancel: handleRenameCancel,
1914
- onSort: handleSort,
1915
- onDragStart: handleDragStart,
1916
- onDragOver: handleDragOver,
1917
- onDragLeave: handleDragLeave,
1918
- onDrop: handleDrop
1919
- }
1920
- )
1921
- ]
1922
- }
1923
- );
1924
- }
1925
- );
1926
- FileListView.displayName = "FileListView";
1927
-
1928
- // src/components/FileSidebar.tsx
1929
- import { Icon as Icon4 } from "@iconify/react";
1930
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1931
- function FileSidebar({ sections, activeId, onNavigate }) {
1932
- const handleNavigate = (item) => {
1933
- onNavigate?.(item);
1934
- };
1935
- const getIconName = (iconName) => {
1936
- if (!iconName) return "mdi:folder";
1937
- if (iconName.includes(":")) return iconName;
1938
- return `lucide:${iconName.toLowerCase()}`;
1939
- };
1940
- return /* @__PURE__ */ jsx6("div", { className: "file-sidebar", children: sections.map((section) => /* @__PURE__ */ jsxs4("div", { className: "file-sidebar-section", children: [
1941
- /* @__PURE__ */ jsx6("div", { className: "file-sidebar-section-title", children: section.title }),
1942
- /* @__PURE__ */ jsx6("ul", { className: "file-sidebar-list", children: section.items.map((item) => {
1943
- const isActive = activeId === item.id;
1944
- return /* @__PURE__ */ jsxs4(
1945
- "li",
1946
- {
1947
- onClick: () => handleNavigate(item),
1948
- className: `file-sidebar-item ${isActive ? "file-sidebar-item--active" : ""}`,
1949
- children: [
1950
- /* @__PURE__ */ jsx6(
1951
- Icon4,
1952
- {
1953
- icon: getIconName(item.icon),
1954
- width: 18,
1955
- height: 18,
1956
- className: isActive ? "file-sidebar-item-icon--active" : "file-sidebar-item-icon"
1957
- }
1958
- ),
1959
- /* @__PURE__ */ jsx6("span", { children: item.label })
1960
- ]
1961
- },
1962
- item.id
1963
- );
1964
- }) })
1965
- ] }, section.id)) });
1966
- }
1967
-
1968
- // src/components/Toolbar.tsx
1969
- import { Icon as Icon6 } from "@iconify/react";
1970
-
1971
- // src/components/Breadcrumb.tsx
1972
- import { Icon as Icon5 } from "@iconify/react";
1973
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1974
- function Breadcrumb({ items, onNavigate }) {
1975
- const handleClick = (item, index) => {
1976
- if (index < items.length - 1) {
1977
- onNavigate?.(item, index);
1978
- }
1979
- };
1980
- return /* @__PURE__ */ jsx7("div", { className: "file-breadcrumb", children: items.map((item, index) => /* @__PURE__ */ jsxs5("span", { className: "file-breadcrumb-item", children: [
1981
- /* @__PURE__ */ jsx7(
1982
- "span",
1983
- {
1984
- onClick: () => handleClick(item, index),
1985
- className: `file-breadcrumb-link ${index === items.length - 1 ? "file-breadcrumb-link--current" : ""}`,
1986
- children: item.name
1987
- }
1988
- ),
1989
- index < items.length - 1 && /* @__PURE__ */ jsx7(Icon5, { icon: "lucide:chevron-right", width: 14, height: 14, className: "file-breadcrumb-separator" })
1990
- ] }, item.id)) });
1991
- }
1992
-
1993
- // src/components/Toolbar.tsx
1994
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1995
- function Toolbar({
1996
- canGoBack = false,
1997
- canGoForward = false,
1998
- breadcrumbs = [],
1999
- viewMode = "grid",
2000
- searchQuery = "",
2001
- showSearch = false,
2002
- showViewToggle = true,
2003
- draggable = false,
2004
- onBack,
2005
- onForward,
2006
- onBreadcrumbNavigate,
2007
- onViewModeChange,
2008
- onSearchQueryChange,
2009
- children,
2010
- breadcrumbSlot,
2011
- actionsSlot
2012
- }) {
2013
- return /* @__PURE__ */ jsxs6(
2014
- "div",
2015
- {
2016
- className: `file-toolbar ${draggable ? "file-toolbar--draggable" : ""}`,
2017
- children: [
2018
- /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-nav", children: [
2019
- /* @__PURE__ */ jsx8(
2020
- "button",
2021
- {
2022
- className: "file-toolbar-button",
2023
- onClick: onBack,
2024
- disabled: !canGoBack,
2025
- title: "\u540E\u9000",
2026
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:chevron-left", width: 18, height: 18 })
2027
- }
2028
- ),
2029
- /* @__PURE__ */ jsx8(
2030
- "button",
2031
- {
2032
- className: "file-toolbar-button",
2033
- onClick: onForward,
2034
- disabled: !canGoForward,
2035
- title: "\u524D\u8FDB",
2036
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:chevron-right", width: 18, height: 18 })
2037
- }
2038
- )
2039
- ] }),
2040
- /* @__PURE__ */ jsx8("div", { className: "file-toolbar-breadcrumb", children: breadcrumbSlot || breadcrumbs.length > 0 && /* @__PURE__ */ jsx8(
2041
- Breadcrumb,
2042
- {
2043
- items: breadcrumbs,
2044
- onNavigate: onBreadcrumbNavigate
2045
- }
2046
- ) }),
2047
- children && /* @__PURE__ */ jsx8("div", { className: "file-toolbar-custom", children }),
2048
- /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-actions", children: [
2049
- showSearch && /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-search", children: [
2050
- /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:search", width: 16, height: 16, className: "file-toolbar-search-icon" }),
2051
- /* @__PURE__ */ jsx8(
2052
- "input",
2053
- {
2054
- type: "text",
2055
- value: searchQuery,
2056
- onChange: (e) => onSearchQueryChange?.(e.target.value),
2057
- placeholder: "\u641C\u7D22",
2058
- className: "file-toolbar-search-input"
2059
- }
2060
- )
2061
- ] }),
2062
- showViewToggle && /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-view-toggle", children: [
2063
- /* @__PURE__ */ jsx8(
2064
- "button",
2065
- {
2066
- onClick: () => onViewModeChange?.("grid"),
2067
- className: `file-toolbar-button ${viewMode === "grid" ? "file-toolbar-button--active" : ""}`,
2068
- title: "\u7F51\u683C\u89C6\u56FE",
2069
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:layout-grid", width: 18, height: 18 })
2070
- }
2071
- ),
2072
- /* @__PURE__ */ jsx8(
2073
- "button",
2074
- {
2075
- onClick: () => onViewModeChange?.("list"),
2076
- className: `file-toolbar-button ${viewMode === "list" ? "file-toolbar-button--active" : ""}`,
2077
- title: "\u5217\u8868\u89C6\u56FE",
2078
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:list", width: 18, height: 18 })
2079
- }
2080
- )
2081
- ] }),
2082
- actionsSlot
2083
- ] })
2084
- ]
2085
- }
2086
- );
2087
- }
2088
-
2089
- // src/components/StatusBar.tsx
2090
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2091
- function StatusBar({ itemCount = 0, selectedCount = 0, children }) {
2092
- return /* @__PURE__ */ jsx9("div", { className: "file-status-bar", children: children || /* @__PURE__ */ jsxs7(Fragment2, { children: [
2093
- /* @__PURE__ */ jsxs7("span", { children: [
2094
- itemCount,
2095
- " \u4E2A\u9879\u76EE"
2096
- ] }),
2097
- selectedCount > 0 && /* @__PURE__ */ jsxs7("span", { children: [
2098
- " \u2022 \u5DF2\u9009\u62E9 ",
2099
- selectedCount,
2100
- " \u4E2A"
2101
- ] })
2102
- ] }) });
2103
- }
2104
-
2105
- // src/components/ContextMenu.tsx
2106
- import { createPortal } from "react-dom";
2107
- import { useMemo as useMemo3, useEffect, useRef as useRef3, useCallback as useCallback2, useState as useState2 } from "react";
2108
- import { Icon as Icon7 } from "@iconify/react";
2109
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2110
- var MARGIN = 8;
2111
- var MENU_WIDTH = 220;
2112
- var MENU_ITEM_HEIGHT = 32;
2113
- var SEPARATOR_HEIGHT = 9;
2114
- var MENU_PADDING = 8;
2115
- var SUBMENU_GAP = 0;
2116
- function estimateMenuHeight(items) {
2117
- let height = MENU_PADDING;
2118
- for (const item of items) {
2119
- height += item.separator ? SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT;
2120
- }
2121
- return height;
2122
- }
2123
- function calculateMenuPosition(clickX, clickY, menuHeight) {
2124
- const viewportWidth = window.innerWidth;
2125
- const viewportHeight = window.innerHeight;
2126
- let adjustedX = clickX;
2127
- let adjustedY = clickY;
2128
- const spaceRight = viewportWidth - clickX;
2129
- const spaceLeft = clickX;
2130
- if (spaceRight < MENU_WIDTH + MARGIN) {
2131
- if (spaceLeft >= MENU_WIDTH + MARGIN) {
2132
- adjustedX = clickX - MENU_WIDTH;
2133
- } else {
2134
- if (spaceRight > spaceLeft) {
2135
- adjustedX = viewportWidth - MENU_WIDTH - MARGIN;
2136
- } else {
2137
- adjustedX = MARGIN;
2138
- }
2139
- }
2140
- }
2141
- const spaceBottom = viewportHeight - clickY;
2142
- const spaceTop = clickY;
2143
- if (spaceBottom < menuHeight + MARGIN) {
2144
- if (spaceTop >= menuHeight + MARGIN) {
2145
- adjustedY = clickY - menuHeight;
2146
- } else {
2147
- if (spaceBottom > spaceTop) {
2148
- adjustedY = viewportHeight - menuHeight - MARGIN;
2149
- } else {
2150
- adjustedY = MARGIN;
2151
- }
2152
- }
2153
- }
2154
- adjustedX = Math.max(MARGIN, Math.min(adjustedX, viewportWidth - MENU_WIDTH - MARGIN));
2155
- adjustedY = Math.max(MARGIN, Math.min(adjustedY, viewportHeight - menuHeight - MARGIN));
2156
- return { x: adjustedX, y: adjustedY };
2157
- }
2158
- function calculateSubmenuPosition(parentRect, submenuHeight) {
2159
- const viewportWidth = window.innerWidth;
2160
- const viewportHeight = window.innerHeight;
2161
- const spaceRight = viewportWidth - parentRect.right;
2162
- const spaceLeft = parentRect.left;
2163
- let submenuX;
2164
- let submenuY;
2165
- if (spaceRight >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {
2166
- submenuX = parentRect.right + SUBMENU_GAP;
2167
- } else if (spaceLeft >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {
2168
- submenuX = parentRect.left - MENU_WIDTH - SUBMENU_GAP;
2169
- } else {
2170
- if (spaceRight > spaceLeft) {
2171
- submenuX = viewportWidth - MENU_WIDTH - MARGIN;
2172
- } else {
2173
- submenuX = MARGIN;
2174
- }
2175
- }
2176
- submenuY = parentRect.top;
2177
- if (submenuY + submenuHeight > viewportHeight - MARGIN) {
2178
- submenuY = viewportHeight - submenuHeight - MARGIN;
2179
- }
2180
- if (submenuY < MARGIN) {
2181
- submenuY = MARGIN;
2182
- }
2183
- return { x: submenuX, y: submenuY };
2184
- }
2185
- function ContextMenu({
2186
- visible,
2187
- x,
2188
- y,
2189
- options,
2190
- onClose,
2191
- onSelect
2192
- }) {
2193
- const menuRef = useRef3(null);
2194
- const [hoveredItemId, setHoveredItemId] = useState2(null);
2195
- const [submenuPosition, setSubmenuPosition] = useState2(null);
2196
- const itemRefs = useRef3(/* @__PURE__ */ new Map());
2197
- const position = useMemo3(() => {
2198
- const estimatedHeight = estimateMenuHeight(options);
2199
- return calculateMenuPosition(x, y, estimatedHeight);
2200
- }, [x, y, options]);
2201
- const menuStyle = useMemo3(
2202
- () => ({
2203
- left: `${position.x}px`,
2204
- top: `${position.y}px`
2205
- }),
2206
- [position]
2207
- );
2208
- const hoveredItem = useMemo3(() => {
2209
- if (!hoveredItemId) return null;
2210
- return options.find((opt) => opt.id === hoveredItemId && opt.children && opt.children.length > 0);
2211
- }, [hoveredItemId, options]);
2212
- useEffect(() => {
2213
- if (!hoveredItemId || !hoveredItem) {
2214
- setSubmenuPosition(null);
2215
- return;
2216
- }
2217
- const itemEl = itemRefs.current.get(hoveredItemId);
2218
- if (!itemEl) {
2219
- setSubmenuPosition(null);
2220
- return;
2221
- }
2222
- const rect = itemEl.getBoundingClientRect();
2223
- const submenuHeight = estimateMenuHeight(hoveredItem.children || []);
2224
- const pos = calculateSubmenuPosition(rect, submenuHeight);
2225
- setSubmenuPosition(pos);
2226
- }, [hoveredItemId, hoveredItem]);
2227
- useEffect(() => {
2228
- if (!visible) return;
2229
- const handleClickOutside = (e) => {
2230
- const target = e.target;
2231
- const menuContainer = document.querySelector(".context-menu-container");
2232
- if (menuContainer && menuContainer.contains(target)) {
2233
- return;
2234
- }
2235
- onClose?.();
2236
- };
2237
- const handleEscape = (e) => {
2238
- if (e.key === "Escape") {
2239
- onClose?.();
2240
- }
2241
- };
2242
- document.addEventListener("mousedown", handleClickOutside);
2243
- document.addEventListener("keydown", handleEscape);
2244
- return () => {
2245
- document.removeEventListener("mousedown", handleClickOutside);
2246
- document.removeEventListener("keydown", handleEscape);
2247
- };
2248
- }, [visible, onClose]);
2249
- useEffect(() => {
2250
- if (!visible) {
2251
- setHoveredItemId(null);
2252
- setSubmenuPosition(null);
2253
- }
2254
- }, [visible]);
2255
- const renderIcon = (iconName) => {
2256
- if (!iconName) return null;
2257
- return /* @__PURE__ */ jsx10(Icon7, { icon: iconName, width: 16, height: 16, className: "context-menu-item-icon" });
2258
- };
2259
- const handleOptionClick = useCallback2(
2260
- (option) => {
2261
- if (option.disabled) return;
2262
- if (option.children && option.children.length > 0) {
2263
- return;
2264
- }
2265
- if (option.action) {
2266
- option.action();
2267
- }
2268
- onSelect?.(option);
2269
- onClose?.();
2270
- },
2271
- [onClose, onSelect]
2272
- );
2273
- const handleItemMouseEnter = useCallback2((option) => {
2274
- if (option.children && option.children.length > 0) {
2275
- setHoveredItemId(option.id);
2276
- } else {
2277
- setHoveredItemId(null);
2278
- }
2279
- }, []);
2280
- if (!visible) return null;
2281
- return createPortal(
2282
- /* @__PURE__ */ jsxs8("div", { className: "context-menu-container", children: [
2283
- /* @__PURE__ */ jsx10("div", { ref: menuRef, className: "context-menu", style: menuStyle, children: options.map((option, index) => {
2284
- if (option.separator) {
2285
- return /* @__PURE__ */ jsx10("div", { className: "context-menu-separator" }, index);
2286
- }
2287
- const hasChildren = option.children && option.children.length > 0;
2288
- const isHovered = hoveredItemId === option.id;
2289
- return /* @__PURE__ */ jsxs8(
2290
- "div",
2291
- {
2292
- ref: (el) => {
2293
- if (el) {
2294
- itemRefs.current.set(option.id, el);
2295
- } else {
2296
- itemRefs.current.delete(option.id);
2297
- }
2298
- },
2299
- className: `context-menu-item ${option.disabled ? "context-menu-item--disabled" : ""} ${option.danger ? "context-menu-item--danger" : ""} ${hasChildren ? "context-menu-item--has-children" : ""} ${isHovered ? "context-menu-item--active" : ""}`,
2300
- onClick: () => handleOptionClick(option),
2301
- onMouseEnter: () => handleItemMouseEnter(option),
2302
- children: [
2303
- option.icon && renderIcon(option.icon),
2304
- /* @__PURE__ */ jsx10("span", { className: "context-menu-item-label", children: option.label }),
2305
- option.checked && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:check", width: 14, height: 14, className: "context-menu-item-check" }),
2306
- option.shortcut && !hasChildren && /* @__PURE__ */ jsx10("span", { className: "context-menu-item-shortcut", children: option.shortcut }),
2307
- hasChildren && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:chevron-right", width: 14, height: 14, className: "context-menu-item-arrow" })
2308
- ]
2309
- },
2310
- option.id || index
2311
- );
2312
- }) }),
2313
- hoveredItem && submenuPosition && /* @__PURE__ */ jsx10(
2314
- "div",
2315
- {
2316
- className: "context-menu context-menu-submenu",
2317
- style: {
2318
- left: `${submenuPosition.x}px`,
2319
- top: `${submenuPosition.y}px`
2320
- },
2321
- onMouseEnter: () => setHoveredItemId(hoveredItem.id),
2322
- onMouseLeave: () => setHoveredItemId(null),
2323
- children: hoveredItem.children.map((child, childIndex) => {
2324
- if (child.separator) {
2325
- return /* @__PURE__ */ jsx10("div", { className: "context-menu-separator" }, `child-sep-${childIndex}`);
2326
- }
2327
- return /* @__PURE__ */ jsxs8(
2328
- "div",
2329
- {
2330
- className: `context-menu-item ${child.disabled ? "context-menu-item--disabled" : ""} ${child.danger ? "context-menu-item--danger" : ""}`,
2331
- onClick: () => handleOptionClick(child),
2332
- children: [
2333
- child.icon && renderIcon(child.icon),
2334
- /* @__PURE__ */ jsx10("span", { className: "context-menu-item-label", children: child.label }),
2335
- child.checked && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:check", width: 14, height: 14, className: "context-menu-item-check" }),
2336
- child.shortcut && /* @__PURE__ */ jsx10("span", { className: "context-menu-item-shortcut", children: child.shortcut })
2337
- ]
2338
- },
2339
- child.id || childIndex
2340
- );
2341
- })
2342
- }
2343
- )
2344
- ] }),
2345
- document.body
2346
- );
2347
- }
2348
-
2349
- // src/components/Window.tsx
2350
- import { createPortal as createPortal2 } from "react-dom";
2351
- import { useMemo as useMemo4, useRef as useRef4, useEffect as useEffect4 } from "react";
2352
- import { Icon as Icon8 } from "@iconify/react";
2353
-
2354
- // src/hooks/useWindowDrag.ts
2355
- import { useState as useState3, useCallback as useCallback3, useEffect as useEffect2 } from "react";
2356
- function useWindowDrag() {
2357
- const [position, setPosition] = useState3({ x: 0, y: 0 });
2358
- const [isDragging, setIsDragging] = useState3(false);
2359
- const handleMouseMove = useCallback3((e) => {
2360
- if (!isDragging) return;
2361
- setPosition((prev) => ({
2362
- x: prev.x + e.movementX,
2363
- y: prev.y + e.movementY
2364
- }));
2365
- }, [isDragging]);
2366
- const handleMouseUp = useCallback3(() => {
2367
- setIsDragging(false);
2368
- }, []);
2369
- const startDrag = useCallback3((e) => {
2370
- const target = e.target;
2371
- if (target.closest(".draggable-area") && !target.closest("button")) {
2372
- e.preventDefault();
2373
- setIsDragging(true);
2374
- }
2375
- }, []);
2376
- useEffect2(() => {
2377
- if (isDragging) {
2378
- window.addEventListener("mousemove", handleMouseMove);
2379
- window.addEventListener("mouseup", handleMouseUp);
2380
- return () => {
2381
- window.removeEventListener("mousemove", handleMouseMove);
2382
- window.removeEventListener("mouseup", handleMouseUp);
2383
- };
2384
- }
2385
- }, [isDragging, handleMouseMove, handleMouseUp]);
2386
- return {
2387
- position,
2388
- isDragging,
2389
- startDrag
2390
- };
2391
- }
2392
-
2393
- // src/hooks/useWindowResize.ts
2394
- import { useState as useState4, useCallback as useCallback4, useEffect as useEffect3 } from "react";
2395
- function useWindowResize(initialWidth, initialHeight, minWidth, minHeight, maxWidth, maxHeight) {
2396
- const [width, setWidth] = useState4(initialWidth);
2397
- const [height, setHeight] = useState4(initialHeight);
2398
- const [isResizing, setIsResizing] = useState4(false);
2399
- const [resizeDirection, setResizeDirection] = useState4(null);
2400
- const [startX, setStartX] = useState4(0);
2401
- const [startY, setStartY] = useState4(0);
2402
- const [startWidth, setStartWidth] = useState4(0);
2403
- const [startHeight, setStartHeight] = useState4(0);
2404
- const handleMouseMove = useCallback4((e) => {
2405
- if (!isResizing || !resizeDirection) return;
2406
- const deltaX = e.clientX - startX;
2407
- const deltaY = e.clientY - startY;
2408
- let newWidth = startWidth;
2409
- let newHeight = startHeight;
2410
- const direction = resizeDirection;
2411
- if (direction.includes("e")) {
2412
- newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);
2413
- } else if (direction.includes("w")) {
2414
- newWidth = Math.min(Math.max(startWidth - deltaX, minWidth), maxWidth);
2415
- }
2416
- if (direction.includes("s")) {
2417
- newHeight = Math.min(Math.max(startHeight + deltaY, minHeight), maxHeight);
2418
- } else if (direction.includes("n")) {
2419
- newHeight = Math.min(Math.max(startHeight - deltaY, minHeight), maxHeight);
2420
- }
2421
- setWidth(newWidth);
2422
- setHeight(newHeight);
2423
- }, [isResizing, resizeDirection, startX, startY, startWidth, startHeight, minWidth, minHeight, maxWidth, maxHeight]);
2424
- const handleMouseUp = useCallback4(() => {
2425
- setIsResizing(false);
2426
- setResizeDirection(null);
2427
- }, []);
2428
- const startResize = useCallback4((e, direction, currentWidth, currentHeight) => {
2429
- e.preventDefault();
2430
- e.stopPropagation();
2431
- setIsResizing(true);
2432
- setResizeDirection(direction);
2433
- setStartX(e.clientX);
2434
- setStartY(e.clientY);
2435
- setStartWidth(currentWidth);
2436
- setStartHeight(currentHeight);
2437
- }, []);
2438
- const getCursorForDirection = useCallback4((direction) => {
2439
- const cursors = {
2440
- n: "n-resize",
2441
- s: "s-resize",
2442
- e: "e-resize",
2443
- w: "w-resize",
2444
- ne: "ne-resize",
2445
- nw: "nw-resize",
2446
- se: "se-resize",
2447
- sw: "sw-resize"
2448
- };
2449
- return cursors[direction];
2450
- }, []);
2451
- useEffect3(() => {
2452
- if (isResizing) {
2453
- window.addEventListener("mousemove", handleMouseMove);
2454
- window.addEventListener("mouseup", handleMouseUp);
2455
- document.body.style.cursor = getCursorForDirection(resizeDirection || "se");
2456
- document.body.style.userSelect = "none";
2457
- return () => {
2458
- window.removeEventListener("mousemove", handleMouseMove);
2459
- window.removeEventListener("mouseup", handleMouseUp);
2460
- document.body.style.cursor = "";
2461
- document.body.style.userSelect = "";
2462
- };
2463
- }
2464
- }, [isResizing, resizeDirection, handleMouseMove, handleMouseUp, getCursorForDirection]);
2465
- return {
2466
- width,
2467
- height,
2468
- isResizing,
2469
- startResize
2470
- };
2471
- }
2472
-
2473
- // src/components/Window.tsx
2474
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2475
- function Window({
2476
- title,
2477
- showTitleBar = true,
2478
- showMinimize = false,
2479
- showMaximize = false,
2480
- draggable = true,
2481
- resizable = true,
2482
- closeOnBackdrop = true,
2483
- width = "auto",
2484
- height = "auto",
2485
- minWidth = 300,
2486
- minHeight = 200,
2487
- maxWidth = "80vw",
2488
- maxHeight = "80vh",
2489
- fitContent = false,
2490
- onClose,
2491
- onMinimize,
2492
- onMaximize,
2493
- children,
2494
- titleSlot,
2495
- actionsSlot
2496
- }) {
2497
- const windowContainerRef = useRef4(null);
2498
- const windowDrag = draggable ? useWindowDrag() : null;
2499
- const isAutoSize = useMemo4(() => {
2500
- return fitContent || width === "auto" || width === "fit-content" || height === "auto" || height === "fit-content";
2501
- }, [fitContent, width, height]);
2502
- const getInitialSize = () => {
2503
- if (isAutoSize) {
2504
- return { initialWidth: 0, initialHeight: 0 };
2505
- }
2506
- const defaultWidth = 600;
2507
- const defaultHeight = 500;
2508
- let initialWidth2 = defaultWidth;
2509
- let initialHeight2 = defaultHeight;
2510
- if (width !== "auto" && width !== "fit-content") {
2511
- initialWidth2 = typeof width === "number" ? width : parseInt(width);
2512
- }
2513
- if (height !== "auto" && height !== "fit-content") {
2514
- initialHeight2 = typeof height === "number" ? height : parseInt(height);
2515
- }
2516
- return { initialWidth: initialWidth2, initialHeight: initialHeight2 };
2517
- };
2518
- const parseSize = (size, defaultPx) => {
2519
- if (typeof size === "number") return size;
2520
- if (typeof size === "string") {
2521
- if (size.endsWith("px")) return parseInt(size);
2522
- if (size.endsWith("vw"))
2523
- return parseInt(size) / 100 * window.innerWidth;
2524
- if (size.endsWith("vh"))
2525
- return parseInt(size) / 100 * window.innerHeight;
2526
- }
2527
- return defaultPx;
2528
- };
2529
- const { initialWidth, initialHeight } = getInitialSize();
2530
- const minW = parseSize(minWidth, 500);
2531
- const minH = parseSize(minHeight, 350);
2532
- const maxW = parseSize(maxWidth, window.innerWidth * 0.8);
2533
- const maxH = parseSize(maxHeight, window.innerHeight * 0.8);
2534
- const windowResize = resizable ? useWindowResize(initialWidth, initialHeight, minW, minH, maxW, maxH) : null;
2535
- const windowStyle = useMemo4(() => {
2536
- const baseStyle = {
2537
- left: "50%",
2538
- top: "50%"
2539
- };
2540
- let translateX = "-50%";
2541
- let translateY = "-50%";
2542
- if (draggable && windowDrag) {
2543
- translateX = `calc(-50% + ${windowDrag.position.x}px)`;
2544
- translateY = `calc(-50% + ${windowDrag.position.y}px)`;
2545
- }
2546
- baseStyle.transform = `translate(${translateX}, ${translateY})`;
2547
- baseStyle.transformOrigin = "center center";
2548
- if (isAutoSize) {
2549
- if (resizable && windowResize && windowResize.width > 0) {
2550
- baseStyle.width = `${windowResize.width}px`;
2551
- baseStyle.height = `${windowResize.height}px`;
2552
- }
2553
- } else {
2554
- if (resizable && windowResize) {
2555
- baseStyle.width = `${windowResize.width}px`;
2556
- baseStyle.height = `${windowResize.height}px`;
2557
- } else {
2558
- if (width !== "auto" && width !== "fit-content") {
2559
- baseStyle.width = typeof width === "number" ? `${width}px` : width;
2560
- }
2561
- if (height !== "auto" && height !== "fit-content") {
2562
- baseStyle.height = typeof height === "number" ? `${height}px` : height;
2563
- }
2564
- }
2565
- }
2566
- if (minWidth) {
2567
- baseStyle.minWidth = typeof minWidth === "number" ? `${minWidth}px` : minWidth;
2568
- }
2569
- if (minHeight) {
2570
- baseStyle.minHeight = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
2571
- }
2572
- if (maxWidth) {
2573
- baseStyle.maxWidth = typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth;
2574
- }
2575
- if (maxHeight) {
2576
- baseStyle.maxHeight = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
2577
- }
2578
- return baseStyle;
2579
- }, [
2580
- draggable,
2581
- windowDrag,
2582
- isAutoSize,
2583
- resizable,
2584
- windowResize,
2585
- width,
2586
- height,
2587
- minWidth,
2588
- minHeight,
2589
- maxWidth,
2590
- maxHeight
2591
- ]);
2592
- const handleBackdropClick = (e) => {
2593
- if (closeOnBackdrop && e.target === e.currentTarget) {
2594
- onClose?.();
2595
- }
2596
- };
2597
- const handleDragStart = (e) => {
2598
- if (draggable && windowDrag) {
2599
- windowDrag.startDrag(e);
2600
- }
2601
- };
2602
- const handleResizeStart = (e, direction) => {
2603
- if (!resizable || !windowResize || !windowContainerRef.current) return;
2604
- const rect = windowContainerRef.current.getBoundingClientRect();
2605
- const currentWidth = rect.width;
2606
- const currentHeight = rect.height;
2607
- windowResize.startResize(e, direction, currentWidth, currentHeight);
2608
- };
2609
- useEffect4(() => {
2610
- const handleEsc = (e) => {
2611
- if (e.key === "Escape") {
2612
- e.preventDefault();
2613
- onClose?.();
2614
- }
2615
- };
2616
- window.addEventListener("keydown", handleEsc);
2617
- return () => {
2618
- window.removeEventListener("keydown", handleEsc);
2619
- };
2620
- }, [onClose]);
2621
- return createPortal2(
2622
- /* @__PURE__ */ jsx11("div", { className: "window-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs9(
2623
- "div",
2624
- {
2625
- ref: windowContainerRef,
2626
- className: "window-container",
2627
- style: windowStyle,
2628
- onClick: (e) => e.stopPropagation(),
2629
- children: [
2630
- showTitleBar && /* @__PURE__ */ jsxs9(
2631
- "div",
2632
- {
2633
- className: "window-title-bar draggable-area",
2634
- onMouseDown: handleDragStart,
2635
- children: [
2636
- /* @__PURE__ */ jsxs9("div", { className: "window-controls", children: [
2637
- /* @__PURE__ */ jsx11(
2638
- "button",
2639
- {
2640
- onClick: (e) => {
2641
- e.stopPropagation();
2642
- onClose?.();
2643
- },
2644
- className: "window-control-button window-control-button--close",
2645
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:x", width: 7, height: 7, className: "window-control-icon" })
2646
- }
2647
- ),
2648
- showMinimize && /* @__PURE__ */ jsx11(
2649
- "button",
2650
- {
2651
- onClick: (e) => {
2652
- e.stopPropagation();
2653
- onMinimize?.();
2654
- },
2655
- className: "window-control-button window-control-button--minimize",
2656
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:minus", width: 7, height: 7, className: "window-control-icon" })
2657
- }
2658
- ),
2659
- showMaximize && /* @__PURE__ */ jsx11(
2660
- "button",
2661
- {
2662
- onClick: (e) => {
2663
- e.stopPropagation();
2664
- onMaximize?.();
2665
- },
2666
- className: "window-control-button window-control-button--maximize",
2667
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:maximize-2", width: 7, height: 7, className: "window-control-icon" })
2668
- }
2669
- )
2670
- ] }),
2671
- /* @__PURE__ */ jsx11("div", { className: "window-title-info", children: titleSlot || /* @__PURE__ */ jsx11("span", { className: "window-title-text", children: title }) }),
2672
- /* @__PURE__ */ jsx11("div", { className: "window-title-actions", children: actionsSlot })
2673
- ]
2674
- }
2675
- ),
2676
- /* @__PURE__ */ jsx11("div", { className: "window-content", children }),
2677
- resizable && /* @__PURE__ */ jsxs9(Fragment3, { children: [
2678
- /* @__PURE__ */ jsx11(
2679
- "div",
2680
- {
2681
- className: "window-resize-handle window-resize-handle--n",
2682
- onMouseDown: (e) => handleResizeStart(e, "n")
2683
- }
2684
- ),
2685
- /* @__PURE__ */ jsx11(
2686
- "div",
2687
- {
2688
- className: "window-resize-handle window-resize-handle--s",
2689
- onMouseDown: (e) => handleResizeStart(e, "s")
2690
- }
2691
- ),
2692
- /* @__PURE__ */ jsx11(
2693
- "div",
2694
- {
2695
- className: "window-resize-handle window-resize-handle--e",
2696
- onMouseDown: (e) => handleResizeStart(e, "e")
2697
- }
2698
- ),
2699
- /* @__PURE__ */ jsx11(
2700
- "div",
2701
- {
2702
- className: "window-resize-handle window-resize-handle--w",
2703
- onMouseDown: (e) => handleResizeStart(e, "w")
2704
- }
2705
- ),
2706
- /* @__PURE__ */ jsx11(
2707
- "div",
2708
- {
2709
- className: "window-resize-handle window-resize-handle--ne",
2710
- onMouseDown: (e) => handleResizeStart(e, "ne")
2711
- }
2712
- ),
2713
- /* @__PURE__ */ jsx11(
2714
- "div",
2715
- {
2716
- className: "window-resize-handle window-resize-handle--nw",
2717
- onMouseDown: (e) => handleResizeStart(e, "nw")
2718
- }
2719
- ),
2720
- /* @__PURE__ */ jsx11(
2721
- "div",
2722
- {
2723
- className: "window-resize-handle window-resize-handle--se",
2724
- onMouseDown: (e) => handleResizeStart(e, "se")
2725
- }
2726
- ),
2727
- /* @__PURE__ */ jsx11(
2728
- "div",
2729
- {
2730
- className: "window-resize-handle window-resize-handle--sw",
2731
- onMouseDown: (e) => handleResizeStart(e, "sw")
2732
- }
2733
- )
2734
- ] })
2735
- ]
2736
- }
2737
- ) }),
2738
- document.body
2739
- );
2740
- }
2741
-
2742
- // src/components/CompressDialog.tsx
2743
- import { useState as useState6, useMemo as useMemo5, useEffect as useEffect5 } from "react";
2744
- import { createPortal as createPortal3 } from "react-dom";
2745
- import { Icon as Icon9 } from "@iconify/react";
2746
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2747
- var FORMAT_OPTIONS = [
2748
- { value: "zip", label: "ZIP", ext: ".zip" },
2749
- { value: "tgz", label: "TAR.GZ (gzip)", ext: ".tar.gz" },
2750
- { value: "tarbz2", label: "TAR.BZ2 (bzip2)", ext: ".tar.bz2" },
2751
- { value: "tar", label: "TAR (\u65E0\u538B\u7F29)", ext: ".tar" }
2752
- ];
2753
- var LEVEL_OPTIONS = [
2754
- { value: "fast", label: "\u5FEB\u901F", desc: "\u538B\u7F29\u901F\u5EA6\u5FEB\uFF0C\u6587\u4EF6\u8F83\u5927" },
2755
- { value: "normal", label: "\u6807\u51C6", desc: "\u5E73\u8861\u901F\u5EA6\u548C\u5927\u5C0F" },
2756
- { value: "best", label: "\u6700\u4F73", desc: "\u6587\u4EF6\u6700\u5C0F\uFF0C\u901F\u5EA6\u8F83\u6162" }
2757
- ];
2758
- function CompressDialog({
2759
- visible,
2760
- filePaths,
2761
- outputDir,
2762
- onConfirm,
2763
- onCancel
2764
- }) {
2765
- const [format, setFormat] = useState6("zip");
2766
- const [level, setLevel] = useState6("normal");
2767
- const [outputName, setOutputName] = useState6("");
2768
- const [deleteSource, setDeleteSource] = useState6(false);
2769
- const [password, setPassword] = useState6("");
2770
- const [showPassword, setShowPassword] = useState6(false);
2771
- const defaultOutputName = useMemo5(() => {
2772
- if (filePaths.length === 0) return "archive";
2773
- if (filePaths.length === 1) {
2774
- const name = filePaths[0].split("/").pop() || "archive";
2775
- return name.replace(/\.[^.]+$/, "");
2776
- }
2777
- return "\u538B\u7F29\u6587\u4EF6";
2778
- }, [filePaths]);
2779
- useEffect5(() => {
2780
- if (visible) {
2781
- setOutputName(defaultOutputName);
2782
- setFormat("zip");
2783
- setLevel("normal");
2784
- setDeleteSource(false);
2785
- setPassword("");
2786
- }
2787
- }, [visible, defaultOutputName]);
2788
- const currentExt = FORMAT_OPTIONS.find((f) => f.value === format)?.ext || ".zip";
2789
- const fullOutputPath = `${outputDir}/${outputName}${currentExt}`;
2790
- const handleConfirm = () => {
2791
- onConfirm({
2792
- format,
2793
- level,
2794
- outputName: outputName + currentExt,
2795
- deleteSource
2796
- });
2797
- };
2798
- const supportsPassword = false;
2799
- if (!visible) return null;
2800
- return createPortal3(
2801
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-overlay", onClick: onCancel, children: /* @__PURE__ */ jsxs10("div", { className: "compress-dialog", onClick: (e) => e.stopPropagation(), children: [
2802
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-header", children: [
2803
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-title", children: [
2804
- /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:archive", width: 20, height: 20 }),
2805
- /* @__PURE__ */ jsx12("span", { children: "\u538B\u7F29\u6587\u4EF6" })
2806
- ] }),
2807
- /* @__PURE__ */ jsx12("button", { className: "compress-dialog-close", onClick: onCancel, children: /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:x", width: 18, height: 18 }) })
2808
- ] }),
2809
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-content", children: [
2810
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-info", children: [
2811
- /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:file-archive", width: 16, height: 16 }),
2812
- /* @__PURE__ */ jsx12("span", { children: filePaths.length === 1 ? filePaths[0].split("/").pop() : `${filePaths.length} \u4E2A\u9879\u76EE` })
2813
- ] }),
2814
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2815
- /* @__PURE__ */ jsx12("label", { children: "\u6587\u4EF6\u540D" }),
2816
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-input-group", children: [
2817
- /* @__PURE__ */ jsx12(
2818
- "input",
2819
- {
2820
- type: "text",
2821
- value: outputName,
2822
- onChange: (e) => setOutputName(e.target.value),
2823
- placeholder: "\u8F93\u5165\u6587\u4EF6\u540D"
2824
- }
2825
- ),
2826
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-ext", children: currentExt })
2827
- ] })
2828
- ] }),
2829
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2830
- /* @__PURE__ */ jsx12("label", { children: "\u538B\u7F29\u683C\u5F0F" }),
2831
- /* @__PURE__ */ jsx12("select", { value: format, onChange: (e) => setFormat(e.target.value), children: FORMAT_OPTIONS.map((opt) => /* @__PURE__ */ jsx12("option", { value: opt.value, children: opt.label }, opt.value)) })
2832
- ] }),
2833
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2834
- /* @__PURE__ */ jsx12("label", { children: "\u538B\u7F29\u7EA7\u522B" }),
2835
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-levels", children: LEVEL_OPTIONS.map((opt) => /* @__PURE__ */ jsxs10("label", { className: "compress-dialog-level", children: [
2836
- /* @__PURE__ */ jsx12(
2837
- "input",
2838
- {
2839
- type: "radio",
2840
- name: "level",
2841
- value: opt.value,
2842
- checked: level === opt.value,
2843
- onChange: () => setLevel(opt.value)
2844
- }
2845
- ),
2846
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-level-label", children: opt.label }),
2847
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-level-desc", children: opt.desc })
2848
- ] }, opt.value)) })
2849
- ] }),
2850
- supportsPassword && /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2851
- /* @__PURE__ */ jsx12("label", { children: "\u5BC6\u7801\u4FDD\u62A4\uFF08\u53EF\u9009\uFF09" }),
2852
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-input-group", children: [
2853
- /* @__PURE__ */ jsx12(
2854
- "input",
2855
- {
2856
- type: showPassword ? "text" : "password",
2857
- value: password,
2858
- onChange: (e) => setPassword(e.target.value),
2859
- placeholder: "\u8BBE\u7F6E\u5BC6\u7801"
2860
- }
2861
- ),
2862
- /* @__PURE__ */ jsx12(
2863
- "button",
2864
- {
2865
- type: "button",
2866
- className: "compress-dialog-toggle-password",
2867
- onClick: () => setShowPassword(!showPassword),
2868
- children: showPassword ? "\u9690\u85CF" : "\u663E\u793A"
2869
- }
2870
- )
2871
- ] })
2872
- ] }),
2873
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-field compress-dialog-checkbox", children: /* @__PURE__ */ jsxs10("label", { children: [
2874
- /* @__PURE__ */ jsx12(
2875
- "input",
2876
- {
2877
- type: "checkbox",
2878
- checked: deleteSource,
2879
- onChange: (e) => setDeleteSource(e.target.checked)
2880
- }
2881
- ),
2882
- /* @__PURE__ */ jsx12("span", { children: "\u538B\u7F29\u540E\u5220\u9664\u6E90\u6587\u4EF6" })
2883
- ] }) }),
2884
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-preview", children: [
2885
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-preview-label", children: "\u8F93\u51FA\u4F4D\u7F6E:" }),
2886
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-preview-path", children: fullOutputPath })
2887
- ] })
2888
- ] }),
2889
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-footer", children: [
2890
- /* @__PURE__ */ jsx12("button", { className: "compress-dialog-btn compress-dialog-btn-cancel", onClick: onCancel, children: "\u53D6\u6D88" }),
2891
- /* @__PURE__ */ jsx12(
2892
- "button",
2893
- {
2894
- className: "compress-dialog-btn compress-dialog-btn-confirm",
2895
- onClick: handleConfirm,
2896
- disabled: !outputName.trim(),
2897
- children: "\u538B\u7F29"
2898
- }
2899
- )
2900
- ] })
2901
- ] }) }),
2902
- document.body
2903
- );
2904
- }
2905
-
2906
- // src/components/ProgressDialog.tsx
2907
- import { createPortal as createPortal4 } from "react-dom";
2908
- import { Icon as Icon10 } from "@iconify/react";
2909
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2910
- function ProgressDialog({
2911
- visible,
2912
- progress,
2913
- onCancel,
2914
- onClose,
2915
- onOpenFolder
2916
- }) {
2917
- const { type, status, percent, currentFile, processedCount, totalCount, error, outputPath } = progress;
2918
- const title = type === "compress" ? "\u538B\u7F29\u6587\u4EF6" : "\u89E3\u538B\u6587\u4EF6";
2919
- const isCompleted = status === "success" || status === "error";
2920
- const StatusIcon = () => {
2921
- switch (status) {
2922
- case "processing":
2923
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:loader-2", width: 24, height: 24, className: "progress-dialog-icon-spin" });
2924
- case "success":
2925
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:check-circle", width: 24, height: 24, className: "progress-dialog-icon-success" });
2926
- case "error":
2927
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:x-circle", width: 24, height: 24, className: "progress-dialog-icon-error" });
2928
- default:
2929
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:archive", width: 24, height: 24 });
2930
- }
2931
- };
2932
- const getStatusText = () => {
2933
- switch (status) {
2934
- case "pending":
2935
- return "\u51C6\u5907\u4E2D...";
2936
- case "processing":
2937
- return type === "compress" ? "\u6B63\u5728\u538B\u7F29..." : "\u6B63\u5728\u89E3\u538B...";
2938
- case "success":
2939
- return type === "compress" ? "\u538B\u7F29\u5B8C\u6210" : "\u89E3\u538B\u5B8C\u6210";
2940
- case "error":
2941
- return "\u64CD\u4F5C\u5931\u8D25";
2942
- default:
2943
- return "";
2944
- }
2945
- };
2946
- const handleClose = () => {
2947
- if (isCompleted) {
2948
- onClose?.();
2949
- } else {
2950
- onCancel?.();
2951
- }
2952
- };
2953
- if (!visible) return null;
2954
- return createPortal4(
2955
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-overlay", children: /* @__PURE__ */ jsxs11("div", { className: "progress-dialog", children: [
2956
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-header", children: [
2957
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-title", children: [
2958
- /* @__PURE__ */ jsx13(StatusIcon, {}),
2959
- /* @__PURE__ */ jsx13("span", { children: title })
2960
- ] }),
2961
- isCompleted && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-close", onClick: handleClose, children: /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:x", width: 18, height: 18 }) })
2962
- ] }),
2963
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-content", children: [
2964
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-status", children: getStatusText() }),
2965
- status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-bar-container", children: [
2966
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-bar", children: /* @__PURE__ */ jsx13(
2967
- "div",
2968
- {
2969
- className: "progress-dialog-bar-fill",
2970
- style: { width: `${percent}%` }
2971
- }
2972
- ) }),
2973
- /* @__PURE__ */ jsxs11("span", { className: "progress-dialog-percent", children: [
2974
- percent,
2975
- "%"
2976
- ] })
2977
- ] }),
2978
- currentFile && status === "processing" && /* @__PURE__ */ jsx13("div", { className: "progress-dialog-current-file", children: currentFile }),
2979
- totalCount && totalCount > 0 && status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-count", children: [
2980
- processedCount || 0,
2981
- " / ",
2982
- totalCount,
2983
- " \u4E2A\u6587\u4EF6"
2984
- ] }),
2985
- error && /* @__PURE__ */ jsx13("div", { className: "progress-dialog-error", children: error }),
2986
- status === "success" && outputPath && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-output", children: [
2987
- /* @__PURE__ */ jsx13("span", { className: "progress-dialog-output-label", children: "\u8F93\u51FA\u4F4D\u7F6E:" }),
2988
- /* @__PURE__ */ jsx13("span", { className: "progress-dialog-output-path", children: outputPath })
2989
- ] })
2990
- ] }),
2991
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-footer", children: [
2992
- status === "processing" && onCancel && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-btn progress-dialog-btn-cancel", onClick: onCancel, children: "\u53D6\u6D88" }),
2993
- status === "success" && outputPath && onOpenFolder && /* @__PURE__ */ jsxs11(
2994
- "button",
2995
- {
2996
- className: "progress-dialog-btn progress-dialog-btn-folder",
2997
- onClick: () => onOpenFolder(outputPath),
2998
- children: [
2999
- /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:folder-open", width: 16, height: 16 }),
3000
- "\u6253\u5F00\u6587\u4EF6\u5939"
3001
- ]
3002
- }
3003
- ),
3004
- isCompleted && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-btn progress-dialog-btn-close", onClick: handleClose, children: "\u5173\u95ED" })
3005
- ] })
3006
- ] }) }),
3007
- document.body
3008
- );
3009
- }
3010
-
3011
- // src/components/FileInfoDialog.tsx
3012
- import React from "react";
3013
- import { Icon as Icon11 } from "@iconify/react";
3014
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3015
- function getFileIcon(type, name) {
3016
- if (type === FileType.FOLDER) {
3017
- return /* @__PURE__ */ jsx14(Icon11, { icon: "ic:round-folder", width: 48, height: 48, className: "file-info-icon" });
3018
- }
3019
- if (name) {
3020
- const iconName2 = getFileTypeIcon(name, type);
3021
- return /* @__PURE__ */ jsx14(Icon11, { icon: iconName2, width: 48, height: 48, className: "file-info-icon" });
3022
- }
3023
- const iconMap = {
3024
- [FileType.IMAGE]: "material-icon-theme:image",
3025
- [FileType.VIDEO]: "material-icon-theme:video",
3026
- [FileType.MUSIC]: "material-icon-theme:audio",
3027
- [FileType.DOCUMENT]: "material-icon-theme:word",
3028
- [FileType.CODE]: "material-icon-theme:javascript",
3029
- [FileType.ARCHIVE]: "material-icon-theme:zip",
3030
- [FileType.PDF]: "material-icon-theme:pdf",
3031
- [FileType.TEXT]: "material-icon-theme:document",
3032
- [FileType.APPLICATION]: "material-icon-theme:exe"
3033
- };
3034
- const iconName = iconMap[type] || "material-icon-theme:document";
3035
- return /* @__PURE__ */ jsx14(Icon11, { icon: iconName, width: 48, height: 48, className: "file-info-icon" });
3036
- }
3037
- function getFileTypeName(type, extension) {
3038
- switch (type) {
3039
- case FileType.FOLDER:
3040
- return "\u6587\u4EF6\u5939";
3041
- case FileType.IMAGE:
3042
- return `\u56FE\u7247${extension ? ` (${extension.toUpperCase()})` : ""}`;
3043
- case FileType.VIDEO:
3044
- return `\u89C6\u9891${extension ? ` (${extension.toUpperCase()})` : ""}`;
3045
- case FileType.MUSIC:
3046
- return `\u97F3\u9891${extension ? ` (${extension.toUpperCase()})` : ""}`;
3047
- case FileType.DOCUMENT:
3048
- return `\u6587\u6863${extension ? ` (${extension.toUpperCase()})` : ""}`;
3049
- case FileType.CODE:
3050
- return `\u4EE3\u7801\u6587\u4EF6${extension ? ` (${extension.toUpperCase()})` : ""}`;
3051
- case FileType.ARCHIVE:
3052
- return `\u538B\u7F29\u5305${extension ? ` (${extension.toUpperCase()})` : ""}`;
3053
- default:
3054
- return extension ? `${extension.toUpperCase()} \u6587\u4EF6` : "\u6587\u4EF6";
3055
- }
3056
- }
3057
- function getExtension(filename) {
3058
- const lastDot = filename.lastIndexOf(".");
3059
- if (lastDot === -1 || lastDot === 0) return void 0;
3060
- return filename.substring(lastDot + 1).toLowerCase();
3061
- }
3062
- function getDirectory(path) {
3063
- const lastSlash = path.lastIndexOf("/");
3064
- if (lastSlash === -1) return path;
3065
- return path.substring(0, lastSlash) || "/";
3066
- }
3067
- function FileInfoDialog({ visible, item, onClose }) {
3068
- if (!visible || !item) return null;
3069
- const extension = getExtension(item.name);
3070
- const directory = getDirectory(item.id);
3071
- const handleBackdropClick = (e) => {
3072
- if (e.target === e.currentTarget) {
3073
- onClose();
3074
- }
3075
- };
3076
- React.useEffect(() => {
3077
- const handleKeyDown = (e) => {
3078
- if (e.key === "Escape") {
3079
- onClose();
3080
- }
3081
- };
3082
- if (visible) {
3083
- document.addEventListener("keydown", handleKeyDown);
3084
- }
3085
- return () => document.removeEventListener("keydown", handleKeyDown);
3086
- }, [visible, onClose]);
3087
- return /* @__PURE__ */ jsx14("div", { className: "file-info-dialog-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog", children: [
3088
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-header", children: [
3089
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-title", children: [
3090
- getFileIcon(item.type, item.name),
3091
- /* @__PURE__ */ jsx14("span", { className: "file-info-dialog-name", title: item.name, children: item.name })
3092
- ] }),
3093
- /* @__PURE__ */ jsx14("button", { className: "file-info-dialog-close", onClick: onClose, children: /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:x", width: 18, height: 18 }) })
3094
- ] }),
3095
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-content", children: [
3096
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3097
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3098
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:file", width: 14, height: 14 }),
3099
- /* @__PURE__ */ jsx14("span", { children: "\u7C7B\u578B" })
3100
- ] }),
3101
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: getFileTypeName(item.type, extension) })
3102
- ] }),
3103
- item.type !== FileType.FOLDER && item.size && /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3104
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3105
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:hard-drive", width: 14, height: 14 }),
3106
- /* @__PURE__ */ jsx14("span", { children: "\u5927\u5C0F" })
3107
- ] }),
3108
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: item.size })
3109
- ] }),
3110
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3111
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3112
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:map-pin", width: 14, height: 14 }),
3113
- /* @__PURE__ */ jsx14("span", { children: "\u4F4D\u7F6E" })
3114
- ] }),
3115
- /* @__PURE__ */ jsx14("div", { className: "file-info-value file-info-value--path", title: directory, children: directory })
3116
- ] }),
3117
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3118
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3119
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:map-pin", width: 14, height: 14 }),
3120
- /* @__PURE__ */ jsx14("span", { children: "\u5B8C\u6574\u8DEF\u5F84" })
3121
- ] }),
3122
- /* @__PURE__ */ jsx14("div", { className: "file-info-value file-info-value--path", title: item.id, children: item.id })
3123
- ] }),
3124
- item.dateModified && /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3125
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3126
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:clock", width: 14, height: 14 }),
3127
- /* @__PURE__ */ jsx14("span", { children: "\u4FEE\u6539\u65F6\u95F4" })
3128
- ] }),
3129
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: item.dateModified })
3130
- ] })
3131
- ] }),
3132
- /* @__PURE__ */ jsx14("div", { className: "file-info-dialog-footer", children: /* @__PURE__ */ jsx14("button", { className: "file-info-dialog-btn", onClick: onClose, children: "\u5173\u95ED" }) })
3133
- ] }) });
3134
- }
3135
-
3136
- // src/hooks/useSelection.ts
3137
- import { useState as useState7, useCallback as useCallback5 } from "react";
3138
- function useSelection() {
3139
- const [selectedIds, setSelectedIds] = useState7(/* @__PURE__ */ new Set());
3140
- const [lastSelectedId, setLastSelectedId] = useState7(null);
3141
- const [editingId, setEditingId] = useState7(null);
3142
- const clearSelection = useCallback5(() => {
3143
- setSelectedIds(/* @__PURE__ */ new Set());
3144
- setLastSelectedId(null);
3145
- }, []);
3146
- const selectItem = useCallback5((id, items, multi = false, range = false) => {
3147
- if (!id) {
3148
- clearSelection();
3149
- return;
3150
- }
3151
- setSelectedIds((prev) => {
3152
- setLastSelectedId((prevLast) => {
3153
- if (range && prevLast) {
3154
- const indexA = items.findIndex((i) => i.id === prevLast);
3155
- const indexB = items.findIndex((i) => i.id === id);
3156
- if (indexA !== -1 && indexB !== -1) {
3157
- const start = Math.min(indexA, indexB);
3158
- const end = Math.max(indexA, indexB);
3159
- const newSet = new Set(multi ? prev : []);
3160
- for (let i = start; i <= end; i++) {
3161
- const item = items[i];
3162
- if (item) {
3163
- newSet.add(item.id);
3164
- }
3165
- }
3166
- setSelectedIds(newSet);
3167
- return id;
3168
- }
3169
- }
3170
- if (multi) {
3171
- const newSet = new Set(prev);
3172
- if (newSet.has(id)) {
3173
- newSet.delete(id);
3174
- } else {
3175
- newSet.add(id);
3176
- }
3177
- setSelectedIds(newSet);
3178
- return id;
3179
- }
3180
- setSelectedIds(/* @__PURE__ */ new Set([id]));
3181
- return id;
3182
- });
3183
- return prev;
3184
- });
3185
- }, [clearSelection]);
3186
- const selectAll = useCallback5((items) => {
3187
- setSelectedIds(new Set(items.map((i) => i.id)));
3188
- }, []);
3189
- const setEditing = useCallback5((id) => {
3190
- setEditingId(id);
3191
- }, []);
3192
- const isSelected = useCallback5((id) => {
3193
- return selectedIds.has(id);
3194
- }, [selectedIds]);
3195
- return {
3196
- selectedIds,
3197
- lastSelectedId,
3198
- editingId,
3199
- clearSelection,
3200
- selectItem,
3201
- selectAll,
3202
- setEditing,
3203
- isSelected
3204
- };
3205
- }
3206
-
3207
- // src/hooks/useDragAndDrop.ts
3208
- import { useState as useState8, useCallback as useCallback6 } from "react";
3209
- function useDragAndDrop(getSelectedIds, onSelect, onMove) {
3210
- const [dragOverId, setDragOverId] = useState8(null);
3211
- const [isDragging, setIsDragging] = useState8(false);
3212
- const handleDragStart = useCallback6((e, itemId) => {
3213
- if (!e.dataTransfer) return;
3214
- const selectedIds = getSelectedIds();
3215
- if (!selectedIds.has(itemId)) {
3216
- onSelect(itemId, false, false);
3217
- }
3218
- const draggedIds = selectedIds.has(itemId) ? selectedIds : /* @__PURE__ */ new Set([itemId]);
3219
- e.dataTransfer.setData("text/plain", JSON.stringify([...draggedIds]));
3220
- e.dataTransfer.effectAllowed = "move";
3221
- setIsDragging(true);
3222
- }, [getSelectedIds, onSelect]);
3223
- const handleDragOver = useCallback6((e, item) => {
3224
- if (!isDragging) return;
3225
- if (item.type === FileType.FOLDER) {
3226
- const selectedIds = getSelectedIds();
3227
- if (!selectedIds.has(item.id)) {
3228
- e.preventDefault();
3229
- setDragOverId(item.id);
3230
- }
3231
- }
3232
- }, [isDragging, getSelectedIds]);
3233
- const handleDragLeave = useCallback6(() => {
3234
- setDragOverId(null);
3235
- }, []);
3236
- const handleDrop = useCallback6((e, targetItem) => {
3237
- setDragOverId(null);
3238
- setIsDragging(false);
3239
- if (!e.dataTransfer || targetItem.type !== FileType.FOLDER) return;
3240
- const data = e.dataTransfer.getData("text/plain");
3241
- if (!data) return;
3242
- try {
3243
- const draggedIds = JSON.parse(data);
3244
- const itemIds = new Set(draggedIds);
3245
- if (itemIds.has(targetItem.id)) return;
3246
- onMove(targetItem.id, itemIds);
3247
- } catch {
3248
- }
3249
- }, [onMove]);
3250
- const handleDragEnd = useCallback6(() => {
3251
- setDragOverId(null);
3252
- setIsDragging(false);
3253
- }, []);
3254
- return {
3255
- dragOverId,
3256
- isDragging,
3257
- handleDragStart,
3258
- handleDragOver,
3259
- handleDragLeave,
3260
- handleDrop,
3261
- handleDragEnd
3262
- };
3263
- }
3264
-
3265
- // src/hooks/useMediaPlayer.ts
3266
- import { useState as useState9, useCallback as useCallback7, useEffect as useEffect6 } from "react";
3267
- function useMediaPlayer(mediaType, mediaRef) {
3268
- const [isPlaying, setIsPlaying] = useState9(false);
3269
- const [progress, setProgress] = useState9(0);
3270
- const [currentTime, setCurrentTime] = useState9(0);
3271
- const [duration, setDuration] = useState9(0);
3272
- const [isMuted, setIsMuted] = useState9(false);
3273
- const [volume, setVolume] = useState9(1);
3274
- const [lastVolume, setLastVolume] = useState9(1);
3275
- const [showControls, setShowControls] = useState9(false);
3276
- const isAudio = mediaType === FileType.MUSIC;
3277
- const updateProgress = useCallback7(() => {
3278
- const media = mediaRef.current;
3279
- if (media) {
3280
- const curr = media.currentTime;
3281
- const dur = media.duration;
3282
- setCurrentTime(curr);
3283
- if (dur && !isNaN(dur)) {
3284
- setDuration(dur);
3285
- setProgress(curr / dur * 100);
3286
- }
3287
- }
3288
- }, [mediaRef]);
3289
- const togglePlay = useCallback7(() => {
3290
- const media = mediaRef.current;
3291
- if (media) {
3292
- if (isPlaying) {
3293
- media.pause();
3294
- setIsPlaying(false);
3295
- } else {
3296
- media.play();
3297
- setIsPlaying(true);
3298
- }
3299
- }
3300
- }, [isPlaying, mediaRef]);
3301
- const toggleMute = useCallback7(() => {
3302
- const media = mediaRef.current;
3303
- if (media) {
3304
- if (isMuted) {
3305
- const volToRestore = lastVolume || 1;
3306
- media.volume = volToRestore;
3307
- media.muted = false;
3308
- setVolume(volToRestore);
3309
- setIsMuted(false);
3310
- } else {
3311
- setLastVolume(volume);
3312
- media.volume = 0;
3313
- media.muted = true;
3314
- setVolume(0);
3315
- setIsMuted(true);
3316
- }
3317
- }
3318
- }, [isMuted, lastVolume, volume, mediaRef]);
3319
- const handleVolumeChange = useCallback7((val) => {
3320
- setVolume(val);
3321
- const media = mediaRef.current;
3322
- if (media) {
3323
- media.volume = val;
3324
- if (val === 0) {
3325
- setIsMuted(true);
3326
- media.muted = true;
3327
- } else {
3328
- setIsMuted(false);
3329
- media.muted = false;
3330
- }
3331
- }
3332
- }, [mediaRef]);
3333
- const seekTo = useCallback7((time) => {
3334
- const media = mediaRef.current;
3335
- if (media && duration) {
3336
- media.currentTime = time;
3337
- setCurrentTime(time);
3338
- setProgress(time / duration * 100);
3339
- }
3340
- }, [duration, mediaRef]);
3341
- const formatTime = useCallback7((time) => {
3342
- if (isNaN(time)) return "0:00";
3343
- const minutes = Math.floor(time / 60);
3344
- const seconds = Math.floor(time % 60);
3345
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
3346
- }, []);
3347
- const autoPlay = useCallback7(() => {
3348
- const media = mediaRef.current;
3349
- if ((mediaType === FileType.VIDEO || isAudio) && media) {
3350
- media.volume = volume;
3351
- media.play().catch(() => {
3352
- });
3353
- setIsPlaying(true);
3354
- }
3355
- }, [mediaType, isAudio, volume, mediaRef]);
3356
- useEffect6(() => {
3357
- const media = mediaRef.current;
3358
- if (media) {
3359
- media.addEventListener("timeupdate", updateProgress);
3360
- media.addEventListener("loadedmetadata", updateProgress);
3361
- media.addEventListener("ended", () => {
3362
- setIsPlaying(false);
3363
- });
3364
- return () => {
3365
- media.removeEventListener("timeupdate", updateProgress);
3366
- media.removeEventListener("loadedmetadata", updateProgress);
3367
- };
3368
- }
3369
- }, [mediaRef, updateProgress]);
3370
- return {
3371
- isPlaying,
3372
- progress,
3373
- currentTime,
3374
- duration,
3375
- isMuted,
3376
- volume,
3377
- showControls,
3378
- isAudio,
3379
- togglePlay,
3380
- toggleMute,
3381
- handleVolumeChange,
3382
- seekTo,
3383
- formatTime,
3384
- autoPlay,
3385
- updateProgress
3386
- };
3387
- }
3388
-
3389
- // src/hooks/useApplicationIcon.ts
3390
- import { useState as useState10, useCallback as useCallback8, useEffect as useEffect7 } from "react";
3391
- function useApplicationIcon(items) {
3392
- const appIconCache = /* @__PURE__ */ new Map();
3393
- const [appIconUrls, setAppIconUrls] = useState10(/* @__PURE__ */ new Map());
3394
- const loadApplicationIcon = useCallback8(async (item) => {
3395
- if (item.type !== FileType.APPLICATION || !item.id) return;
3396
- if (appIconCache.has(item.id)) {
3397
- const cachedUrl = appIconCache.get(item.id);
3398
- if (cachedUrl) {
3399
- setAppIconUrls((prev) => new Map(prev).set(item.id, cachedUrl));
3400
- }
3401
- return;
3402
- }
3403
- if (appIconUrls.has(item.id)) {
3404
- return;
3405
- }
3406
- if (typeof window.fileExplorerAPI !== "undefined" && window.fileExplorerAPI.getApplicationIcon) {
3407
- try {
3408
- const iconUrl = await window.fileExplorerAPI.getApplicationIcon(item.id);
3409
- if (iconUrl) {
3410
- appIconCache.set(item.id, iconUrl);
3411
- setAppIconUrls((prev) => new Map(prev).set(item.id, iconUrl));
3412
- }
3413
- } catch (error) {
3414
- console.error(`Failed to load application icon for ${item.name}:`, error);
3415
- }
3416
- }
3417
- }, [appIconUrls]);
3418
- useEffect7(() => {
3419
- items.forEach((item) => {
3420
- if (item.type === FileType.APPLICATION && !appIconUrls.has(item.id)) {
3421
- loadApplicationIcon(item);
3422
- }
3423
- });
3424
- }, [items, appIconUrls, loadApplicationIcon]);
3425
- const getAppIconUrl = useCallback8((item) => {
3426
- return appIconUrls.get(item.id);
3427
- }, [appIconUrls]);
3428
- return {
3429
- getAppIconUrl,
3430
- loadApplicationIcon
3431
- };
3432
- }
3433
- export {
3434
- Breadcrumb,
3435
- CompressDialog,
3436
- ContextMenu,
3437
- FileGrid,
3438
- FileIcon,
3439
- FileInfoDialog,
3440
- FileList,
3441
- FileListView,
3442
- FileSidebar,
3443
- FileType,
3444
- ProgressDialog,
3445
- SortIndicator,
3446
- StatusBar,
3447
- Toolbar,
3448
- Window,
3449
- useApplicationIcon,
3450
- useDragAndDrop,
3451
- useMediaPlayer,
3452
- useSelection,
3453
- useWindowDrag,
3454
- useWindowResize
3455
- };
3456
- //# sourceMappingURL=index.js.map
1
+ var e={FOLDER:"folder",FILE:"file",IMAGE:"image",VIDEO:"video",MUSIC:"music",DOCUMENT:"document",CODE:"code",TEXT:"text",PDF:"pdf",ARCHIVE:"archive",APPLICATION:"application",UNKNOWN:"unknown"};import{useState as t,useCallback as i,useImperativeHandle as n,forwardRef as s}from"react";import{Icon as a}from"@iconify/react";import{useRef as o,useMemo as r}from"react";import{useMemo as l}from"react";import{Icon as c}from"@iconify/react";var d=new Set(["3d","actionscript","ada","adobe-illustrator","adobe-photoshop","android","angular","applescript","arduino","asciidoc","assembly","astro","audio","aurelia","babel","ballerina","bazel","biome","blender","bower","bun","c","cabal","caddy","cake","certificate","changelog","circleci","claude","clojure","cmake","cobol","coffee","command","conduct","contributing","controller","copilot","cpp","crystal","csharp","css","css-map","cucumber","cuda","cursor","cypress","d","dart","database","deno","dependabot","diff","django","docker","document","drawio","drizzle","editorconfig","ejs","elixir","elm","email","ember","epub","erlang","esbuild","eslint","excalidraw","exe","favicon","figma","firebase","flash","flow","font","forth","fortran","freemarker","fsharp","gamemaker","gatsby","gcp","gemfile","gemini","git","gitlab","gleam","go","go-mod","godot","gradle","graphql","groovy","grunt","gulp","h","haml","handlebars","hardhat","haskell","haxe","hcl","helm","hjson","hosts","hpp","html","http","husky","i18n","image","imba","ionic","jar","java","javaclass","javascript","javascript-map","jenkins","jest","jinja","jsconfig","json","julia","jupyter","just","karma","key","kotlin","kubernetes","laravel","lean","lefthook","lerna","less","lib","license","lighthouse","liquid","lisp","livescript","lock","log","lua","luau","makefile","markdown","markdownlint","matlab","maven","mdx","mercurial","mermaid","meson","minecraft","mjml","mocha","mojo","nest","netlify","next","nginx","nim","nix","nodejs","nodemon","npm","nuget","nunjucks","nuxt","nx","objective-c","objective-cpp","ocaml","odin","openapi","opentofu","pascal","pdf","perl","php","phpstan","phpunit","pipeline","playwright","pnpm","postcss","powerpoint","powershell","prettier","prisma","processing","prolog","proto","pug","puppet","purescript","python","pytorch","quasar","r","racket","razor","react","react-ts","readme","reason","remark","remix","renovate","replit","rescript","riot","roadmap","robot","robots","rollup","routing","rspec","rubocop","ruby","ruff","rust","salt","san","sas","sass","sbt","scala","scheme","search","sentry","sequelize","serverless","settings","shader","shellcheck","sketch","slim","slint","smarty","snakemake","snapcraft","snyk","solidity","spwn","stackblitz","stan","stencil","storybook","stryker","stylelint","stylus","sublime","subtitles","supabase","svelte","svg","svgo","swagger","swc","swift","tailwindcss","taskfile","tauri","tcl","teal","templ","template","terraform","test-js","test-jsx","test-ts","tex","todo","toml","travis","tree","tsconfig","tsdoc","turborepo","twig","typescript","typescript-def","unity","unocss","vagrant","vanilla-extract","vercel","verilog","video","vim","vite","vitest","vlang","vscode","vue","vue-config","wakatime","wallaby","webassembly","webhint","webpack","windicss","word","wrangler","wxt","xaml","xmake","xml","yaml","yarn","zig","zip"]),m={js:"javascript",mjs:"javascript",cjs:"javascript",jsx:"react",ts:"typescript",mts:"typescript",cts:"typescript",tsx:"react-ts",vue:"vue",svelte:"svelte",astro:"astro",py:"python",pyw:"python",pyi:"python",pyc:"python",java:"java",class:"javaclass",jar:"jar",c:"c",h:"h",cpp:"cpp",cc:"cpp",cxx:"cpp",hpp:"hpp",hh:"hpp",hxx:"hpp",cs:"csharp",csx:"csharp",go:"go",rs:"rust",php:"php",phtml:"php",rb:"ruby",rake:"ruby",swift:"swift",kt:"kotlin",kts:"kotlin",scala:"scala",dart:"dart",lua:"lua",luau:"luau",r:"r",rdata:"r",rds:"r",pl:"perl",pm:"perl",sh:"command",bash:"command",zsh:"command",fish:"command",ps1:"powershell",psm1:"powershell",psd1:"powershell",bat:"command",cmd:"command",css:"css",scss:"sass",sass:"sass",less:"less",styl:"stylus",html:"html",htm:"html",xhtml:"html",xml:"xml",xsl:"xml",xslt:"xml",json:"json",jsonc:"json",json5:"json",yaml:"yaml",yml:"yaml",toml:"toml",ini:"settings",conf:"settings",config:"settings",md:"markdown",markdown:"markdown",mdx:"mdx",txt:"document",pdf:"pdf",doc:"word",docx:"word",dot:"word",dotx:"word",odt:"word",xls:"table",xlsx:"table",xlsm:"table",ods:"table",csv:"table",ppt:"powerpoint",pptx:"powerpoint",odp:"powerpoint",jpg:"image",jpeg:"image",png:"image",gif:"image",webp:"image",ico:"image",bmp:"image",tiff:"image",tif:"image",heic:"image",heif:"image",svg:"svg",psd:"adobe-photoshop",ai:"adobe-illustrator",sketch:"sketch",fig:"figma",figma:"figma",mp4:"video",mov:"video",avi:"video",mkv:"video",webm:"video",flv:"video",wmv:"video",m4v:"video","3gp":"video",mpeg:"video",mpg:"video",mp3:"audio",wav:"audio",flac:"audio",aac:"audio",ogg:"audio",wma:"audio",m4a:"audio",aiff:"audio",zip:"zip",rar:"zip","7z":"zip",tar:"zip",gz:"zip",bz2:"zip",xz:"zip",tgz:"zip",tbz2:"zip",sql:"database",db:"database",sqlite:"database",sqlite3:"database",prisma:"prisma",log:"log",lock:"lock",env:"settings",graphql:"graphql",gql:"graphql",proto:"proto",wasm:"webassembly",zig:"zig",nim:"nim",nix:"nix",hcl:"hcl",tf:"terraform",sol:"solidity",ex:"elixir",exs:"elixir",erl:"erlang",hrl:"erlang",hs:"haskell",lhs:"haskell",ml:"ocaml",mli:"ocaml",clj:"clojure",cljs:"clojure",cljc:"clojure",lisp:"lisp",lsp:"lisp",el:"lisp",vim:"vim",dockerfile:"docker"},u={".gitignore":"git",".gitattributes":"git",".gitmodules":"git",".gitkeep":"git",".env":"settings",".env.local":"settings",".env.development":"settings",".env.production":"settings",".env.test":"settings",".env.example":"settings","package.json":"nodejs","package-lock.json":"npm","yarn.lock":"yarn",".yarnrc":"yarn",".yarnrc.yml":"yarn","pnpm-lock.yaml":"pnpm",".pnpmfile.cjs":"pnpm","bun.lockb":"bun","bunfig.toml":"bun","requirements.txt":"python",pipfile:"python","pipfile.lock":"python","pyproject.toml":"python","poetry.lock":"python","setup.py":"python","cargo.toml":"rust","cargo.lock":"rust","go.mod":"go-mod","go.sum":"go-mod","go.work":"go-mod","composer.json":"php","composer.lock":"php",gemfile:"gemfile","gemfile.lock":"gemfile",rakefile:"ruby",dockerfile:"docker","docker-compose.yml":"docker","docker-compose.yaml":"docker",".dockerignore":"docker",makefile:"makefile",gnumakefile:"makefile","cmakelists.txt":"cmake","build.gradle":"gradle","build.gradle.kts":"gradle","settings.gradle":"gradle","pom.xml":"maven","tsconfig.json":"tsconfig","jsconfig.json":"jsconfig",".prettierrc":"prettier",".prettierrc.json":"prettier",".prettierrc.js":"prettier",".prettierignore":"prettier","prettier.config.js":"prettier",".eslintrc":"eslint",".eslintrc.json":"eslint",".eslintrc.js":"eslint",".eslintignore":"eslint","eslint.config.js":"eslint","eslint.config.mjs":"eslint",".editorconfig":"editorconfig","vite.config.ts":"vite","vite.config.js":"vite","webpack.config.js":"webpack","webpack.config.ts":"webpack","rollup.config.js":"rollup","rollup.config.ts":"rollup","esbuild.config.js":"esbuild","tailwind.config.js":"tailwindcss","tailwind.config.ts":"tailwindcss","postcss.config.js":"postcss","postcss.config.cjs":"postcss","babel.config.js":"babel",".babelrc":"babel","jest.config.js":"jest","jest.config.ts":"jest","vitest.config.ts":"vitest","vitest.config.js":"vitest","playwright.config.ts":"playwright","playwright.config.js":"playwright","cypress.config.ts":"cypress","cypress.config.js":"cypress",".swcrc":"swc","swc.config.js":"swc","turbo.json":"turborepo","nx.json":"nx","biome.json":"biome",".nvmrc":"nodejs",".node-version":"nodejs","nuxt.config.ts":"nuxt","nuxt.config.js":"nuxt","next.config.js":"next","next.config.mjs":"next","next.config.ts":"next","svelte.config.js":"svelte","astro.config.mjs":"astro","astro.config.ts":"astro","vue.config.js":"vue-config","angular.json":"angular","nest-cli.json":"nest","tauri.conf.json":"tauri",".travis.yml":"travis",".gitlab-ci.yml":"gitlab","vercel.json":"vercel","netlify.toml":"netlify",license:"license","license.md":"license","license.txt":"license",readme:"readme","readme.md":"readme","readme.txt":"readme",changelog:"changelog","changelog.md":"changelog",".npmrc":"npm",".npmignore":"npm","robots.txt":"robots",".htaccess":"nginx",vagrantfile:"vagrant",".stylelintrc":"stylelint",".stylelintrc.json":"stylelint","nodemon.json":"nodemon",".huskyrc":"husky","renovate.json":"renovate",".snyk":"snyk","deno.json":"deno","deno.jsonc":"deno"};function p(t,i){const n=t.toLowerCase();if(u[n]){const e=u[n];if(d.has(e))return`material-icon-theme:${e}`}if("dockerfile"===n||n.startsWith("dockerfile."))return"material-icon-theme:docker";if(".env"===n||n.startsWith(".env."))return"material-icon-theme:settings";const s=t.lastIndexOf("."),a=s>0?t.substring(s+1).toLowerCase():"";if("ts"===a||"js"===a){const e=t.substring(0,s).toLowerCase();if(e.endsWith(".d"))return"material-icon-theme:typescript-def";if(e.endsWith(".test")||e.endsWith(".spec"))return"ts"===a?"material-icon-theme:test-ts":"material-icon-theme:test-js"}if("jsx"===a||"tsx"===a){const e=t.substring(0,s).toLowerCase();if(e.endsWith(".test")||e.endsWith(".spec"))return"tsx"===a?"material-icon-theme:test-ts":"material-icon-theme:test-jsx"}if(a&&m[a]){const e=m[a];if(d.has(e))return`material-icon-theme:${e}`}return i?function(t){switch(t){case e.IMAGE:return"material-icon-theme:image";case e.VIDEO:return"material-icon-theme:video";case e.MUSIC:return"material-icon-theme:audio";case e.CODE:return"material-icon-theme:javascript";case e.TEXT:return"material-icon-theme:document";case e.DOCUMENT:return"material-icon-theme:word";case e.PDF:return"material-icon-theme:pdf";case e.ARCHIVE:return"material-icon-theme:zip";case e.APPLICATION:return"material-icon-theme:exe";default:return"material-icon-theme:document"}}(i):"material-icon-theme:document"}var h=new Set(["admin","android","angular","animation","ansible","api","apollo","app","archive","astro","atom","attachment","audio","aurelia","aws","azure-pipelines","backup","base","batch","benchmark","bibliography","bicep","blender","bloc","bower","buildkite","cart","changesets","ci","circleci","class","claude","client","cline","cloud-functions","cloudflare","cluster","cobol","command","components","config","connection","console","constant","container","content","context","contract","controller","core","coverage","css","cue","cursor","custom","cypress","dal","dart","database","debug","decorators","delta","desktop","directive","dist","docker","docs","download","drizzle","dump","element","enum","environment","error","eslint","event","examples","expo","export","fastlane","favicon","features","filter","firebase","firestore","flow","flutter","font","forgejo","functions","gamemaker","generator","gh-workflows","git","gitea","github","gitlab","global","godot","gradle","graphql","guard","gulp","helm","helper","home","hook","husky","i18n","images","import","include","input","intellij","interceptor","interface","ios","java","javascript","jinja","job","json","jupyter","keys","kubernetes","kusto","layout","lefthook","less","lib","license","link","linux","liquibase","log","lottie","lua","luau","macos","mail","mappings","markdown","mercurial","messages","meta","metro","middleware","migrations","mjml","mobile","mock","mojo","molecule","moon","netlify","next","ngrx-store","node","nuxt","obsidian","organism","other","packages","pdf","pdm","php","phpmailer","pipe","plastic","plugin","policy","powershell","prisma","private","project","prompts","proto","public","python","pytorch","quasar","queue","react-components","redux-reducer","repository","resolver","resource","review","robot","routes","rules","rust","salt","sandbox","sass","scala","scons","scripts","secure","seeders","server","serverless","shader","shared","simulations","snapcraft","snippet","src","src-tauri","stack","stencil","store","storybook","stylus","sublime","supabase","svelte","svg","syntax","target","taskfile","tasks","television","temp","template","terraform","test","theme","toc","tools","trash","trigger","turborepo","typescript","ui","unity","update","upload","utils","vercel","verdaccio","video","views","vm","vscode","vue","vue-directives","vuepress","vuex-store","wakatime","webpack","windows","wordpress","yarn","zeabur"]),g={tests:"test",__tests__:"test",__test__:"test",spec:"test",specs:"test",script:"scripts",configs:"config",configuration:"config",configurations:"config",route:"routes",routing:"routes",stories:"storybook",story:"storybook",templates:"template",themes:"theme",videos:"video",imgs:"images",img:"images",image:"images",fonts:"font",styles:"css",style:"css",styling:"css",stylesheets:"css",view:"views",pages:"views",page:"views",layouts:"layout",models:"database",model:"database",modules:"lib",module:"lib",mods:"lib",plugins:"plugin",addons:"plugin",extensions:"plugin",middlewares:"middleware",helpers:"helper",utilities:"utils",util:"utils",tool:"tools",tooling:"tools",resources:"resource",res:"resource",assets:"resource",asset:"resource",hooks:"hook",composables:"hook",mocks:"mock",__mocks__:"mock",fixtures:"mock",__fixtures__:"mock",logs:"log",uploads:"upload",function:"functions",func:"functions",fns:"functions",services:"server",service:"server",component:"components",comp:"components",comps:"components",controllers:"controller",source:"src",sources:"src",distribution:"dist",build:"dist",builds:"dist",out:"dist",output:"dist",documentation:"docs",doc:"docs",document:"docs",documents:"docs",static:"public",statics:"public",publics:"public",libs:"lib",library:"lib",vendor:"lib",vendors:"lib",bin:"scripts",binaries:"scripts",tmp:"temp",temporary:"temp",cache:"temp",caches:"temp",".cache":"temp",".turbo":"temp",types:"typescript","@types":"typescript",typings:"typescript",dts:"typescript",locales:"i18n",locale:"i18n",lang:"i18n",languages:"i18n",translations:"i18n",db:"database",databases:"database",sql:"database",queries:"database",migration:"migrations",seeds:"seeders",seed:"seeders",".vscode":"vscode",".github":"github",".gitlab":"gitlab",".circleci":"circleci",".husky":"husky",".docker":"docker",node_modules:"node",scss:"sass",renderer:"client",frontend:"client",web:"client",webapp:"client",website:"client",backend:"server",main:"server",preload:"scripts",".idea":"intellij",".git":"git",k8s:"kubernetes",kube:"kubernetes",mongo:"database",mongodb:"database",mysql:"database",postgres:"database",api:"api",apis:"api",interfaces:"interface",notebook:"jupyter",notebooks:"jupyter",ipynb:"jupyter",notification:"messages",notifications:"messages",env:"environment",envs:"environment",redux:"redux-reducer",store:"store",stores:"store",electron:"desktop",tauri:"src-tauri"};import{jsx as f}from"react/jsx-runtime";function v({type:t,name:i,className:n="",size:s=24}){const a=l(()=>{if(t===e.FOLDER){const e=i?function(e){const t=(e||"").trim();if(!t)return;const i=t.replace(/[\\/]+$/,"").toLowerCase(),n=g[i]??i;return h.has(n)?`material-icon-theme:folder-${n}`:void 0}(i):void 0;return e??"ic:round-folder"}if(i)return p(i,t);switch(t){case e.IMAGE:return"material-icon-theme:image";case e.TEXT:return"material-icon-theme:document";case e.CODE:return"material-icon-theme:javascript";case e.MUSIC:return"material-icon-theme:audio";case e.VIDEO:return"material-icon-theme:video";case e.PDF:return"material-icon-theme:pdf";case e.DOCUMENT:return"material-icon-theme:word";case e.APPLICATION:return"material-icon-theme:exe";case e.ARCHIVE:return"material-icon-theme:zip";default:return"material-icon-theme:document"}},[t,i]),o=l(()=>{const i="file-icon";switch(t){case e.FOLDER:return`${i} file-icon--folder`;case e.IMAGE:return`${i} file-icon--image`;case e.TEXT:return`${i} file-icon--text`;case e.CODE:return`${i} file-icon--code`;case e.MUSIC:return`${i} file-icon--music`;case e.VIDEO:return`${i} file-icon--video`;case e.PDF:case e.DOCUMENT:return`${i} file-icon--pdf`;case e.APPLICATION:return`${i} file-icon--application`;case e.ARCHIVE:return`${i} file-icon--archive`;default:return`${i} file-icon--default`}},[t]);return f("div",{className:n,children:f(c,{icon:a,width:s,height:s,className:o})})}import{Fragment as b,jsx as w,jsxs as y}from"react/jsx-runtime";function x({name:e,isFolder:t,isSelected:i,onClick:n}){const{baseName:s,ext:a}=r(()=>function(e,t){if(t)return{baseName:e,ext:""};const i=e.lastIndexOf(".");return i<=0?{baseName:e,ext:""}:{baseName:e.substring(0,i),ext:e.substring(i)}}(e,t),[e,t]);return w("span",{onClick:n,className:"file-grid-item-name "+(i?"file-grid-item-name--selected":""),title:e,children:a?y(b,{children:[w("span",{className:"file-grid-item-name-base",children:s}),w("span",{className:"file-grid-item-name-ext",children:a})]}):w("span",{className:"file-grid-item-name-base file-grid-item-name-base--two-lines",children:s})})}function N({items:t,selectedIds:i,editingId:n,dragOverId:s,getAppIconUrl:a,onSelect:r,onOpen:l,onContextMenu:c,onContextMenuEmpty:d,onNameClick:m,onRename:u,onRenameCancel:p,onDragStart:h,onDragOver:g,onDragLeave:f,onDrop:b,onThumbnailError:N}){const k=o(null);return w("div",{className:"file-grid",onContextMenu:e=>{e.preventDefault(),(e=>{e.target.closest(".file-grid-item")||d?.(e)})(e)},children:t.map(o=>{const d=i.has(o.id),j=n===o.id,C=s===o.id,E=(t=>!(t.type!==e.APPLICATION||!a?.(t))||(t.type===e.IMAGE||t.type===e.VIDEO)&&!!t.thumbnailUrl)(o),I=o.type===e.APPLICATION?a?.(o):void 0;let D="file-grid-item";return D+=d&&!j?" file-grid-item--selected":C?" file-grid-item--drag-over":" file-grid-item--normal",y("div",{draggable:!j,onDragStart:e=>h?.(e,o),onDragOver:e=>{e.preventDefault(),g?.(e,o)},onDragLeave:e=>f?.(e),onDrop:e=>{e.preventDefault(),b?.(e,o)},onClick:e=>{e.stopPropagation(),r?.(o,e)},onDoubleClick:e=>{e.stopPropagation(),l?.(o)},onContextMenu:e=>{e.preventDefault(),e.stopPropagation(),c?.(o,e)},className:D,children:[y("div",{className:"file-grid-item-icon",children:[I&&w("img",{src:I,alt:o.name,className:"file-grid-item-thumbnail file-grid-item-thumbnail--application "+(d&&!j?"file-grid-item-thumbnail--selected":"")}),!I&&o.type===e.VIDEO&&o.thumbnailUrl&&E&&y("div",{className:"file-grid-item-thumbnail file-grid-item-thumbnail--video",children:[w("img",{src:o.thumbnailUrl,alt:o.name,className:"file-grid-item-thumbnail",onError:e=>N?.(o,e)}),w("div",{className:"file-grid-item-video-play",children:w("div",{className:"file-grid-item-video-play-icon"})})]}),!I&&o.type===e.IMAGE&&o.thumbnailUrl&&E&&w("img",{src:o.thumbnailUrl,alt:o.name,className:"file-grid-item-thumbnail",onError:e=>N?.(o,e)}),!I&&!E&&w(v,{type:o.type,name:o.name,size:48})]}),w("div",{className:"file-grid-item-name-wrapper",children:j?w("input",{ref:k,type:"text",className:"file-grid-item-rename-input",defaultValue:o.name,onBlur:e=>((e,t)=>{const i=t.target.value.trim();i&&i!==e.name?u?.(e,i):p?.(e)})(o,e),onKeyDown:e=>{"Enter"===e.key?(e=>{e.currentTarget.blur()})(e):"Escape"===e.key&&(e=>{const i=e.currentTarget,s=t.find(e=>e.id===n);s&&(i.value=s.name),i.blur()})(e)},autoFocus:!0}):w(x,{name:o.name,isFolder:o.type===e.FOLDER,isSelected:d,onClick:e=>{e.stopPropagation(),m?.(o,e)}})})]},o.id)})})}import{useRef as k}from"react";import{Icon as j}from"@iconify/react";import{jsx as C}from"react/jsx-runtime";function E({direction:e}){return C("span",{className:"sort-indicator",children:C(j,{icon:"asc"===e?"lucide:chevron-up":"lucide:chevron-down",width:12,height:12})})}import{jsx as I,jsxs as D}from"react/jsx-runtime";function M({items:t,selectedIds:i,sortConfig:n,editingId:s,dragOverId:a,onSelect:o,onOpen:r,onContextMenu:l,onContextMenuEmpty:c,onNameClick:d,onRename:m,onRenameCancel:u,onSort:p,onDragStart:h,onDragOver:g,onDragLeave:f,onDrop:b}){const w=k(null);return I("div",{className:"file-list",onContextMenu:e=>{e.preventDefault(),(e=>{e.target.closest("tr")||c?.(e)})(e)},children:D("table",{className:"file-list-table",children:[I("thead",{className:"file-list-header",children:D("tr",{children:[D("th",{className:"file-list-header-cell file-list-header-cell--name",onClick:()=>p?.("name"),children:["名称","name"===n?.field&&I(E,{direction:n.direction})]}),D("th",{className:"file-list-header-cell",onClick:()=>p?.("dateModified"),children:["修改日期","dateModified"===n?.field&&I(E,{direction:n.direction})]}),D("th",{className:"file-list-header-cell",onClick:()=>p?.("size"),children:["大小","size"===n?.field&&I(E,{direction:n.direction})]}),D("th",{className:"file-list-header-cell",onClick:()=>p?.("type"),children:["类型","type"===n?.field&&I(E,{direction:n.direction})]})]})}),I("tbody",{className:"file-list-body",children:t.map((n,c)=>{const p=i.has(n.id),y=s===n.id,x=a===n.id;let N="file-list-row";return N+=p?" file-list-row--selected":x?" file-list-row--drag-over":c%2==0?" file-list-row--even":" file-list-row--odd",D("tr",{draggable:!y,onDragStart:e=>h?.(e,n),onDragOver:e=>{e.preventDefault(),g?.(e,n)},onDragLeave:e=>f?.(e),onDrop:e=>{e.preventDefault(),b?.(e,n)},onClick:e=>{e.stopPropagation(),o?.(n,e)},onDoubleClick:e=>{e.stopPropagation(),r?.(n)},onContextMenu:e=>{e.preventDefault(),e.stopPropagation(),l?.(n,e)},className:N,children:[D("td",{className:"file-list-cell file-list-cell--name "+(p?"file-list-cell--selected":""),children:[I(v,{type:n.type,name:n.name,size:16}),y?I("input",{ref:w,type:"text",className:"file-list-rename-input",defaultValue:n.name,onBlur:e=>((e,t)=>{const i=t.target.value.trim();i&&i!==e.name?m?.(e,i):u?.(e)})(n,e),onKeyDown:e=>{"Enter"===e.key?(e=>{e.currentTarget.blur()})(e):"Escape"===e.key&&(e=>{const i=e.currentTarget,n=t.find(e=>e.id===s);n&&(i.value=n.name),i.blur()})(e)},autoFocus:!0}):I("span",{onClick:e=>{e.stopPropagation(),d?.(n,e)},className:"file-list-name "+(p?"file-list-name--selected":""),children:n.name})]}),I("td",{className:"file-list-cell "+(p?"file-list-cell--selected":""),children:n.dateModified||"--"}),I("td",{className:"file-list-cell file-list-cell--size "+(p?"file-list-cell--selected":""),children:n.size||"--"}),I("td",{className:"file-list-cell "+(p?"file-list-cell--selected":""),children:(k=n.type,{[e.FOLDER]:"文件夹",[e.FILE]:"文件",[e.IMAGE]:"图片",[e.VIDEO]:"视频",[e.MUSIC]:"音频",[e.DOCUMENT]:"文档",[e.CODE]:"代码",[e.TEXT]:"文本",[e.PDF]:"PDF",[e.ARCHIVE]:"压缩包",[e.APPLICATION]:"应用程序",[e.UNKNOWN]:"未知"}[k]||k)})]},n.id);var k})})]})})}import{jsx as z,jsxs as O}from"react/jsx-runtime";var S=s(({items:s,viewMode:o="grid",loading:r=!1,adapter:l,currentPath:c,getAppIconUrl:d,onOpen:m,onSelectionChange:u,onContextMenu:p,onContextMenuEmpty:h,onRename:g,onSortChange:f,onMove:v},b)=>{const[w,y]=t(new Set),[x,k]=t(null),[j,C]=t(null),[E,I]=t({field:"name",direction:"asc"}),D=s.filter(e=>w.has(e.id)),S=i((e,t)=>{if(t.metaKey||t.ctrlKey)y(t=>{const i=new Set(t);i.has(e.id)?i.delete(e.id):i.add(e.id);const n=s.filter(e=>i.has(e.id));return u?.(i,n),i});else if(t.shiftKey&&w.size>0){const t=Array.from(w).pop(),i=s.findIndex(e=>e.id===t),n=s.findIndex(t=>t.id===e.id),a=Math.min(i,n),o=Math.max(i,n),r=new Set;for(let e=a;e<=o;e++)r.add(s[e].id);y(r);const l=s.filter(e=>r.has(e.id));u?.(r,l)}else{const t=new Set([e.id]);y(t),u?.(t,[e])}},[s,w,u]),L=i(e=>{e.target===e.currentTarget&&P()},[]),P=i(()=>{y(new Set),u?.(new Set,[])},[u]),T=i(e=>{m?.(e)},[m]),$=i((e,t)=>{if(!w.has(e.id)){const t=new Set([e.id]);y(t),u?.(t,[e])}p?.(t,e)},[w,u,p]),A=i(e=>{const t=e.target;t.closest(".file-grid-item")||t.closest(".file-list-row")||(P(),h?.(e))},[P,h]),R=i(e=>{P(),h?.(e)},[P,h]),U=i((e,t)=>{w.has(e.id)&&1===w.size&&setTimeout(()=>{w.has(e.id)&&k(e.id)},500)},[w]),F=i((e,t)=>{t&&t!==e.name&&g?.(e,t),k(null)},[g]),V=i(()=>{k(null)},[]),W=i(e=>{I(t=>{const i=t.field===e?{...t,direction:"asc"===t.direction?"desc":"asc"}:{field:e,direction:"asc"};return f?.(i),i})},[f]),q=i((e,t)=>{if(!w.has(t.id)){const e=new Set([t.id]);y(e),u?.(e,[t])}e.dataTransfer.setData("text/plain",JSON.stringify([...w]))},[w,u]),H=i((t,i)=>{i.type!==e.FOLDER||w.has(i.id)||C(i.id)},[w]),_=i(()=>{C(null)},[]),G=i((t,i)=>{if(C(null),i.type!==e.FOLDER)return;const n=t.dataTransfer.getData("text/plain");if(n)try{const e=JSON.parse(n);if(e.includes(i.id))return;v?.(e,i.id),P()}catch(e){}},[v,P]),B=i(e=>{k(e)},[]),X=i(()=>{const e=new Set(s.map(e=>e.id));y(e),u?.(e,s)},[s,u]);return n(b,()=>({clearSelection:P,startRename:B,selectAll:X,selectedIds:w,selectedItems:D}),[w,D,P,B,X]),O("div",{className:"file-list-view",onClick:L,onContextMenu:e=>{e.preventDefault(),A(e)},children:[r&&O("div",{className:"file-list-view-loading",children:[z("div",{className:"file-list-view-spinner"}),z("p",{children:"加载中..."})]}),!r&&0===s.length&&O("div",{className:"file-list-view-empty",children:[z(a,{icon:"lucide:folder-open",width:64,height:64,className:"file-list-view-empty-icon"}),z("p",{children:"文件夹为空"})]}),!r&&s.length>0&&"grid"===o&&z(N,{items:s,selectedIds:w,editingId:x,dragOverId:j,getAppIconUrl:d,onSelect:S,onOpen:T,onContextMenu:$,onContextMenuEmpty:R,onNameClick:U,onRename:F,onRenameCancel:V,onDragStart:q,onDragOver:H,onDragLeave:_,onDrop:G}),!r&&s.length>0&&"list"===o&&z(M,{items:s,selectedIds:w,editingId:x,dragOverId:j,sortConfig:E,onSelect:S,onOpen:T,onContextMenu:$,onContextMenuEmpty:R,onNameClick:U,onRename:F,onRenameCancel:V,onSort:W,onDragStart:q,onDragOver:H,onDragLeave:_,onDrop:G})]})});S.displayName="FileListView";import{Icon as L}from"@iconify/react";import{jsx as P,jsxs as T}from"react/jsx-runtime";function $({sections:e,activeId:t,onNavigate:i}){return P("div",{className:"file-sidebar",children:e.map(e=>T("div",{className:"file-sidebar-section",children:[P("div",{className:"file-sidebar-section-title",children:e.title}),P("ul",{className:"file-sidebar-list",children:e.items.map(e=>{const n=t===e.id;return T("li",{onClick:()=>(e=>{i?.(e)})(e),className:"file-sidebar-item "+(n?"file-sidebar-item--active":""),children:[P(L,{icon:(s=e.icon,s?s.includes(":")?s:`lucide:${s.toLowerCase()}`:"mdi:folder"),width:18,height:18,className:n?"file-sidebar-item-icon--active":"file-sidebar-item-icon"}),P("span",{children:e.label})]},e.id);var s})})]},e.id))})}import{Icon as A}from"@iconify/react";import{Icon as R}from"@iconify/react";import{jsx as U,jsxs as F}from"react/jsx-runtime";function V({items:e,onNavigate:t}){return U("div",{className:"file-breadcrumb",children:e.map((i,n)=>F("span",{className:"file-breadcrumb-item",children:[U("span",{onClick:()=>((i,n)=>{n<e.length-1&&t?.(i,n)})(i,n),className:"file-breadcrumb-link "+(n===e.length-1?"file-breadcrumb-link--current":""),children:i.name}),n<e.length-1&&U(R,{icon:"lucide:chevron-right",width:14,height:14,className:"file-breadcrumb-separator"})]},i.id))})}import{jsx as W,jsxs as q}from"react/jsx-runtime";function H({canGoBack:e=!1,canGoForward:t=!1,breadcrumbs:i=[],viewMode:n="grid",searchQuery:s="",showSearch:a=!1,showViewToggle:o=!0,draggable:r=!1,onBack:l,onForward:c,onBreadcrumbNavigate:d,onViewModeChange:m,onSearchQueryChange:u,children:p,breadcrumbSlot:h,actionsSlot:g}){return q("div",{className:"file-toolbar "+(r?"file-toolbar--draggable":""),children:[q("div",{className:"file-toolbar-nav",children:[W("button",{className:"file-toolbar-button",onClick:l,disabled:!e,title:"后退",children:W(A,{icon:"lucide:chevron-left",width:18,height:18})}),W("button",{className:"file-toolbar-button",onClick:c,disabled:!t,title:"前进",children:W(A,{icon:"lucide:chevron-right",width:18,height:18})})]}),W("div",{className:"file-toolbar-breadcrumb",children:h||i.length>0&&W(V,{items:i,onNavigate:d})}),p&&W("div",{className:"file-toolbar-custom",children:p}),q("div",{className:"file-toolbar-actions",children:[a&&q("div",{className:"file-toolbar-search",children:[W(A,{icon:"lucide:search",width:16,height:16,className:"file-toolbar-search-icon"}),W("input",{type:"text",value:s,onChange:e=>u?.(e.target.value),placeholder:"搜索",className:"file-toolbar-search-input"})]}),o&&q("div",{className:"file-toolbar-view-toggle",children:[W("button",{onClick:()=>m?.("grid"),className:"file-toolbar-button "+("grid"===n?"file-toolbar-button--active":""),title:"网格视图",children:W(A,{icon:"lucide:layout-grid",width:18,height:18})}),W("button",{onClick:()=>m?.("list"),className:"file-toolbar-button "+("list"===n?"file-toolbar-button--active":""),title:"列表视图",children:W(A,{icon:"lucide:list",width:18,height:18})})]}),g]})]})}import{Fragment as _,jsx as G,jsxs as B}from"react/jsx-runtime";function X({itemCount:e=0,selectedCount:t=0,children:i}){return G("div",{className:"file-status-bar",children:i||B(_,{children:[B("span",{children:[e," 个项目"]}),t>0&&B("span",{children:[" • 已选择 ",t," 个"]})]})})}import{createPortal as K}from"react-dom";import{useMemo as J,useEffect as Y,useRef as Z,useCallback as Q,useState as ee}from"react";import{Icon as te}from"@iconify/react";import{jsx as ie,jsxs as ne}from"react/jsx-runtime";var se=220;function ae(e){let t=8;for(const i of e)t+=i.separator?9:32;return t}function oe({visible:e,x:t,y:i,options:n,onClose:s,onSelect:a}){const o=Z(null),[r,l]=ee(null),[c,d]=ee(null),m=Z(new Map),u=J(()=>{const e=ae(n);return function(e,t,i){const n=window.innerWidth,s=window.innerHeight;let a=e,o=t;const r=n-e;r<228&&(a=e>=228?e-se:r>e?n-se-8:8);const l=s-t;return l<i+8&&(o=t>=i+8?t-i:l>t?s-i-8:8),a=Math.max(8,Math.min(a,n-se-8)),o=Math.max(8,Math.min(o,s-i-8)),{x:a,y:o}}(t,i,e)},[t,i,n]),p=J(()=>({left:`${u.x}px`,top:`${u.y}px`}),[u]),h=J(()=>r?n.find(e=>e.id===r&&e.children&&e.children.length>0):null,[r,n]);Y(()=>{if(!r||!h)return void d(null);const e=m.current.get(r);if(!e)return void d(null);const t=function(e,t){const i=window.innerWidth,n=window.innerHeight,s=i-e.right,a=e.left;let o,r;return o=s>=228?e.right+0:a>=228?e.left-se-0:s>a?i-se-8:8,r=e.top,r+t>n-8&&(r=n-t-8),r<8&&(r=8),{x:o,y:r}}(e.getBoundingClientRect(),ae(h.children||[]));d(t)},[r,h]),Y(()=>{if(!e)return;const t=e=>{const t=e.target,i=document.querySelector(".context-menu-container");i&&i.contains(t)||s?.()},i=e=>{"Escape"===e.key&&s?.()};return document.addEventListener("mousedown",t),document.addEventListener("keydown",i),()=>{document.removeEventListener("mousedown",t),document.removeEventListener("keydown",i)}},[e,s]),Y(()=>{e||(l(null),d(null))},[e]);const g=e=>e?ie(te,{icon:e,width:16,height:16,className:"context-menu-item-icon"}):null,f=Q(e=>{e.disabled||e.children&&e.children.length>0||(e.action&&e.action(),a?.(e),s?.())},[s,a]),v=Q(e=>{e.children&&e.children.length>0?l(e.id):l(null)},[]);return e?K(ne("div",{className:"context-menu-container",children:[ie("div",{ref:o,className:"context-menu",style:p,children:n.map((e,t)=>{if(e.separator)return ie("div",{className:"context-menu-separator"},t);const i=e.children&&e.children.length>0,n=r===e.id;return ne("div",{ref:t=>{t?m.current.set(e.id,t):m.current.delete(e.id)},className:`context-menu-item ${e.disabled?"context-menu-item--disabled":""} ${e.danger?"context-menu-item--danger":""} ${i?"context-menu-item--has-children":""} ${n?"context-menu-item--active":""}`,onClick:()=>f(e),onMouseEnter:()=>v(e),children:[e.icon&&g(e.icon),ie("span",{className:"context-menu-item-label",children:e.label}),e.checked&&ie(te,{icon:"lucide:check",width:14,height:14,className:"context-menu-item-check"}),e.shortcut&&!i&&ie("span",{className:"context-menu-item-shortcut",children:e.shortcut}),i&&ie(te,{icon:"lucide:chevron-right",width:14,height:14,className:"context-menu-item-arrow"})]},e.id||t)})}),h&&c&&ie("div",{className:"context-menu context-menu-submenu",style:{left:`${c.x}px`,top:`${c.y}px`},onMouseEnter:()=>l(h.id),onMouseLeave:()=>l(null),children:h.children.map((e,t)=>e.separator?ie("div",{className:"context-menu-separator"},`child-sep-${t}`):ne("div",{className:`context-menu-item ${e.disabled?"context-menu-item--disabled":""} ${e.danger?"context-menu-item--danger":""}`,onClick:()=>f(e),children:[e.icon&&g(e.icon),ie("span",{className:"context-menu-item-label",children:e.label}),e.checked&&ie(te,{icon:"lucide:check",width:14,height:14,className:"context-menu-item-check"}),e.shortcut&&ie("span",{className:"context-menu-item-shortcut",children:e.shortcut})]},e.id||t))})]}),document.body):null}import{createPortal as re}from"react-dom";import{useMemo as le,useRef as ce,useEffect as de}from"react";import{Icon as me}from"@iconify/react";import{useState as ue,useCallback as pe,useEffect as he}from"react";function ge(){const[e,t]=ue({x:0,y:0}),[i,n]=ue(!1),s=pe(e=>{i&&t(t=>({x:t.x+e.movementX,y:t.y+e.movementY}))},[i]),a=pe(()=>{n(!1)},[]),o=pe(e=>{const t=e.target;t.closest(".draggable-area")&&!t.closest("button")&&(e.preventDefault(),n(!0))},[]);return he(()=>{if(i)return window.addEventListener("mousemove",s),window.addEventListener("mouseup",a),()=>{window.removeEventListener("mousemove",s),window.removeEventListener("mouseup",a)}},[i,s,a]),{position:e,isDragging:i,startDrag:o}}import{useState as fe,useCallback as ve,useEffect as be}from"react";function we(e,t,i,n,s,a){const[o,r]=fe(e),[l,c]=fe(t),[d,m]=fe(!1),[u,p]=fe(null),[h,g]=fe(0),[f,v]=fe(0),[b,w]=fe(0),[y,x]=fe(0),N=ve(e=>{if(!d||!u)return;const t=e.clientX-h,o=e.clientY-f;let l=b,m=y;const p=u;p.includes("e")?l=Math.min(Math.max(b+t,i),s):p.includes("w")&&(l=Math.min(Math.max(b-t,i),s)),p.includes("s")?m=Math.min(Math.max(y+o,n),a):p.includes("n")&&(m=Math.min(Math.max(y-o,n),a)),r(l),c(m)},[d,u,h,f,b,y,i,n,s,a]),k=ve(()=>{m(!1),p(null)},[]),j=ve((e,t,i,n)=>{e.preventDefault(),e.stopPropagation(),m(!0),p(t),g(e.clientX),v(e.clientY),w(i),x(n)},[]),C=ve(e=>({n:"n-resize",s:"s-resize",e:"e-resize",w:"w-resize",ne:"ne-resize",nw:"nw-resize",se:"se-resize",sw:"sw-resize"}[e]),[]);return be(()=>{if(d)return window.addEventListener("mousemove",N),window.addEventListener("mouseup",k),document.body.style.cursor=C(u||"se"),document.body.style.userSelect="none",()=>{window.removeEventListener("mousemove",N),window.removeEventListener("mouseup",k),document.body.style.cursor="",document.body.style.userSelect=""}},[d,u,N,k,C]),{width:o,height:l,isResizing:d,startResize:j}}import{Fragment as ye,jsx as xe,jsxs as Ne}from"react/jsx-runtime";function ke({title:e,showTitleBar:t=!0,showMinimize:i=!1,showMaximize:n=!1,draggable:s=!0,resizable:a=!0,closeOnBackdrop:o=!0,width:r="auto",height:l="auto",minWidth:c=300,minHeight:d=200,maxWidth:m="80vw",maxHeight:u="80vh",fitContent:p=!1,onClose:h,onMinimize:g,onMaximize:f,children:v,titleSlot:b,actionsSlot:w}){const y=ce(null),x=s?ge():null,N=le(()=>p||"auto"===r||"fit-content"===r||"auto"===l||"fit-content"===l,[p,r,l]),k=(e,t)=>{if("number"==typeof e)return e;if("string"==typeof e){if(e.endsWith("px"))return parseInt(e);if(e.endsWith("vw"))return parseInt(e)/100*window.innerWidth;if(e.endsWith("vh"))return parseInt(e)/100*window.innerHeight}return t},{initialWidth:j,initialHeight:C}=(()=>{if(N)return{initialWidth:0,initialHeight:0};let e=600,t=500;return"auto"!==r&&"fit-content"!==r&&(e="number"==typeof r?r:parseInt(r)),"auto"!==l&&"fit-content"!==l&&(t="number"==typeof l?l:parseInt(l)),{initialWidth:e,initialHeight:t}})(),E=k(c,500),I=k(d,350),D=k(m,.8*window.innerWidth),M=k(u,.8*window.innerHeight),z=a?we(j,C,E,I,D,M):null,O=le(()=>{const e={left:"50%",top:"50%"};let t="-50%",i="-50%";return s&&x&&(t=`calc(-50% + ${x.position.x}px)`,i=`calc(-50% + ${x.position.y}px)`),e.transform=`translate(${t}, ${i})`,e.transformOrigin="center center",N?a&&z&&z.width>0&&(e.width=`${z.width}px`,e.height=`${z.height}px`):a&&z?(e.width=`${z.width}px`,e.height=`${z.height}px`):("auto"!==r&&"fit-content"!==r&&(e.width="number"==typeof r?`${r}px`:r),"auto"!==l&&"fit-content"!==l&&(e.height="number"==typeof l?`${l}px`:l)),c&&(e.minWidth="number"==typeof c?`${c}px`:c),d&&(e.minHeight="number"==typeof d?`${d}px`:d),m&&(e.maxWidth="number"==typeof m?`${m}px`:m),u&&(e.maxHeight="number"==typeof u?`${u}px`:u),e},[s,x,N,a,z,r,l,c,d,m,u]),S=(e,t)=>{if(!a||!z||!y.current)return;const i=y.current.getBoundingClientRect(),n=i.width,s=i.height;z.startResize(e,t,n,s)};return de(()=>{const e=e=>{"Escape"===e.key&&(e.preventDefault(),h?.())};return window.addEventListener("keydown",e),()=>{window.removeEventListener("keydown",e)}},[h]),re(xe("div",{className:"window-overlay",onClick:e=>{o&&e.target===e.currentTarget&&h?.()},children:Ne("div",{ref:y,className:"window-container",style:O,onClick:e=>e.stopPropagation(),children:[t&&Ne("div",{className:"window-title-bar draggable-area",onMouseDown:e=>{s&&x&&x.startDrag(e)},children:[Ne("div",{className:"window-controls",children:[xe("button",{onClick:e=>{e.stopPropagation(),h?.()},className:"window-control-button window-control-button--close",children:xe(me,{icon:"lucide:x",width:7,height:7,className:"window-control-icon"})}),i&&xe("button",{onClick:e=>{e.stopPropagation(),g?.()},className:"window-control-button window-control-button--minimize",children:xe(me,{icon:"lucide:minus",width:7,height:7,className:"window-control-icon"})}),n&&xe("button",{onClick:e=>{e.stopPropagation(),f?.()},className:"window-control-button window-control-button--maximize",children:xe(me,{icon:"lucide:maximize-2",width:7,height:7,className:"window-control-icon"})})]}),xe("div",{className:"window-title-info",children:b||xe("span",{className:"window-title-text",children:e})}),xe("div",{className:"window-title-actions",children:w})]}),xe("div",{className:"window-content",children:v}),a&&Ne(ye,{children:[xe("div",{className:"window-resize-handle window-resize-handle--n",onMouseDown:e=>S(e,"n")}),xe("div",{className:"window-resize-handle window-resize-handle--s",onMouseDown:e=>S(e,"s")}),xe("div",{className:"window-resize-handle window-resize-handle--e",onMouseDown:e=>S(e,"e")}),xe("div",{className:"window-resize-handle window-resize-handle--w",onMouseDown:e=>S(e,"w")}),xe("div",{className:"window-resize-handle window-resize-handle--ne",onMouseDown:e=>S(e,"ne")}),xe("div",{className:"window-resize-handle window-resize-handle--nw",onMouseDown:e=>S(e,"nw")}),xe("div",{className:"window-resize-handle window-resize-handle--se",onMouseDown:e=>S(e,"se")}),xe("div",{className:"window-resize-handle window-resize-handle--sw",onMouseDown:e=>S(e,"sw")})]})]})}),document.body)}import{useState as je,useMemo as Ce,useEffect as Ee}from"react";import{createPortal as Ie}from"react-dom";import{Icon as De}from"@iconify/react";import{jsx as Me,jsxs as ze}from"react/jsx-runtime";var Oe=[{value:"zip",label:"ZIP",ext:".zip"},{value:"tgz",label:"TAR.GZ (gzip)",ext:".tar.gz"},{value:"tarbz2",label:"TAR.BZ2 (bzip2)",ext:".tar.bz2"},{value:"tar",label:"TAR (无压缩)",ext:".tar"}],Se=[{value:"fast",label:"快速",desc:"压缩速度快,文件较大"},{value:"normal",label:"标准",desc:"平衡速度和大小"},{value:"best",label:"最佳",desc:"文件最小,速度较慢"}];function Le({visible:e,filePaths:t,outputDir:i,onConfirm:n,onCancel:s}){const[a,o]=je("zip"),[r,l]=je("normal"),[c,d]=je(""),[m,u]=je(!1),[p,h]=je(""),[g,f]=je(!1),v=Ce(()=>{if(0===t.length)return"archive";if(1===t.length){return(t[0].split("/").pop()||"archive").replace(/\.[^.]+$/,"")}return"压缩文件"},[t]);Ee(()=>{e&&(d(v),o("zip"),l("normal"),u(!1),h(""))},[e,v]);const b=Oe.find(e=>e.value===a)?.ext||".zip",w=`${i}/${c}${b}`;return e?Ie(Me("div",{className:"compress-dialog-overlay",onClick:s,children:ze("div",{className:"compress-dialog",onClick:e=>e.stopPropagation(),children:[ze("div",{className:"compress-dialog-header",children:[ze("div",{className:"compress-dialog-title",children:[Me(De,{icon:"lucide:archive",width:20,height:20}),Me("span",{children:"压缩文件"})]}),Me("button",{className:"compress-dialog-close",onClick:s,children:Me(De,{icon:"lucide:x",width:18,height:18})})]}),ze("div",{className:"compress-dialog-content",children:[ze("div",{className:"compress-dialog-info",children:[Me(De,{icon:"lucide:file-archive",width:16,height:16}),Me("span",{children:1===t.length?t[0].split("/").pop():`${t.length} 个项目`})]}),ze("div",{className:"compress-dialog-field",children:[Me("label",{children:"文件名"}),ze("div",{className:"compress-dialog-input-group",children:[Me("input",{type:"text",value:c,onChange:e=>d(e.target.value),placeholder:"输入文件名"}),Me("span",{className:"compress-dialog-ext",children:b})]})]}),ze("div",{className:"compress-dialog-field",children:[Me("label",{children:"压缩格式"}),Me("select",{value:a,onChange:e=>o(e.target.value),children:Oe.map(e=>Me("option",{value:e.value,children:e.label},e.value))})]}),ze("div",{className:"compress-dialog-field",children:[Me("label",{children:"压缩级别"}),Me("div",{className:"compress-dialog-levels",children:Se.map(e=>ze("label",{className:"compress-dialog-level",children:[Me("input",{type:"radio",name:"level",value:e.value,checked:r===e.value,onChange:()=>l(e.value)}),Me("span",{className:"compress-dialog-level-label",children:e.label}),Me("span",{className:"compress-dialog-level-desc",children:e.desc})]},e.value))})]}),!1,Me("div",{className:"compress-dialog-field compress-dialog-checkbox",children:ze("label",{children:[Me("input",{type:"checkbox",checked:m,onChange:e=>u(e.target.checked)}),Me("span",{children:"压缩后删除源文件"})]})}),ze("div",{className:"compress-dialog-preview",children:[Me("span",{className:"compress-dialog-preview-label",children:"输出位置:"}),Me("span",{className:"compress-dialog-preview-path",children:w})]})]}),ze("div",{className:"compress-dialog-footer",children:[Me("button",{className:"compress-dialog-btn compress-dialog-btn-cancel",onClick:s,children:"取消"}),Me("button",{className:"compress-dialog-btn compress-dialog-btn-confirm",onClick:()=>{n({format:a,level:r,outputName:c+b,deleteSource:m})},disabled:!c.trim(),children:"压缩"})]})]})}),document.body):null}import{createPortal as Pe}from"react-dom";import{Icon as Te}from"@iconify/react";import{jsx as $e,jsxs as Ae}from"react/jsx-runtime";function Re({visible:e,progress:t,onCancel:i,onClose:n,onOpenFolder:s}){const{type:a,status:o,percent:r,currentFile:l,processedCount:c,totalCount:d,error:m,outputPath:u}=t,p="compress"===a?"压缩文件":"解压文件",h="success"===o||"error"===o,g=()=>{h?n?.():i?.()};return e?Pe($e("div",{className:"progress-dialog-overlay",children:Ae("div",{className:"progress-dialog",children:[Ae("div",{className:"progress-dialog-header",children:[Ae("div",{className:"progress-dialog-title",children:[$e(()=>{switch(o){case"processing":return $e(Te,{icon:"lucide:loader-2",width:24,height:24,className:"progress-dialog-icon-spin"});case"success":return $e(Te,{icon:"lucide:check-circle",width:24,height:24,className:"progress-dialog-icon-success"});case"error":return $e(Te,{icon:"lucide:x-circle",width:24,height:24,className:"progress-dialog-icon-error"});default:return $e(Te,{icon:"lucide:archive",width:24,height:24})}},{}),$e("span",{children:p})]}),h&&$e("button",{className:"progress-dialog-close",onClick:g,children:$e(Te,{icon:"lucide:x",width:18,height:18})})]}),Ae("div",{className:"progress-dialog-content",children:[$e("div",{className:"progress-dialog-status",children:(()=>{switch(o){case"pending":return"准备中...";case"processing":return"compress"===a?"正在压缩...":"正在解压...";case"success":return"compress"===a?"压缩完成":"解压完成";case"error":return"操作失败";default:return""}})()}),"processing"===o&&Ae("div",{className:"progress-dialog-bar-container",children:[$e("div",{className:"progress-dialog-bar",children:$e("div",{className:"progress-dialog-bar-fill",style:{width:`${r}%`}})}),Ae("span",{className:"progress-dialog-percent",children:[r,"%"]})]}),l&&"processing"===o&&$e("div",{className:"progress-dialog-current-file",children:l}),d&&d>0&&"processing"===o&&Ae("div",{className:"progress-dialog-count",children:[c||0," / ",d," 个文件"]}),m&&$e("div",{className:"progress-dialog-error",children:m}),"success"===o&&u&&Ae("div",{className:"progress-dialog-output",children:[$e("span",{className:"progress-dialog-output-label",children:"输出位置:"}),$e("span",{className:"progress-dialog-output-path",children:u})]})]}),Ae("div",{className:"progress-dialog-footer",children:["processing"===o&&i&&$e("button",{className:"progress-dialog-btn progress-dialog-btn-cancel",onClick:i,children:"取消"}),"success"===o&&u&&s&&Ae("button",{className:"progress-dialog-btn progress-dialog-btn-folder",onClick:()=>s(u),children:[$e(Te,{icon:"lucide:folder-open",width:16,height:16}),"打开文件夹"]}),h&&$e("button",{className:"progress-dialog-btn progress-dialog-btn-close",onClick:g,children:"关闭"})]})]})}),document.body):null}import Ue from"react";import{Icon as Fe}from"@iconify/react";import{jsx as Ve,jsxs as We}from"react/jsx-runtime";function qe(t,i){if(t===e.FOLDER)return Ve(Fe,{icon:"ic:round-folder",width:48,height:48,className:"file-info-icon"});if(i){const e=p(i,t);return Ve(Fe,{icon:e,width:48,height:48,className:"file-info-icon"})}return Ve(Fe,{icon:{[e.IMAGE]:"material-icon-theme:image",[e.VIDEO]:"material-icon-theme:video",[e.MUSIC]:"material-icon-theme:audio",[e.DOCUMENT]:"material-icon-theme:word",[e.CODE]:"material-icon-theme:javascript",[e.ARCHIVE]:"material-icon-theme:zip",[e.PDF]:"material-icon-theme:pdf",[e.TEXT]:"material-icon-theme:document",[e.APPLICATION]:"material-icon-theme:exe"}[t]||"material-icon-theme:document",width:48,height:48,className:"file-info-icon"})}function He(t,i){switch(t){case e.FOLDER:return"文件夹";case e.IMAGE:return"图片"+(i?` (${i.toUpperCase()})`:"");case e.VIDEO:return"视频"+(i?` (${i.toUpperCase()})`:"");case e.MUSIC:return"音频"+(i?` (${i.toUpperCase()})`:"");case e.DOCUMENT:return"文档"+(i?` (${i.toUpperCase()})`:"");case e.CODE:return"代码文件"+(i?` (${i.toUpperCase()})`:"");case e.ARCHIVE:return"压缩包"+(i?` (${i.toUpperCase()})`:"");default:return i?`${i.toUpperCase()} 文件`:"文件"}}function _e({visible:t,item:i,onClose:n}){if(!t||!i)return null;const s=function(e){const t=e.lastIndexOf(".");if(-1!==t&&0!==t)return e.substring(t+1).toLowerCase()}(i.name),a=function(e){const t=e.lastIndexOf("/");return-1===t?e:e.substring(0,t)||"/"}(i.id);return Ue.useEffect(()=>{const e=e=>{"Escape"===e.key&&n()};return t&&document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[t,n]),Ve("div",{className:"file-info-dialog-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:We("div",{className:"file-info-dialog",children:[We("div",{className:"file-info-dialog-header",children:[We("div",{className:"file-info-dialog-title",children:[qe(i.type,i.name),Ve("span",{className:"file-info-dialog-name",title:i.name,children:i.name})]}),Ve("button",{className:"file-info-dialog-close",onClick:n,children:Ve(Fe,{icon:"lucide:x",width:18,height:18})})]}),We("div",{className:"file-info-dialog-content",children:[We("div",{className:"file-info-row",children:[We("div",{className:"file-info-label",children:[Ve(Fe,{icon:"lucide:file",width:14,height:14}),Ve("span",{children:"类型"})]}),Ve("div",{className:"file-info-value",children:He(i.type,s)})]}),i.type!==e.FOLDER&&i.size&&We("div",{className:"file-info-row",children:[We("div",{className:"file-info-label",children:[Ve(Fe,{icon:"lucide:hard-drive",width:14,height:14}),Ve("span",{children:"大小"})]}),Ve("div",{className:"file-info-value",children:i.size})]}),We("div",{className:"file-info-row",children:[We("div",{className:"file-info-label",children:[Ve(Fe,{icon:"lucide:map-pin",width:14,height:14}),Ve("span",{children:"位置"})]}),Ve("div",{className:"file-info-value file-info-value--path",title:a,children:a})]}),We("div",{className:"file-info-row",children:[We("div",{className:"file-info-label",children:[Ve(Fe,{icon:"lucide:map-pin",width:14,height:14}),Ve("span",{children:"完整路径"})]}),Ve("div",{className:"file-info-value file-info-value--path",title:i.id,children:i.id})]}),i.dateModified&&We("div",{className:"file-info-row",children:[We("div",{className:"file-info-label",children:[Ve(Fe,{icon:"lucide:clock",width:14,height:14}),Ve("span",{children:"修改时间"})]}),Ve("div",{className:"file-info-value",children:i.dateModified})]})]}),Ve("div",{className:"file-info-dialog-footer",children:Ve("button",{className:"file-info-dialog-btn",onClick:n,children:"关闭"})})]})})}import{useState as Ge,useCallback as Be}from"react";function Xe(){const[e,t]=Ge(new Set),[i,n]=Ge(null),[s,a]=Ge(null),o=Be(()=>{t(new Set),n(null)},[]),r=Be((e,i,s=!1,a=!1)=>{e?t(o=>(n(n=>{if(a&&n){const a=i.findIndex(e=>e.id===n),r=i.findIndex(t=>t.id===e);if(-1!==a&&-1!==r){const n=Math.min(a,r),l=Math.max(a,r),c=new Set(s?o:[]);for(let e=n;e<=l;e++){const t=i[e];t&&c.add(t.id)}return t(c),e}}if(s){const i=new Set(o);return i.has(e)?i.delete(e):i.add(e),t(i),e}return t(new Set([e])),e}),o)):o()},[o]),l=Be(e=>{t(new Set(e.map(e=>e.id)))},[]),c=Be(e=>{a(e)},[]),d=Be(t=>e.has(t),[e]);return{selectedIds:e,lastSelectedId:i,editingId:s,clearSelection:o,selectItem:r,selectAll:l,setEditing:c,isSelected:d}}import{useState as Ke,useCallback as Je}from"react";function Ye(t,i,n){const[s,a]=Ke(null),[o,r]=Ke(!1),l=Je((e,n)=>{if(!e.dataTransfer)return;const s=t();s.has(n)||i(n,!1,!1);const a=s.has(n)?s:new Set([n]);e.dataTransfer.setData("text/plain",JSON.stringify([...a])),e.dataTransfer.effectAllowed="move",r(!0)},[t,i]),c=Je((i,n)=>{if(o&&n.type===e.FOLDER){t().has(n.id)||(i.preventDefault(),a(n.id))}},[o,t]),d=Je(()=>{a(null)},[]),m=Je((t,i)=>{if(a(null),r(!1),!t.dataTransfer||i.type!==e.FOLDER)return;const s=t.dataTransfer.getData("text/plain");if(s)try{const e=JSON.parse(s),t=new Set(e);if(t.has(i.id))return;n(i.id,t)}catch{}},[n]),u=Je(()=>{a(null),r(!1)},[]);return{dragOverId:s,isDragging:o,handleDragStart:l,handleDragOver:c,handleDragLeave:d,handleDrop:m,handleDragEnd:u}}import{useState as Ze,useCallback as Qe,useEffect as et}from"react";function tt(t,i){const[n,s]=Ze(!1),[a,o]=Ze(0),[r,l]=Ze(0),[c,d]=Ze(0),[m,u]=Ze(!1),[p,h]=Ze(1),[g,f]=Ze(1),[v,b]=Ze(!1),w=t===e.MUSIC,y=Qe(()=>{const e=i.current;if(e){const t=e.currentTime,i=e.duration;l(t),i&&!isNaN(i)&&(d(i),o(t/i*100))}},[i]),x=Qe(()=>{const e=i.current;e&&(n?(e.pause(),s(!1)):(e.play(),s(!0)))},[n,i]),N=Qe(()=>{const e=i.current;if(e)if(m){const t=g||1;e.volume=t,e.muted=!1,h(t),u(!1)}else f(p),e.volume=0,e.muted=!0,h(0),u(!0)},[m,g,p,i]),k=Qe(e=>{h(e);const t=i.current;t&&(t.volume=e,0===e?(u(!0),t.muted=!0):(u(!1),t.muted=!1))},[i]),j=Qe(e=>{const t=i.current;t&&c&&(t.currentTime=e,l(e),o(e/c*100))},[c,i]),C=Qe(e=>{if(isNaN(e))return"0:00";return`${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`},[]),E=Qe(()=>{const n=i.current;(t===e.VIDEO||w)&&n&&(n.volume=p,n.play().catch(()=>{}),s(!0))},[t,w,p,i]);return et(()=>{const e=i.current;if(e)return e.addEventListener("timeupdate",y),e.addEventListener("loadedmetadata",y),e.addEventListener("ended",()=>{s(!1)}),()=>{e.removeEventListener("timeupdate",y),e.removeEventListener("loadedmetadata",y)}},[i,y]),{isPlaying:n,progress:a,currentTime:r,duration:c,isMuted:m,volume:p,showControls:v,isAudio:w,togglePlay:x,toggleMute:N,handleVolumeChange:k,seekTo:j,formatTime:C,autoPlay:E,updateProgress:y}}import{useState as it,useCallback as nt,useEffect as st}from"react";function at(t){const i=new Map,[n,s]=it(new Map),a=nt(async t=>{if(t.type===e.APPLICATION&&t.id){if(i.has(t.id)){const e=i.get(t.id);return void(e&&s(i=>new Map(i).set(t.id,e)))}if(!n.has(t.id)&&void 0!==window.fileExplorerAPI&&window.fileExplorerAPI.getApplicationIcon)try{const e=await window.fileExplorerAPI.getApplicationIcon(t.id);e&&(i.set(t.id,e),s(i=>new Map(i).set(t.id,e)))}catch(e){}}},[n]);st(()=>{t.forEach(t=>{t.type!==e.APPLICATION||n.has(t.id)||a(t)})},[t,n,a]);return{getAppIconUrl:nt(e=>n.get(e.id),[n]),loadApplicationIcon:a}}export{V as Breadcrumb,Le as CompressDialog,oe as ContextMenu,N as FileGrid,v as FileIcon,_e as FileInfoDialog,M as FileList,S as FileListView,$ as FileSidebar,e as FileType,Re as ProgressDialog,E as SortIndicator,X as StatusBar,H as Toolbar,ke as Window,at as useApplicationIcon,Ye as useDragAndDrop,tt as useMediaPlayer,Xe as useSelection,ge as useWindowDrag,we as useWindowResize};