@huyooo/file-explorer-frontend-react 0.4.16 → 0.4.19

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 +3 -1
  2. package/dist/index.js +1 -3453
  3. package/package.json +3 -3
  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 -234
  13. package/src/components/FileGrid.tsx +0 -277
  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,3453 +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
- ] }) : name
1253
- }
1254
- );
1255
- }
1256
- function FileGrid({
1257
- items,
1258
- selectedIds,
1259
- editingId,
1260
- dragOverId,
1261
- getAppIconUrl,
1262
- onSelect,
1263
- onOpen,
1264
- onContextMenu,
1265
- onContextMenuEmpty,
1266
- onNameClick,
1267
- onRename,
1268
- onRenameCancel,
1269
- onDragStart,
1270
- onDragOver,
1271
- onDragLeave,
1272
- onDrop,
1273
- onThumbnailError
1274
- }) {
1275
- const renameInputRef = useRef(null);
1276
- const handleEmptyContextMenu = (e) => {
1277
- const target = e.target;
1278
- if (!target.closest(".file-grid-item")) {
1279
- onContextMenuEmpty?.(e);
1280
- }
1281
- };
1282
- const hasThumbnail = (item) => {
1283
- if (item.type === FileType.APPLICATION && getAppIconUrl?.(item)) {
1284
- return true;
1285
- }
1286
- if (item.type === FileType.IMAGE) {
1287
- return !!item.thumbnailUrl;
1288
- }
1289
- if (item.type === FileType.VIDEO) {
1290
- return !!item.thumbnailUrl;
1291
- }
1292
- return false;
1293
- };
1294
- const handleVideoHover = (e, isHover) => {
1295
- const video = e.currentTarget;
1296
- if (isHover) {
1297
- video.play().catch(() => {
1298
- });
1299
- } else {
1300
- video.pause();
1301
- video.currentTime = 0;
1302
- }
1303
- };
1304
- const handleRename = (item, e) => {
1305
- const input = e.target;
1306
- const newName = input.value.trim();
1307
- if (newName && newName !== item.name) {
1308
- onRename?.(item, newName);
1309
- } else {
1310
- onRenameCancel?.(item);
1311
- }
1312
- };
1313
- const handleEnterKey = (e) => {
1314
- e.currentTarget.blur();
1315
- };
1316
- const handleEscapeKey = (e) => {
1317
- const input = e.currentTarget;
1318
- const item = items.find((i) => i.id === editingId);
1319
- if (item) {
1320
- input.value = item.name;
1321
- }
1322
- input.blur();
1323
- };
1324
- return /* @__PURE__ */ jsx2("div", { className: "file-grid", onContextMenu: (e) => {
1325
- e.preventDefault();
1326
- handleEmptyContextMenu(e);
1327
- }, children: items.map((item) => {
1328
- const isSelected = selectedIds.has(item.id);
1329
- const isEditing = editingId === item.id;
1330
- const isDragOver = dragOverId === item.id;
1331
- const hasThumb = hasThumbnail(item);
1332
- const appIconUrl = item.type === FileType.APPLICATION ? getAppIconUrl?.(item) : void 0;
1333
- let itemClassName = "file-grid-item";
1334
- if (isSelected && !isEditing) {
1335
- itemClassName += " file-grid-item--selected";
1336
- } else if (isDragOver) {
1337
- itemClassName += " file-grid-item--drag-over";
1338
- } else {
1339
- itemClassName += " file-grid-item--normal";
1340
- }
1341
- return /* @__PURE__ */ jsxs(
1342
- "div",
1343
- {
1344
- draggable: !isEditing,
1345
- onDragStart: (e) => onDragStart?.(e, item),
1346
- onDragOver: (e) => {
1347
- e.preventDefault();
1348
- onDragOver?.(e, item);
1349
- },
1350
- onDragLeave: (e) => onDragLeave?.(e),
1351
- onDrop: (e) => {
1352
- e.preventDefault();
1353
- onDrop?.(e, item);
1354
- },
1355
- onClick: (e) => {
1356
- e.stopPropagation();
1357
- onSelect?.(item, e);
1358
- },
1359
- onDoubleClick: (e) => {
1360
- e.stopPropagation();
1361
- onOpen?.(item);
1362
- },
1363
- onContextMenu: (e) => {
1364
- e.preventDefault();
1365
- e.stopPropagation();
1366
- onContextMenu?.(item, e);
1367
- },
1368
- className: itemClassName,
1369
- children: [
1370
- /* @__PURE__ */ jsxs("div", { className: "file-grid-item-icon", children: [
1371
- appIconUrl && /* @__PURE__ */ jsx2(
1372
- "img",
1373
- {
1374
- src: appIconUrl,
1375
- alt: item.name,
1376
- className: `file-grid-item-thumbnail file-grid-item-thumbnail--application ${isSelected && !isEditing ? "file-grid-item-thumbnail--selected" : ""}`
1377
- }
1378
- ),
1379
- !appIconUrl && item.type === FileType.VIDEO && item.thumbnailUrl && hasThumb && /* @__PURE__ */ jsxs("div", { className: "file-grid-item-thumbnail file-grid-item-thumbnail--video", children: [
1380
- /* @__PURE__ */ jsx2(
1381
- "img",
1382
- {
1383
- src: item.thumbnailUrl,
1384
- alt: item.name,
1385
- className: "file-grid-item-thumbnail",
1386
- onError: (e) => onThumbnailError?.(item, e)
1387
- }
1388
- ),
1389
- /* @__PURE__ */ jsx2("div", { className: "file-grid-item-video-play", children: /* @__PURE__ */ jsx2("div", { className: "file-grid-item-video-play-icon" }) })
1390
- ] }),
1391
- !appIconUrl && item.type === FileType.IMAGE && item.thumbnailUrl && hasThumb && /* @__PURE__ */ jsx2(
1392
- "img",
1393
- {
1394
- src: item.thumbnailUrl,
1395
- alt: item.name,
1396
- className: "file-grid-item-thumbnail",
1397
- onError: (e) => onThumbnailError?.(item, e)
1398
- }
1399
- ),
1400
- !appIconUrl && !hasThumb && /* @__PURE__ */ jsx2(FileIcon, { type: item.type, name: item.name, size: 48 })
1401
- ] }),
1402
- /* @__PURE__ */ jsx2("div", { className: "file-grid-item-name-wrapper", children: isEditing ? /* @__PURE__ */ jsx2(
1403
- "input",
1404
- {
1405
- ref: renameInputRef,
1406
- type: "text",
1407
- className: "file-grid-item-rename-input",
1408
- defaultValue: item.name,
1409
- onBlur: (e) => handleRename(item, e),
1410
- onKeyDown: (e) => {
1411
- if (e.key === "Enter") {
1412
- handleEnterKey(e);
1413
- } else if (e.key === "Escape") {
1414
- handleEscapeKey(e);
1415
- }
1416
- },
1417
- autoFocus: true
1418
- }
1419
- ) : /* @__PURE__ */ jsx2(
1420
- FileName,
1421
- {
1422
- name: item.name,
1423
- isFolder: item.type === FileType.FOLDER,
1424
- isSelected,
1425
- onClick: (e) => {
1426
- e.stopPropagation();
1427
- onNameClick?.(item, e);
1428
- }
1429
- }
1430
- ) })
1431
- ]
1432
- },
1433
- item.id
1434
- );
1435
- }) });
1436
- }
1437
-
1438
- // src/components/FileList.tsx
1439
- import { useRef as useRef2 } from "react";
1440
-
1441
- // src/components/SortIndicator.tsx
1442
- import { Icon as Icon2 } from "@iconify/react";
1443
- import { jsx as jsx3 } from "react/jsx-runtime";
1444
- function SortIndicator({ direction }) {
1445
- return /* @__PURE__ */ jsx3("span", { className: "sort-indicator", children: /* @__PURE__ */ jsx3(
1446
- Icon2,
1447
- {
1448
- icon: direction === "asc" ? "lucide:chevron-up" : "lucide:chevron-down",
1449
- width: 12,
1450
- height: 12
1451
- }
1452
- ) });
1453
- }
1454
-
1455
- // src/components/FileList.tsx
1456
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1457
- function getTypeLabel(type) {
1458
- const labels = {
1459
- [FileType.FOLDER]: "\u6587\u4EF6\u5939",
1460
- [FileType.FILE]: "\u6587\u4EF6",
1461
- [FileType.IMAGE]: "\u56FE\u7247",
1462
- [FileType.VIDEO]: "\u89C6\u9891",
1463
- [FileType.MUSIC]: "\u97F3\u9891",
1464
- [FileType.DOCUMENT]: "\u6587\u6863",
1465
- [FileType.CODE]: "\u4EE3\u7801",
1466
- [FileType.TEXT]: "\u6587\u672C",
1467
- [FileType.PDF]: "PDF",
1468
- [FileType.ARCHIVE]: "\u538B\u7F29\u5305",
1469
- [FileType.APPLICATION]: "\u5E94\u7528\u7A0B\u5E8F",
1470
- [FileType.UNKNOWN]: "\u672A\u77E5"
1471
- };
1472
- return labels[type] || type;
1473
- }
1474
- function FileList({
1475
- items,
1476
- selectedIds,
1477
- sortConfig,
1478
- editingId,
1479
- dragOverId,
1480
- onSelect,
1481
- onOpen,
1482
- onContextMenu,
1483
- onContextMenuEmpty,
1484
- onNameClick,
1485
- onRename,
1486
- onRenameCancel,
1487
- onSort,
1488
- onDragStart,
1489
- onDragOver,
1490
- onDragLeave,
1491
- onDrop
1492
- }) {
1493
- const renameInputRef = useRef2(null);
1494
- const handleEmptyContextMenu = (e) => {
1495
- const target = e.target;
1496
- if (!target.closest("tr")) {
1497
- onContextMenuEmpty?.(e);
1498
- }
1499
- };
1500
- const handleRename = (item, e) => {
1501
- const input = e.target;
1502
- const newName = input.value.trim();
1503
- if (newName && newName !== item.name) {
1504
- onRename?.(item, newName);
1505
- } else {
1506
- onRenameCancel?.(item);
1507
- }
1508
- };
1509
- const handleEnterKey = (e) => {
1510
- e.currentTarget.blur();
1511
- };
1512
- const handleEscapeKey = (e) => {
1513
- const input = e.currentTarget;
1514
- const item = items.find((i) => i.id === editingId);
1515
- if (item) {
1516
- input.value = item.name;
1517
- }
1518
- input.blur();
1519
- };
1520
- return /* @__PURE__ */ jsx4("div", { className: "file-list", onContextMenu: (e) => {
1521
- e.preventDefault();
1522
- handleEmptyContextMenu(e);
1523
- }, children: /* @__PURE__ */ jsxs2("table", { className: "file-list-table", children: [
1524
- /* @__PURE__ */ jsx4("thead", { className: "file-list-header", children: /* @__PURE__ */ jsxs2("tr", { children: [
1525
- /* @__PURE__ */ jsxs2(
1526
- "th",
1527
- {
1528
- className: "file-list-header-cell file-list-header-cell--name",
1529
- onClick: () => onSort?.("name"),
1530
- children: [
1531
- "\u540D\u79F0",
1532
- sortConfig?.field === "name" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1533
- ]
1534
- }
1535
- ),
1536
- /* @__PURE__ */ jsxs2(
1537
- "th",
1538
- {
1539
- className: "file-list-header-cell",
1540
- onClick: () => onSort?.("dateModified"),
1541
- children: [
1542
- "\u4FEE\u6539\u65E5\u671F",
1543
- sortConfig?.field === "dateModified" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1544
- ]
1545
- }
1546
- ),
1547
- /* @__PURE__ */ jsxs2(
1548
- "th",
1549
- {
1550
- className: "file-list-header-cell",
1551
- onClick: () => onSort?.("size"),
1552
- children: [
1553
- "\u5927\u5C0F",
1554
- sortConfig?.field === "size" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1555
- ]
1556
- }
1557
- ),
1558
- /* @__PURE__ */ jsxs2(
1559
- "th",
1560
- {
1561
- className: "file-list-header-cell",
1562
- onClick: () => onSort?.("type"),
1563
- children: [
1564
- "\u7C7B\u578B",
1565
- sortConfig?.field === "type" && /* @__PURE__ */ jsx4(SortIndicator, { direction: sortConfig.direction })
1566
- ]
1567
- }
1568
- )
1569
- ] }) }),
1570
- /* @__PURE__ */ jsx4("tbody", { className: "file-list-body", children: items.map((item, index) => {
1571
- const isSelected = selectedIds.has(item.id);
1572
- const isEditing = editingId === item.id;
1573
- const isDragOver = dragOverId === item.id;
1574
- let rowClassName = "file-list-row";
1575
- if (isSelected) {
1576
- rowClassName += " file-list-row--selected";
1577
- } else if (isDragOver) {
1578
- rowClassName += " file-list-row--drag-over";
1579
- } else if (index % 2 === 0) {
1580
- rowClassName += " file-list-row--even";
1581
- } else {
1582
- rowClassName += " file-list-row--odd";
1583
- }
1584
- return /* @__PURE__ */ jsxs2(
1585
- "tr",
1586
- {
1587
- draggable: !isEditing,
1588
- onDragStart: (e) => onDragStart?.(e, item),
1589
- onDragOver: (e) => {
1590
- e.preventDefault();
1591
- onDragOver?.(e, item);
1592
- },
1593
- onDragLeave: (e) => onDragLeave?.(e),
1594
- onDrop: (e) => {
1595
- e.preventDefault();
1596
- onDrop?.(e, item);
1597
- },
1598
- onClick: (e) => {
1599
- e.stopPropagation();
1600
- onSelect?.(item, e);
1601
- },
1602
- onDoubleClick: (e) => {
1603
- e.stopPropagation();
1604
- onOpen?.(item);
1605
- },
1606
- onContextMenu: (e) => {
1607
- e.preventDefault();
1608
- e.stopPropagation();
1609
- onContextMenu?.(item, e);
1610
- },
1611
- className: rowClassName,
1612
- children: [
1613
- /* @__PURE__ */ jsxs2("td", { className: `file-list-cell file-list-cell--name ${isSelected ? "file-list-cell--selected" : ""}`, children: [
1614
- /* @__PURE__ */ jsx4(FileIcon, { type: item.type, name: item.name, size: 16 }),
1615
- isEditing ? /* @__PURE__ */ jsx4(
1616
- "input",
1617
- {
1618
- ref: renameInputRef,
1619
- type: "text",
1620
- className: "file-list-rename-input",
1621
- defaultValue: item.name,
1622
- onBlur: (e) => handleRename(item, e),
1623
- onKeyDown: (e) => {
1624
- if (e.key === "Enter") {
1625
- handleEnterKey(e);
1626
- } else if (e.key === "Escape") {
1627
- handleEscapeKey(e);
1628
- }
1629
- },
1630
- autoFocus: true
1631
- }
1632
- ) : /* @__PURE__ */ jsx4(
1633
- "span",
1634
- {
1635
- onClick: (e) => {
1636
- e.stopPropagation();
1637
- onNameClick?.(item, e);
1638
- },
1639
- className: `file-list-name ${isSelected ? "file-list-name--selected" : ""}`,
1640
- children: item.name
1641
- }
1642
- )
1643
- ] }),
1644
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell ${isSelected ? "file-list-cell--selected" : ""}`, children: item.dateModified || "--" }),
1645
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell file-list-cell--size ${isSelected ? "file-list-cell--selected" : ""}`, children: item.size || "--" }),
1646
- /* @__PURE__ */ jsx4("td", { className: `file-list-cell ${isSelected ? "file-list-cell--selected" : ""}`, children: getTypeLabel(item.type) })
1647
- ]
1648
- },
1649
- item.id
1650
- );
1651
- }) })
1652
- ] }) });
1653
- }
1654
-
1655
- // src/components/FileListView.tsx
1656
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1657
- var FileListView = forwardRef(
1658
- ({
1659
- items,
1660
- viewMode = "grid",
1661
- loading = false,
1662
- adapter,
1663
- currentPath,
1664
- getAppIconUrl,
1665
- onOpen,
1666
- onSelectionChange,
1667
- onContextMenu,
1668
- onContextMenuEmpty,
1669
- onRename,
1670
- onSortChange,
1671
- onMove
1672
- }, ref) => {
1673
- const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
1674
- const [editingId, setEditingId] = useState(null);
1675
- const [dragOverId, setDragOverId] = useState(null);
1676
- const [sortConfig, setSortConfig] = useState({
1677
- field: "name",
1678
- direction: "asc"
1679
- });
1680
- const selectedItems = items.filter((item) => selectedIds.has(item.id));
1681
- const handleSelect = useCallback(
1682
- (item, e) => {
1683
- if (e.metaKey || e.ctrlKey) {
1684
- setSelectedIds((prev) => {
1685
- const newSet = new Set(prev);
1686
- if (newSet.has(item.id)) {
1687
- newSet.delete(item.id);
1688
- } else {
1689
- newSet.add(item.id);
1690
- }
1691
- const newItems = items.filter((i) => newSet.has(i.id));
1692
- onSelectionChange?.(newSet, newItems);
1693
- return newSet;
1694
- });
1695
- } else if (e.shiftKey && selectedIds.size > 0) {
1696
- const lastId = Array.from(selectedIds).pop();
1697
- const lastIndex = items.findIndex((i) => i.id === lastId);
1698
- const currentIndex = items.findIndex((i) => i.id === item.id);
1699
- const start = Math.min(lastIndex, currentIndex);
1700
- const end = Math.max(lastIndex, currentIndex);
1701
- const newSet = /* @__PURE__ */ new Set();
1702
- for (let i = start; i <= end; i++) {
1703
- newSet.add(items[i].id);
1704
- }
1705
- setSelectedIds(newSet);
1706
- const newItems = items.filter((i) => newSet.has(i.id));
1707
- onSelectionChange?.(newSet, newItems);
1708
- } else {
1709
- const newSet = /* @__PURE__ */ new Set([item.id]);
1710
- setSelectedIds(newSet);
1711
- onSelectionChange?.(newSet, [item]);
1712
- }
1713
- },
1714
- [items, selectedIds, onSelectionChange]
1715
- );
1716
- const handleEmptyClick = useCallback(
1717
- (e) => {
1718
- if (e.target === e.currentTarget) {
1719
- clearSelection();
1720
- }
1721
- },
1722
- []
1723
- );
1724
- const clearSelection = useCallback(() => {
1725
- setSelectedIds(/* @__PURE__ */ new Set());
1726
- onSelectionChange?.(/* @__PURE__ */ new Set(), []);
1727
- }, [onSelectionChange]);
1728
- const handleOpen = useCallback(
1729
- (item) => {
1730
- onOpen?.(item);
1731
- },
1732
- [onOpen]
1733
- );
1734
- const handleContextMenu = useCallback(
1735
- (item, e) => {
1736
- if (!selectedIds.has(item.id)) {
1737
- const newSet = /* @__PURE__ */ new Set([item.id]);
1738
- setSelectedIds(newSet);
1739
- onSelectionChange?.(newSet, [item]);
1740
- }
1741
- onContextMenu?.(e, item);
1742
- },
1743
- [selectedIds, onSelectionChange, onContextMenu]
1744
- );
1745
- const handleEmptyContextMenu = useCallback(
1746
- (e) => {
1747
- const target = e.target;
1748
- if (!target.closest(".file-grid-item") && !target.closest(".file-list-row")) {
1749
- clearSelection();
1750
- onContextMenuEmpty?.(e);
1751
- }
1752
- },
1753
- [clearSelection, onContextMenuEmpty]
1754
- );
1755
- const handleEmptyContextMenuFromChild = useCallback(
1756
- (e) => {
1757
- clearSelection();
1758
- onContextMenuEmpty?.(e);
1759
- },
1760
- [clearSelection, onContextMenuEmpty]
1761
- );
1762
- const handleNameClick = useCallback(
1763
- (item, e) => {
1764
- if (selectedIds.has(item.id) && selectedIds.size === 1) {
1765
- setTimeout(() => {
1766
- if (selectedIds.has(item.id)) {
1767
- setEditingId(item.id);
1768
- }
1769
- }, 500);
1770
- }
1771
- },
1772
- [selectedIds]
1773
- );
1774
- const handleRename = useCallback(
1775
- (item, newName) => {
1776
- if (newName && newName !== item.name) {
1777
- onRename?.(item, newName);
1778
- }
1779
- setEditingId(null);
1780
- },
1781
- [onRename]
1782
- );
1783
- const handleRenameCancel = useCallback(() => {
1784
- setEditingId(null);
1785
- }, []);
1786
- const handleSort = useCallback(
1787
- (field) => {
1788
- setSortConfig((prev) => {
1789
- const newConfig = prev.field === field ? { ...prev, direction: prev.direction === "asc" ? "desc" : "asc" } : { field, direction: "asc" };
1790
- onSortChange?.(newConfig);
1791
- return newConfig;
1792
- });
1793
- },
1794
- [onSortChange]
1795
- );
1796
- const handleDragStart = useCallback(
1797
- (e, item) => {
1798
- if (!selectedIds.has(item.id)) {
1799
- const newSet = /* @__PURE__ */ new Set([item.id]);
1800
- setSelectedIds(newSet);
1801
- onSelectionChange?.(newSet, [item]);
1802
- }
1803
- e.dataTransfer.setData(
1804
- "text/plain",
1805
- JSON.stringify([...selectedIds])
1806
- );
1807
- },
1808
- [selectedIds, onSelectionChange]
1809
- );
1810
- const handleDragOver = useCallback(
1811
- (e, item) => {
1812
- if (item.type === FileType.FOLDER && !selectedIds.has(item.id)) {
1813
- setDragOverId(item.id);
1814
- }
1815
- },
1816
- [selectedIds]
1817
- );
1818
- const handleDragLeave = useCallback(() => {
1819
- setDragOverId(null);
1820
- }, []);
1821
- const handleDrop = useCallback(
1822
- (e, targetItem) => {
1823
- setDragOverId(null);
1824
- if (targetItem.type !== FileType.FOLDER) return;
1825
- const data = e.dataTransfer.getData("text/plain");
1826
- if (!data) return;
1827
- try {
1828
- const draggedIds = JSON.parse(data);
1829
- if (draggedIds.includes(targetItem.id)) return;
1830
- onMove?.(draggedIds, targetItem.id);
1831
- clearSelection();
1832
- } catch (error) {
1833
- console.error("\u62D6\u62FD\u89E3\u6790\u5931\u8D25:", error);
1834
- }
1835
- },
1836
- [onMove, clearSelection]
1837
- );
1838
- const startRename = useCallback((id) => {
1839
- setEditingId(id);
1840
- }, []);
1841
- const selectAll = useCallback(() => {
1842
- const newSet = new Set(items.map((i) => i.id));
1843
- setSelectedIds(newSet);
1844
- onSelectionChange?.(newSet, items);
1845
- }, [items, onSelectionChange]);
1846
- useImperativeHandle(
1847
- ref,
1848
- () => ({
1849
- clearSelection,
1850
- startRename,
1851
- selectAll,
1852
- selectedIds,
1853
- selectedItems
1854
- }),
1855
- [selectedIds, selectedItems, clearSelection, startRename, selectAll]
1856
- );
1857
- return /* @__PURE__ */ jsxs3(
1858
- "div",
1859
- {
1860
- className: "file-list-view",
1861
- onClick: handleEmptyClick,
1862
- onContextMenu: (e) => {
1863
- e.preventDefault();
1864
- handleEmptyContextMenu(e);
1865
- },
1866
- children: [
1867
- loading && /* @__PURE__ */ jsxs3("div", { className: "file-list-view-loading", children: [
1868
- /* @__PURE__ */ jsx5("div", { className: "file-list-view-spinner" }),
1869
- /* @__PURE__ */ jsx5("p", { children: "\u52A0\u8F7D\u4E2D..." })
1870
- ] }),
1871
- !loading && items.length === 0 && /* @__PURE__ */ jsxs3("div", { className: "file-list-view-empty", children: [
1872
- /* @__PURE__ */ jsx5(Icon3, { icon: "lucide:folder-open", width: 64, height: 64, className: "file-list-view-empty-icon" }),
1873
- /* @__PURE__ */ jsx5("p", { children: "\u6587\u4EF6\u5939\u4E3A\u7A7A" })
1874
- ] }),
1875
- !loading && items.length > 0 && viewMode === "grid" && /* @__PURE__ */ jsx5(
1876
- FileGrid,
1877
- {
1878
- items,
1879
- selectedIds,
1880
- editingId,
1881
- dragOverId,
1882
- getAppIconUrl,
1883
- onSelect: handleSelect,
1884
- onOpen: handleOpen,
1885
- onContextMenu: handleContextMenu,
1886
- onContextMenuEmpty: handleEmptyContextMenuFromChild,
1887
- onNameClick: handleNameClick,
1888
- onRename: handleRename,
1889
- onRenameCancel: handleRenameCancel,
1890
- onDragStart: handleDragStart,
1891
- onDragOver: handleDragOver,
1892
- onDragLeave: handleDragLeave,
1893
- onDrop: handleDrop
1894
- }
1895
- ),
1896
- !loading && items.length > 0 && viewMode === "list" && /* @__PURE__ */ jsx5(
1897
- FileList,
1898
- {
1899
- items,
1900
- selectedIds,
1901
- editingId,
1902
- dragOverId,
1903
- sortConfig,
1904
- onSelect: handleSelect,
1905
- onOpen: handleOpen,
1906
- onContextMenu: handleContextMenu,
1907
- onContextMenuEmpty: handleEmptyContextMenuFromChild,
1908
- onNameClick: handleNameClick,
1909
- onRename: handleRename,
1910
- onRenameCancel: handleRenameCancel,
1911
- onSort: handleSort,
1912
- onDragStart: handleDragStart,
1913
- onDragOver: handleDragOver,
1914
- onDragLeave: handleDragLeave,
1915
- onDrop: handleDrop
1916
- }
1917
- )
1918
- ]
1919
- }
1920
- );
1921
- }
1922
- );
1923
- FileListView.displayName = "FileListView";
1924
-
1925
- // src/components/FileSidebar.tsx
1926
- import { Icon as Icon4 } from "@iconify/react";
1927
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1928
- function FileSidebar({ sections, activeId, onNavigate }) {
1929
- const handleNavigate = (item) => {
1930
- onNavigate?.(item);
1931
- };
1932
- const getIconName = (iconName) => {
1933
- if (!iconName) return "mdi:folder";
1934
- if (iconName.includes(":")) return iconName;
1935
- return `lucide:${iconName.toLowerCase()}`;
1936
- };
1937
- return /* @__PURE__ */ jsx6("div", { className: "file-sidebar", children: sections.map((section) => /* @__PURE__ */ jsxs4("div", { className: "file-sidebar-section", children: [
1938
- /* @__PURE__ */ jsx6("div", { className: "file-sidebar-section-title", children: section.title }),
1939
- /* @__PURE__ */ jsx6("ul", { className: "file-sidebar-list", children: section.items.map((item) => {
1940
- const isActive = activeId === item.id;
1941
- return /* @__PURE__ */ jsxs4(
1942
- "li",
1943
- {
1944
- onClick: () => handleNavigate(item),
1945
- className: `file-sidebar-item ${isActive ? "file-sidebar-item--active" : ""}`,
1946
- children: [
1947
- /* @__PURE__ */ jsx6(
1948
- Icon4,
1949
- {
1950
- icon: getIconName(item.icon),
1951
- width: 18,
1952
- height: 18,
1953
- className: isActive ? "file-sidebar-item-icon--active" : "file-sidebar-item-icon"
1954
- }
1955
- ),
1956
- /* @__PURE__ */ jsx6("span", { children: item.label })
1957
- ]
1958
- },
1959
- item.id
1960
- );
1961
- }) })
1962
- ] }, section.id)) });
1963
- }
1964
-
1965
- // src/components/Toolbar.tsx
1966
- import { Icon as Icon6 } from "@iconify/react";
1967
-
1968
- // src/components/Breadcrumb.tsx
1969
- import { Icon as Icon5 } from "@iconify/react";
1970
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1971
- function Breadcrumb({ items, onNavigate }) {
1972
- const handleClick = (item, index) => {
1973
- if (index < items.length - 1) {
1974
- onNavigate?.(item, index);
1975
- }
1976
- };
1977
- return /* @__PURE__ */ jsx7("div", { className: "file-breadcrumb", children: items.map((item, index) => /* @__PURE__ */ jsxs5("span", { className: "file-breadcrumb-item", children: [
1978
- /* @__PURE__ */ jsx7(
1979
- "span",
1980
- {
1981
- onClick: () => handleClick(item, index),
1982
- className: `file-breadcrumb-link ${index === items.length - 1 ? "file-breadcrumb-link--current" : ""}`,
1983
- children: item.name
1984
- }
1985
- ),
1986
- index < items.length - 1 && /* @__PURE__ */ jsx7(Icon5, { icon: "lucide:chevron-right", width: 14, height: 14, className: "file-breadcrumb-separator" })
1987
- ] }, item.id)) });
1988
- }
1989
-
1990
- // src/components/Toolbar.tsx
1991
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1992
- function Toolbar({
1993
- canGoBack = false,
1994
- canGoForward = false,
1995
- breadcrumbs = [],
1996
- viewMode = "grid",
1997
- searchQuery = "",
1998
- showSearch = false,
1999
- showViewToggle = true,
2000
- draggable = false,
2001
- onBack,
2002
- onForward,
2003
- onBreadcrumbNavigate,
2004
- onViewModeChange,
2005
- onSearchQueryChange,
2006
- children,
2007
- breadcrumbSlot,
2008
- actionsSlot
2009
- }) {
2010
- return /* @__PURE__ */ jsxs6(
2011
- "div",
2012
- {
2013
- className: `file-toolbar ${draggable ? "file-toolbar--draggable" : ""}`,
2014
- children: [
2015
- /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-nav", children: [
2016
- /* @__PURE__ */ jsx8(
2017
- "button",
2018
- {
2019
- className: "file-toolbar-button",
2020
- onClick: onBack,
2021
- disabled: !canGoBack,
2022
- title: "\u540E\u9000",
2023
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:chevron-left", width: 18, height: 18 })
2024
- }
2025
- ),
2026
- /* @__PURE__ */ jsx8(
2027
- "button",
2028
- {
2029
- className: "file-toolbar-button",
2030
- onClick: onForward,
2031
- disabled: !canGoForward,
2032
- title: "\u524D\u8FDB",
2033
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:chevron-right", width: 18, height: 18 })
2034
- }
2035
- )
2036
- ] }),
2037
- /* @__PURE__ */ jsx8("div", { className: "file-toolbar-breadcrumb", children: breadcrumbSlot || breadcrumbs.length > 0 && /* @__PURE__ */ jsx8(
2038
- Breadcrumb,
2039
- {
2040
- items: breadcrumbs,
2041
- onNavigate: onBreadcrumbNavigate
2042
- }
2043
- ) }),
2044
- children && /* @__PURE__ */ jsx8("div", { className: "file-toolbar-custom", children }),
2045
- /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-actions", children: [
2046
- showSearch && /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-search", children: [
2047
- /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:search", width: 16, height: 16, className: "file-toolbar-search-icon" }),
2048
- /* @__PURE__ */ jsx8(
2049
- "input",
2050
- {
2051
- type: "text",
2052
- value: searchQuery,
2053
- onChange: (e) => onSearchQueryChange?.(e.target.value),
2054
- placeholder: "\u641C\u7D22",
2055
- className: "file-toolbar-search-input"
2056
- }
2057
- )
2058
- ] }),
2059
- showViewToggle && /* @__PURE__ */ jsxs6("div", { className: "file-toolbar-view-toggle", children: [
2060
- /* @__PURE__ */ jsx8(
2061
- "button",
2062
- {
2063
- onClick: () => onViewModeChange?.("grid"),
2064
- className: `file-toolbar-button ${viewMode === "grid" ? "file-toolbar-button--active" : ""}`,
2065
- title: "\u7F51\u683C\u89C6\u56FE",
2066
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:layout-grid", width: 18, height: 18 })
2067
- }
2068
- ),
2069
- /* @__PURE__ */ jsx8(
2070
- "button",
2071
- {
2072
- onClick: () => onViewModeChange?.("list"),
2073
- className: `file-toolbar-button ${viewMode === "list" ? "file-toolbar-button--active" : ""}`,
2074
- title: "\u5217\u8868\u89C6\u56FE",
2075
- children: /* @__PURE__ */ jsx8(Icon6, { icon: "lucide:list", width: 18, height: 18 })
2076
- }
2077
- )
2078
- ] }),
2079
- actionsSlot
2080
- ] })
2081
- ]
2082
- }
2083
- );
2084
- }
2085
-
2086
- // src/components/StatusBar.tsx
2087
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2088
- function StatusBar({ itemCount = 0, selectedCount = 0, children }) {
2089
- return /* @__PURE__ */ jsx9("div", { className: "file-status-bar", children: children || /* @__PURE__ */ jsxs7(Fragment2, { children: [
2090
- /* @__PURE__ */ jsxs7("span", { children: [
2091
- itemCount,
2092
- " \u4E2A\u9879\u76EE"
2093
- ] }),
2094
- selectedCount > 0 && /* @__PURE__ */ jsxs7("span", { children: [
2095
- " \u2022 \u5DF2\u9009\u62E9 ",
2096
- selectedCount,
2097
- " \u4E2A"
2098
- ] })
2099
- ] }) });
2100
- }
2101
-
2102
- // src/components/ContextMenu.tsx
2103
- import { createPortal } from "react-dom";
2104
- import { useMemo as useMemo3, useEffect, useRef as useRef3, useCallback as useCallback2, useState as useState2 } from "react";
2105
- import { Icon as Icon7 } from "@iconify/react";
2106
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2107
- var MARGIN = 8;
2108
- var MENU_WIDTH = 220;
2109
- var MENU_ITEM_HEIGHT = 32;
2110
- var SEPARATOR_HEIGHT = 9;
2111
- var MENU_PADDING = 8;
2112
- var SUBMENU_GAP = 0;
2113
- function estimateMenuHeight(items) {
2114
- let height = MENU_PADDING;
2115
- for (const item of items) {
2116
- height += item.separator ? SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT;
2117
- }
2118
- return height;
2119
- }
2120
- function calculateMenuPosition(clickX, clickY, menuHeight) {
2121
- const viewportWidth = window.innerWidth;
2122
- const viewportHeight = window.innerHeight;
2123
- let adjustedX = clickX;
2124
- let adjustedY = clickY;
2125
- const spaceRight = viewportWidth - clickX;
2126
- const spaceLeft = clickX;
2127
- if (spaceRight < MENU_WIDTH + MARGIN) {
2128
- if (spaceLeft >= MENU_WIDTH + MARGIN) {
2129
- adjustedX = clickX - MENU_WIDTH;
2130
- } else {
2131
- if (spaceRight > spaceLeft) {
2132
- adjustedX = viewportWidth - MENU_WIDTH - MARGIN;
2133
- } else {
2134
- adjustedX = MARGIN;
2135
- }
2136
- }
2137
- }
2138
- const spaceBottom = viewportHeight - clickY;
2139
- const spaceTop = clickY;
2140
- if (spaceBottom < menuHeight + MARGIN) {
2141
- if (spaceTop >= menuHeight + MARGIN) {
2142
- adjustedY = clickY - menuHeight;
2143
- } else {
2144
- if (spaceBottom > spaceTop) {
2145
- adjustedY = viewportHeight - menuHeight - MARGIN;
2146
- } else {
2147
- adjustedY = MARGIN;
2148
- }
2149
- }
2150
- }
2151
- adjustedX = Math.max(MARGIN, Math.min(adjustedX, viewportWidth - MENU_WIDTH - MARGIN));
2152
- adjustedY = Math.max(MARGIN, Math.min(adjustedY, viewportHeight - menuHeight - MARGIN));
2153
- return { x: adjustedX, y: adjustedY };
2154
- }
2155
- function calculateSubmenuPosition(parentRect, submenuHeight) {
2156
- const viewportWidth = window.innerWidth;
2157
- const viewportHeight = window.innerHeight;
2158
- const spaceRight = viewportWidth - parentRect.right;
2159
- const spaceLeft = parentRect.left;
2160
- let submenuX;
2161
- let submenuY;
2162
- if (spaceRight >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {
2163
- submenuX = parentRect.right + SUBMENU_GAP;
2164
- } else if (spaceLeft >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {
2165
- submenuX = parentRect.left - MENU_WIDTH - SUBMENU_GAP;
2166
- } else {
2167
- if (spaceRight > spaceLeft) {
2168
- submenuX = viewportWidth - MENU_WIDTH - MARGIN;
2169
- } else {
2170
- submenuX = MARGIN;
2171
- }
2172
- }
2173
- submenuY = parentRect.top;
2174
- if (submenuY + submenuHeight > viewportHeight - MARGIN) {
2175
- submenuY = viewportHeight - submenuHeight - MARGIN;
2176
- }
2177
- if (submenuY < MARGIN) {
2178
- submenuY = MARGIN;
2179
- }
2180
- return { x: submenuX, y: submenuY };
2181
- }
2182
- function ContextMenu({
2183
- visible,
2184
- x,
2185
- y,
2186
- options,
2187
- onClose,
2188
- onSelect
2189
- }) {
2190
- const menuRef = useRef3(null);
2191
- const [hoveredItemId, setHoveredItemId] = useState2(null);
2192
- const [submenuPosition, setSubmenuPosition] = useState2(null);
2193
- const itemRefs = useRef3(/* @__PURE__ */ new Map());
2194
- const position = useMemo3(() => {
2195
- const estimatedHeight = estimateMenuHeight(options);
2196
- return calculateMenuPosition(x, y, estimatedHeight);
2197
- }, [x, y, options]);
2198
- const menuStyle = useMemo3(
2199
- () => ({
2200
- left: `${position.x}px`,
2201
- top: `${position.y}px`
2202
- }),
2203
- [position]
2204
- );
2205
- const hoveredItem = useMemo3(() => {
2206
- if (!hoveredItemId) return null;
2207
- return options.find((opt) => opt.id === hoveredItemId && opt.children && opt.children.length > 0);
2208
- }, [hoveredItemId, options]);
2209
- useEffect(() => {
2210
- if (!hoveredItemId || !hoveredItem) {
2211
- setSubmenuPosition(null);
2212
- return;
2213
- }
2214
- const itemEl = itemRefs.current.get(hoveredItemId);
2215
- if (!itemEl) {
2216
- setSubmenuPosition(null);
2217
- return;
2218
- }
2219
- const rect = itemEl.getBoundingClientRect();
2220
- const submenuHeight = estimateMenuHeight(hoveredItem.children || []);
2221
- const pos = calculateSubmenuPosition(rect, submenuHeight);
2222
- setSubmenuPosition(pos);
2223
- }, [hoveredItemId, hoveredItem]);
2224
- useEffect(() => {
2225
- if (!visible) return;
2226
- const handleClickOutside = (e) => {
2227
- const target = e.target;
2228
- const menuContainer = document.querySelector(".context-menu-container");
2229
- if (menuContainer && menuContainer.contains(target)) {
2230
- return;
2231
- }
2232
- onClose?.();
2233
- };
2234
- const handleEscape = (e) => {
2235
- if (e.key === "Escape") {
2236
- onClose?.();
2237
- }
2238
- };
2239
- document.addEventListener("mousedown", handleClickOutside);
2240
- document.addEventListener("keydown", handleEscape);
2241
- return () => {
2242
- document.removeEventListener("mousedown", handleClickOutside);
2243
- document.removeEventListener("keydown", handleEscape);
2244
- };
2245
- }, [visible, onClose]);
2246
- useEffect(() => {
2247
- if (!visible) {
2248
- setHoveredItemId(null);
2249
- setSubmenuPosition(null);
2250
- }
2251
- }, [visible]);
2252
- const renderIcon = (iconName) => {
2253
- if (!iconName) return null;
2254
- return /* @__PURE__ */ jsx10(Icon7, { icon: iconName, width: 16, height: 16, className: "context-menu-item-icon" });
2255
- };
2256
- const handleOptionClick = useCallback2(
2257
- (option) => {
2258
- if (option.disabled) return;
2259
- if (option.children && option.children.length > 0) {
2260
- return;
2261
- }
2262
- if (option.action) {
2263
- option.action();
2264
- }
2265
- onSelect?.(option);
2266
- onClose?.();
2267
- },
2268
- [onClose, onSelect]
2269
- );
2270
- const handleItemMouseEnter = useCallback2((option) => {
2271
- if (option.children && option.children.length > 0) {
2272
- setHoveredItemId(option.id);
2273
- } else {
2274
- setHoveredItemId(null);
2275
- }
2276
- }, []);
2277
- if (!visible) return null;
2278
- return createPortal(
2279
- /* @__PURE__ */ jsxs8("div", { className: "context-menu-container", children: [
2280
- /* @__PURE__ */ jsx10("div", { ref: menuRef, className: "context-menu", style: menuStyle, children: options.map((option, index) => {
2281
- if (option.separator) {
2282
- return /* @__PURE__ */ jsx10("div", { className: "context-menu-separator" }, index);
2283
- }
2284
- const hasChildren = option.children && option.children.length > 0;
2285
- const isHovered = hoveredItemId === option.id;
2286
- return /* @__PURE__ */ jsxs8(
2287
- "div",
2288
- {
2289
- ref: (el) => {
2290
- if (el) {
2291
- itemRefs.current.set(option.id, el);
2292
- } else {
2293
- itemRefs.current.delete(option.id);
2294
- }
2295
- },
2296
- 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" : ""}`,
2297
- onClick: () => handleOptionClick(option),
2298
- onMouseEnter: () => handleItemMouseEnter(option),
2299
- children: [
2300
- option.icon && renderIcon(option.icon),
2301
- /* @__PURE__ */ jsx10("span", { className: "context-menu-item-label", children: option.label }),
2302
- option.checked && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:check", width: 14, height: 14, className: "context-menu-item-check" }),
2303
- option.shortcut && !hasChildren && /* @__PURE__ */ jsx10("span", { className: "context-menu-item-shortcut", children: option.shortcut }),
2304
- hasChildren && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:chevron-right", width: 14, height: 14, className: "context-menu-item-arrow" })
2305
- ]
2306
- },
2307
- option.id || index
2308
- );
2309
- }) }),
2310
- hoveredItem && submenuPosition && /* @__PURE__ */ jsx10(
2311
- "div",
2312
- {
2313
- className: "context-menu context-menu-submenu",
2314
- style: {
2315
- left: `${submenuPosition.x}px`,
2316
- top: `${submenuPosition.y}px`
2317
- },
2318
- onMouseEnter: () => setHoveredItemId(hoveredItem.id),
2319
- onMouseLeave: () => setHoveredItemId(null),
2320
- children: hoveredItem.children.map((child, childIndex) => {
2321
- if (child.separator) {
2322
- return /* @__PURE__ */ jsx10("div", { className: "context-menu-separator" }, `child-sep-${childIndex}`);
2323
- }
2324
- return /* @__PURE__ */ jsxs8(
2325
- "div",
2326
- {
2327
- className: `context-menu-item ${child.disabled ? "context-menu-item--disabled" : ""} ${child.danger ? "context-menu-item--danger" : ""}`,
2328
- onClick: () => handleOptionClick(child),
2329
- children: [
2330
- child.icon && renderIcon(child.icon),
2331
- /* @__PURE__ */ jsx10("span", { className: "context-menu-item-label", children: child.label }),
2332
- child.checked && /* @__PURE__ */ jsx10(Icon7, { icon: "lucide:check", width: 14, height: 14, className: "context-menu-item-check" }),
2333
- child.shortcut && /* @__PURE__ */ jsx10("span", { className: "context-menu-item-shortcut", children: child.shortcut })
2334
- ]
2335
- },
2336
- child.id || childIndex
2337
- );
2338
- })
2339
- }
2340
- )
2341
- ] }),
2342
- document.body
2343
- );
2344
- }
2345
-
2346
- // src/components/Window.tsx
2347
- import { createPortal as createPortal2 } from "react-dom";
2348
- import { useMemo as useMemo4, useRef as useRef4, useEffect as useEffect4 } from "react";
2349
- import { Icon as Icon8 } from "@iconify/react";
2350
-
2351
- // src/hooks/useWindowDrag.ts
2352
- import { useState as useState3, useCallback as useCallback3, useEffect as useEffect2 } from "react";
2353
- function useWindowDrag() {
2354
- const [position, setPosition] = useState3({ x: 0, y: 0 });
2355
- const [isDragging, setIsDragging] = useState3(false);
2356
- const handleMouseMove = useCallback3((e) => {
2357
- if (!isDragging) return;
2358
- setPosition((prev) => ({
2359
- x: prev.x + e.movementX,
2360
- y: prev.y + e.movementY
2361
- }));
2362
- }, [isDragging]);
2363
- const handleMouseUp = useCallback3(() => {
2364
- setIsDragging(false);
2365
- }, []);
2366
- const startDrag = useCallback3((e) => {
2367
- const target = e.target;
2368
- if (target.closest(".draggable-area") && !target.closest("button")) {
2369
- e.preventDefault();
2370
- setIsDragging(true);
2371
- }
2372
- }, []);
2373
- useEffect2(() => {
2374
- if (isDragging) {
2375
- window.addEventListener("mousemove", handleMouseMove);
2376
- window.addEventListener("mouseup", handleMouseUp);
2377
- return () => {
2378
- window.removeEventListener("mousemove", handleMouseMove);
2379
- window.removeEventListener("mouseup", handleMouseUp);
2380
- };
2381
- }
2382
- }, [isDragging, handleMouseMove, handleMouseUp]);
2383
- return {
2384
- position,
2385
- isDragging,
2386
- startDrag
2387
- };
2388
- }
2389
-
2390
- // src/hooks/useWindowResize.ts
2391
- import { useState as useState4, useCallback as useCallback4, useEffect as useEffect3 } from "react";
2392
- function useWindowResize(initialWidth, initialHeight, minWidth, minHeight, maxWidth, maxHeight) {
2393
- const [width, setWidth] = useState4(initialWidth);
2394
- const [height, setHeight] = useState4(initialHeight);
2395
- const [isResizing, setIsResizing] = useState4(false);
2396
- const [resizeDirection, setResizeDirection] = useState4(null);
2397
- const [startX, setStartX] = useState4(0);
2398
- const [startY, setStartY] = useState4(0);
2399
- const [startWidth, setStartWidth] = useState4(0);
2400
- const [startHeight, setStartHeight] = useState4(0);
2401
- const handleMouseMove = useCallback4((e) => {
2402
- if (!isResizing || !resizeDirection) return;
2403
- const deltaX = e.clientX - startX;
2404
- const deltaY = e.clientY - startY;
2405
- let newWidth = startWidth;
2406
- let newHeight = startHeight;
2407
- const direction = resizeDirection;
2408
- if (direction.includes("e")) {
2409
- newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);
2410
- } else if (direction.includes("w")) {
2411
- newWidth = Math.min(Math.max(startWidth - deltaX, minWidth), maxWidth);
2412
- }
2413
- if (direction.includes("s")) {
2414
- newHeight = Math.min(Math.max(startHeight + deltaY, minHeight), maxHeight);
2415
- } else if (direction.includes("n")) {
2416
- newHeight = Math.min(Math.max(startHeight - deltaY, minHeight), maxHeight);
2417
- }
2418
- setWidth(newWidth);
2419
- setHeight(newHeight);
2420
- }, [isResizing, resizeDirection, startX, startY, startWidth, startHeight, minWidth, minHeight, maxWidth, maxHeight]);
2421
- const handleMouseUp = useCallback4(() => {
2422
- setIsResizing(false);
2423
- setResizeDirection(null);
2424
- }, []);
2425
- const startResize = useCallback4((e, direction, currentWidth, currentHeight) => {
2426
- e.preventDefault();
2427
- e.stopPropagation();
2428
- setIsResizing(true);
2429
- setResizeDirection(direction);
2430
- setStartX(e.clientX);
2431
- setStartY(e.clientY);
2432
- setStartWidth(currentWidth);
2433
- setStartHeight(currentHeight);
2434
- }, []);
2435
- const getCursorForDirection = useCallback4((direction) => {
2436
- const cursors = {
2437
- n: "n-resize",
2438
- s: "s-resize",
2439
- e: "e-resize",
2440
- w: "w-resize",
2441
- ne: "ne-resize",
2442
- nw: "nw-resize",
2443
- se: "se-resize",
2444
- sw: "sw-resize"
2445
- };
2446
- return cursors[direction];
2447
- }, []);
2448
- useEffect3(() => {
2449
- if (isResizing) {
2450
- window.addEventListener("mousemove", handleMouseMove);
2451
- window.addEventListener("mouseup", handleMouseUp);
2452
- document.body.style.cursor = getCursorForDirection(resizeDirection || "se");
2453
- document.body.style.userSelect = "none";
2454
- return () => {
2455
- window.removeEventListener("mousemove", handleMouseMove);
2456
- window.removeEventListener("mouseup", handleMouseUp);
2457
- document.body.style.cursor = "";
2458
- document.body.style.userSelect = "";
2459
- };
2460
- }
2461
- }, [isResizing, resizeDirection, handleMouseMove, handleMouseUp, getCursorForDirection]);
2462
- return {
2463
- width,
2464
- height,
2465
- isResizing,
2466
- startResize
2467
- };
2468
- }
2469
-
2470
- // src/components/Window.tsx
2471
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2472
- function Window({
2473
- title,
2474
- showTitleBar = true,
2475
- showMinimize = false,
2476
- showMaximize = false,
2477
- draggable = true,
2478
- resizable = true,
2479
- closeOnBackdrop = true,
2480
- width = "auto",
2481
- height = "auto",
2482
- minWidth = 300,
2483
- minHeight = 200,
2484
- maxWidth = "80vw",
2485
- maxHeight = "80vh",
2486
- fitContent = false,
2487
- onClose,
2488
- onMinimize,
2489
- onMaximize,
2490
- children,
2491
- titleSlot,
2492
- actionsSlot
2493
- }) {
2494
- const windowContainerRef = useRef4(null);
2495
- const windowDrag = draggable ? useWindowDrag() : null;
2496
- const isAutoSize = useMemo4(() => {
2497
- return fitContent || width === "auto" || width === "fit-content" || height === "auto" || height === "fit-content";
2498
- }, [fitContent, width, height]);
2499
- const getInitialSize = () => {
2500
- if (isAutoSize) {
2501
- return { initialWidth: 0, initialHeight: 0 };
2502
- }
2503
- const defaultWidth = 600;
2504
- const defaultHeight = 500;
2505
- let initialWidth2 = defaultWidth;
2506
- let initialHeight2 = defaultHeight;
2507
- if (width !== "auto" && width !== "fit-content") {
2508
- initialWidth2 = typeof width === "number" ? width : parseInt(width);
2509
- }
2510
- if (height !== "auto" && height !== "fit-content") {
2511
- initialHeight2 = typeof height === "number" ? height : parseInt(height);
2512
- }
2513
- return { initialWidth: initialWidth2, initialHeight: initialHeight2 };
2514
- };
2515
- const parseSize = (size, defaultPx) => {
2516
- if (typeof size === "number") return size;
2517
- if (typeof size === "string") {
2518
- if (size.endsWith("px")) return parseInt(size);
2519
- if (size.endsWith("vw"))
2520
- return parseInt(size) / 100 * window.innerWidth;
2521
- if (size.endsWith("vh"))
2522
- return parseInt(size) / 100 * window.innerHeight;
2523
- }
2524
- return defaultPx;
2525
- };
2526
- const { initialWidth, initialHeight } = getInitialSize();
2527
- const minW = parseSize(minWidth, 500);
2528
- const minH = parseSize(minHeight, 350);
2529
- const maxW = parseSize(maxWidth, window.innerWidth * 0.8);
2530
- const maxH = parseSize(maxHeight, window.innerHeight * 0.8);
2531
- const windowResize = resizable ? useWindowResize(initialWidth, initialHeight, minW, minH, maxW, maxH) : null;
2532
- const windowStyle = useMemo4(() => {
2533
- const baseStyle = {
2534
- left: "50%",
2535
- top: "50%"
2536
- };
2537
- let translateX = "-50%";
2538
- let translateY = "-50%";
2539
- if (draggable && windowDrag) {
2540
- translateX = `calc(-50% + ${windowDrag.position.x}px)`;
2541
- translateY = `calc(-50% + ${windowDrag.position.y}px)`;
2542
- }
2543
- baseStyle.transform = `translate(${translateX}, ${translateY})`;
2544
- baseStyle.transformOrigin = "center center";
2545
- if (isAutoSize) {
2546
- if (resizable && windowResize && windowResize.width > 0) {
2547
- baseStyle.width = `${windowResize.width}px`;
2548
- baseStyle.height = `${windowResize.height}px`;
2549
- }
2550
- } else {
2551
- if (resizable && windowResize) {
2552
- baseStyle.width = `${windowResize.width}px`;
2553
- baseStyle.height = `${windowResize.height}px`;
2554
- } else {
2555
- if (width !== "auto" && width !== "fit-content") {
2556
- baseStyle.width = typeof width === "number" ? `${width}px` : width;
2557
- }
2558
- if (height !== "auto" && height !== "fit-content") {
2559
- baseStyle.height = typeof height === "number" ? `${height}px` : height;
2560
- }
2561
- }
2562
- }
2563
- if (minWidth) {
2564
- baseStyle.minWidth = typeof minWidth === "number" ? `${minWidth}px` : minWidth;
2565
- }
2566
- if (minHeight) {
2567
- baseStyle.minHeight = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
2568
- }
2569
- if (maxWidth) {
2570
- baseStyle.maxWidth = typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth;
2571
- }
2572
- if (maxHeight) {
2573
- baseStyle.maxHeight = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
2574
- }
2575
- return baseStyle;
2576
- }, [
2577
- draggable,
2578
- windowDrag,
2579
- isAutoSize,
2580
- resizable,
2581
- windowResize,
2582
- width,
2583
- height,
2584
- minWidth,
2585
- minHeight,
2586
- maxWidth,
2587
- maxHeight
2588
- ]);
2589
- const handleBackdropClick = (e) => {
2590
- if (closeOnBackdrop && e.target === e.currentTarget) {
2591
- onClose?.();
2592
- }
2593
- };
2594
- const handleDragStart = (e) => {
2595
- if (draggable && windowDrag) {
2596
- windowDrag.startDrag(e);
2597
- }
2598
- };
2599
- const handleResizeStart = (e, direction) => {
2600
- if (!resizable || !windowResize || !windowContainerRef.current) return;
2601
- const rect = windowContainerRef.current.getBoundingClientRect();
2602
- const currentWidth = rect.width;
2603
- const currentHeight = rect.height;
2604
- windowResize.startResize(e, direction, currentWidth, currentHeight);
2605
- };
2606
- useEffect4(() => {
2607
- const handleEsc = (e) => {
2608
- if (e.key === "Escape") {
2609
- e.preventDefault();
2610
- onClose?.();
2611
- }
2612
- };
2613
- window.addEventListener("keydown", handleEsc);
2614
- return () => {
2615
- window.removeEventListener("keydown", handleEsc);
2616
- };
2617
- }, [onClose]);
2618
- return createPortal2(
2619
- /* @__PURE__ */ jsx11("div", { className: "window-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs9(
2620
- "div",
2621
- {
2622
- ref: windowContainerRef,
2623
- className: "window-container",
2624
- style: windowStyle,
2625
- onClick: (e) => e.stopPropagation(),
2626
- children: [
2627
- showTitleBar && /* @__PURE__ */ jsxs9(
2628
- "div",
2629
- {
2630
- className: "window-title-bar draggable-area",
2631
- onMouseDown: handleDragStart,
2632
- children: [
2633
- /* @__PURE__ */ jsxs9("div", { className: "window-controls", children: [
2634
- /* @__PURE__ */ jsx11(
2635
- "button",
2636
- {
2637
- onClick: (e) => {
2638
- e.stopPropagation();
2639
- onClose?.();
2640
- },
2641
- className: "window-control-button window-control-button--close",
2642
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:x", width: 7, height: 7, className: "window-control-icon" })
2643
- }
2644
- ),
2645
- showMinimize && /* @__PURE__ */ jsx11(
2646
- "button",
2647
- {
2648
- onClick: (e) => {
2649
- e.stopPropagation();
2650
- onMinimize?.();
2651
- },
2652
- className: "window-control-button window-control-button--minimize",
2653
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:minus", width: 7, height: 7, className: "window-control-icon" })
2654
- }
2655
- ),
2656
- showMaximize && /* @__PURE__ */ jsx11(
2657
- "button",
2658
- {
2659
- onClick: (e) => {
2660
- e.stopPropagation();
2661
- onMaximize?.();
2662
- },
2663
- className: "window-control-button window-control-button--maximize",
2664
- children: /* @__PURE__ */ jsx11(Icon8, { icon: "lucide:maximize-2", width: 7, height: 7, className: "window-control-icon" })
2665
- }
2666
- )
2667
- ] }),
2668
- /* @__PURE__ */ jsx11("div", { className: "window-title-info", children: titleSlot || /* @__PURE__ */ jsx11("span", { className: "window-title-text", children: title }) }),
2669
- /* @__PURE__ */ jsx11("div", { className: "window-title-actions", children: actionsSlot })
2670
- ]
2671
- }
2672
- ),
2673
- /* @__PURE__ */ jsx11("div", { className: "window-content", children }),
2674
- resizable && /* @__PURE__ */ jsxs9(Fragment3, { children: [
2675
- /* @__PURE__ */ jsx11(
2676
- "div",
2677
- {
2678
- className: "window-resize-handle window-resize-handle--n",
2679
- onMouseDown: (e) => handleResizeStart(e, "n")
2680
- }
2681
- ),
2682
- /* @__PURE__ */ jsx11(
2683
- "div",
2684
- {
2685
- className: "window-resize-handle window-resize-handle--s",
2686
- onMouseDown: (e) => handleResizeStart(e, "s")
2687
- }
2688
- ),
2689
- /* @__PURE__ */ jsx11(
2690
- "div",
2691
- {
2692
- className: "window-resize-handle window-resize-handle--e",
2693
- onMouseDown: (e) => handleResizeStart(e, "e")
2694
- }
2695
- ),
2696
- /* @__PURE__ */ jsx11(
2697
- "div",
2698
- {
2699
- className: "window-resize-handle window-resize-handle--w",
2700
- onMouseDown: (e) => handleResizeStart(e, "w")
2701
- }
2702
- ),
2703
- /* @__PURE__ */ jsx11(
2704
- "div",
2705
- {
2706
- className: "window-resize-handle window-resize-handle--ne",
2707
- onMouseDown: (e) => handleResizeStart(e, "ne")
2708
- }
2709
- ),
2710
- /* @__PURE__ */ jsx11(
2711
- "div",
2712
- {
2713
- className: "window-resize-handle window-resize-handle--nw",
2714
- onMouseDown: (e) => handleResizeStart(e, "nw")
2715
- }
2716
- ),
2717
- /* @__PURE__ */ jsx11(
2718
- "div",
2719
- {
2720
- className: "window-resize-handle window-resize-handle--se",
2721
- onMouseDown: (e) => handleResizeStart(e, "se")
2722
- }
2723
- ),
2724
- /* @__PURE__ */ jsx11(
2725
- "div",
2726
- {
2727
- className: "window-resize-handle window-resize-handle--sw",
2728
- onMouseDown: (e) => handleResizeStart(e, "sw")
2729
- }
2730
- )
2731
- ] })
2732
- ]
2733
- }
2734
- ) }),
2735
- document.body
2736
- );
2737
- }
2738
-
2739
- // src/components/CompressDialog.tsx
2740
- import { useState as useState6, useMemo as useMemo5, useEffect as useEffect5 } from "react";
2741
- import { createPortal as createPortal3 } from "react-dom";
2742
- import { Icon as Icon9 } from "@iconify/react";
2743
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2744
- var FORMAT_OPTIONS = [
2745
- { value: "zip", label: "ZIP", ext: ".zip" },
2746
- { value: "tgz", label: "TAR.GZ (gzip)", ext: ".tar.gz" },
2747
- { value: "tarbz2", label: "TAR.BZ2 (bzip2)", ext: ".tar.bz2" },
2748
- { value: "tar", label: "TAR (\u65E0\u538B\u7F29)", ext: ".tar" }
2749
- ];
2750
- var LEVEL_OPTIONS = [
2751
- { value: "fast", label: "\u5FEB\u901F", desc: "\u538B\u7F29\u901F\u5EA6\u5FEB\uFF0C\u6587\u4EF6\u8F83\u5927" },
2752
- { value: "normal", label: "\u6807\u51C6", desc: "\u5E73\u8861\u901F\u5EA6\u548C\u5927\u5C0F" },
2753
- { value: "best", label: "\u6700\u4F73", desc: "\u6587\u4EF6\u6700\u5C0F\uFF0C\u901F\u5EA6\u8F83\u6162" }
2754
- ];
2755
- function CompressDialog({
2756
- visible,
2757
- filePaths,
2758
- outputDir,
2759
- onConfirm,
2760
- onCancel
2761
- }) {
2762
- const [format, setFormat] = useState6("zip");
2763
- const [level, setLevel] = useState6("normal");
2764
- const [outputName, setOutputName] = useState6("");
2765
- const [deleteSource, setDeleteSource] = useState6(false);
2766
- const [password, setPassword] = useState6("");
2767
- const [showPassword, setShowPassword] = useState6(false);
2768
- const defaultOutputName = useMemo5(() => {
2769
- if (filePaths.length === 0) return "archive";
2770
- if (filePaths.length === 1) {
2771
- const name = filePaths[0].split("/").pop() || "archive";
2772
- return name.replace(/\.[^.]+$/, "");
2773
- }
2774
- return "\u538B\u7F29\u6587\u4EF6";
2775
- }, [filePaths]);
2776
- useEffect5(() => {
2777
- if (visible) {
2778
- setOutputName(defaultOutputName);
2779
- setFormat("zip");
2780
- setLevel("normal");
2781
- setDeleteSource(false);
2782
- setPassword("");
2783
- }
2784
- }, [visible, defaultOutputName]);
2785
- const currentExt = FORMAT_OPTIONS.find((f) => f.value === format)?.ext || ".zip";
2786
- const fullOutputPath = `${outputDir}/${outputName}${currentExt}`;
2787
- const handleConfirm = () => {
2788
- onConfirm({
2789
- format,
2790
- level,
2791
- outputName: outputName + currentExt,
2792
- deleteSource
2793
- });
2794
- };
2795
- const supportsPassword = false;
2796
- if (!visible) return null;
2797
- return createPortal3(
2798
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-overlay", onClick: onCancel, children: /* @__PURE__ */ jsxs10("div", { className: "compress-dialog", onClick: (e) => e.stopPropagation(), children: [
2799
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-header", children: [
2800
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-title", children: [
2801
- /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:archive", width: 20, height: 20 }),
2802
- /* @__PURE__ */ jsx12("span", { children: "\u538B\u7F29\u6587\u4EF6" })
2803
- ] }),
2804
- /* @__PURE__ */ jsx12("button", { className: "compress-dialog-close", onClick: onCancel, children: /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:x", width: 18, height: 18 }) })
2805
- ] }),
2806
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-content", children: [
2807
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-info", children: [
2808
- /* @__PURE__ */ jsx12(Icon9, { icon: "lucide:file-archive", width: 16, height: 16 }),
2809
- /* @__PURE__ */ jsx12("span", { children: filePaths.length === 1 ? filePaths[0].split("/").pop() : `${filePaths.length} \u4E2A\u9879\u76EE` })
2810
- ] }),
2811
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2812
- /* @__PURE__ */ jsx12("label", { children: "\u6587\u4EF6\u540D" }),
2813
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-input-group", children: [
2814
- /* @__PURE__ */ jsx12(
2815
- "input",
2816
- {
2817
- type: "text",
2818
- value: outputName,
2819
- onChange: (e) => setOutputName(e.target.value),
2820
- placeholder: "\u8F93\u5165\u6587\u4EF6\u540D"
2821
- }
2822
- ),
2823
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-ext", children: currentExt })
2824
- ] })
2825
- ] }),
2826
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2827
- /* @__PURE__ */ jsx12("label", { children: "\u538B\u7F29\u683C\u5F0F" }),
2828
- /* @__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)) })
2829
- ] }),
2830
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2831
- /* @__PURE__ */ jsx12("label", { children: "\u538B\u7F29\u7EA7\u522B" }),
2832
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-levels", children: LEVEL_OPTIONS.map((opt) => /* @__PURE__ */ jsxs10("label", { className: "compress-dialog-level", children: [
2833
- /* @__PURE__ */ jsx12(
2834
- "input",
2835
- {
2836
- type: "radio",
2837
- name: "level",
2838
- value: opt.value,
2839
- checked: level === opt.value,
2840
- onChange: () => setLevel(opt.value)
2841
- }
2842
- ),
2843
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-level-label", children: opt.label }),
2844
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-level-desc", children: opt.desc })
2845
- ] }, opt.value)) })
2846
- ] }),
2847
- supportsPassword && /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-field", children: [
2848
- /* @__PURE__ */ jsx12("label", { children: "\u5BC6\u7801\u4FDD\u62A4\uFF08\u53EF\u9009\uFF09" }),
2849
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-input-group", children: [
2850
- /* @__PURE__ */ jsx12(
2851
- "input",
2852
- {
2853
- type: showPassword ? "text" : "password",
2854
- value: password,
2855
- onChange: (e) => setPassword(e.target.value),
2856
- placeholder: "\u8BBE\u7F6E\u5BC6\u7801"
2857
- }
2858
- ),
2859
- /* @__PURE__ */ jsx12(
2860
- "button",
2861
- {
2862
- type: "button",
2863
- className: "compress-dialog-toggle-password",
2864
- onClick: () => setShowPassword(!showPassword),
2865
- children: showPassword ? "\u9690\u85CF" : "\u663E\u793A"
2866
- }
2867
- )
2868
- ] })
2869
- ] }),
2870
- /* @__PURE__ */ jsx12("div", { className: "compress-dialog-field compress-dialog-checkbox", children: /* @__PURE__ */ jsxs10("label", { children: [
2871
- /* @__PURE__ */ jsx12(
2872
- "input",
2873
- {
2874
- type: "checkbox",
2875
- checked: deleteSource,
2876
- onChange: (e) => setDeleteSource(e.target.checked)
2877
- }
2878
- ),
2879
- /* @__PURE__ */ jsx12("span", { children: "\u538B\u7F29\u540E\u5220\u9664\u6E90\u6587\u4EF6" })
2880
- ] }) }),
2881
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-preview", children: [
2882
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-preview-label", children: "\u8F93\u51FA\u4F4D\u7F6E:" }),
2883
- /* @__PURE__ */ jsx12("span", { className: "compress-dialog-preview-path", children: fullOutputPath })
2884
- ] })
2885
- ] }),
2886
- /* @__PURE__ */ jsxs10("div", { className: "compress-dialog-footer", children: [
2887
- /* @__PURE__ */ jsx12("button", { className: "compress-dialog-btn compress-dialog-btn-cancel", onClick: onCancel, children: "\u53D6\u6D88" }),
2888
- /* @__PURE__ */ jsx12(
2889
- "button",
2890
- {
2891
- className: "compress-dialog-btn compress-dialog-btn-confirm",
2892
- onClick: handleConfirm,
2893
- disabled: !outputName.trim(),
2894
- children: "\u538B\u7F29"
2895
- }
2896
- )
2897
- ] })
2898
- ] }) }),
2899
- document.body
2900
- );
2901
- }
2902
-
2903
- // src/components/ProgressDialog.tsx
2904
- import { createPortal as createPortal4 } from "react-dom";
2905
- import { Icon as Icon10 } from "@iconify/react";
2906
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2907
- function ProgressDialog({
2908
- visible,
2909
- progress,
2910
- onCancel,
2911
- onClose,
2912
- onOpenFolder
2913
- }) {
2914
- const { type, status, percent, currentFile, processedCount, totalCount, error, outputPath } = progress;
2915
- const title = type === "compress" ? "\u538B\u7F29\u6587\u4EF6" : "\u89E3\u538B\u6587\u4EF6";
2916
- const isCompleted = status === "success" || status === "error";
2917
- const StatusIcon = () => {
2918
- switch (status) {
2919
- case "processing":
2920
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:loader-2", width: 24, height: 24, className: "progress-dialog-icon-spin" });
2921
- case "success":
2922
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:check-circle", width: 24, height: 24, className: "progress-dialog-icon-success" });
2923
- case "error":
2924
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:x-circle", width: 24, height: 24, className: "progress-dialog-icon-error" });
2925
- default:
2926
- return /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:archive", width: 24, height: 24 });
2927
- }
2928
- };
2929
- const getStatusText = () => {
2930
- switch (status) {
2931
- case "pending":
2932
- return "\u51C6\u5907\u4E2D...";
2933
- case "processing":
2934
- return type === "compress" ? "\u6B63\u5728\u538B\u7F29..." : "\u6B63\u5728\u89E3\u538B...";
2935
- case "success":
2936
- return type === "compress" ? "\u538B\u7F29\u5B8C\u6210" : "\u89E3\u538B\u5B8C\u6210";
2937
- case "error":
2938
- return "\u64CD\u4F5C\u5931\u8D25";
2939
- default:
2940
- return "";
2941
- }
2942
- };
2943
- const handleClose = () => {
2944
- if (isCompleted) {
2945
- onClose?.();
2946
- } else {
2947
- onCancel?.();
2948
- }
2949
- };
2950
- if (!visible) return null;
2951
- return createPortal4(
2952
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-overlay", children: /* @__PURE__ */ jsxs11("div", { className: "progress-dialog", children: [
2953
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-header", children: [
2954
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-title", children: [
2955
- /* @__PURE__ */ jsx13(StatusIcon, {}),
2956
- /* @__PURE__ */ jsx13("span", { children: title })
2957
- ] }),
2958
- isCompleted && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-close", onClick: handleClose, children: /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:x", width: 18, height: 18 }) })
2959
- ] }),
2960
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-content", children: [
2961
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-status", children: getStatusText() }),
2962
- status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-bar-container", children: [
2963
- /* @__PURE__ */ jsx13("div", { className: "progress-dialog-bar", children: /* @__PURE__ */ jsx13(
2964
- "div",
2965
- {
2966
- className: "progress-dialog-bar-fill",
2967
- style: { width: `${percent}%` }
2968
- }
2969
- ) }),
2970
- /* @__PURE__ */ jsxs11("span", { className: "progress-dialog-percent", children: [
2971
- percent,
2972
- "%"
2973
- ] })
2974
- ] }),
2975
- currentFile && status === "processing" && /* @__PURE__ */ jsx13("div", { className: "progress-dialog-current-file", children: currentFile }),
2976
- totalCount && totalCount > 0 && status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-count", children: [
2977
- processedCount || 0,
2978
- " / ",
2979
- totalCount,
2980
- " \u4E2A\u6587\u4EF6"
2981
- ] }),
2982
- error && /* @__PURE__ */ jsx13("div", { className: "progress-dialog-error", children: error }),
2983
- status === "success" && outputPath && /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-output", children: [
2984
- /* @__PURE__ */ jsx13("span", { className: "progress-dialog-output-label", children: "\u8F93\u51FA\u4F4D\u7F6E:" }),
2985
- /* @__PURE__ */ jsx13("span", { className: "progress-dialog-output-path", children: outputPath })
2986
- ] })
2987
- ] }),
2988
- /* @__PURE__ */ jsxs11("div", { className: "progress-dialog-footer", children: [
2989
- status === "processing" && onCancel && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-btn progress-dialog-btn-cancel", onClick: onCancel, children: "\u53D6\u6D88" }),
2990
- status === "success" && outputPath && onOpenFolder && /* @__PURE__ */ jsxs11(
2991
- "button",
2992
- {
2993
- className: "progress-dialog-btn progress-dialog-btn-folder",
2994
- onClick: () => onOpenFolder(outputPath),
2995
- children: [
2996
- /* @__PURE__ */ jsx13(Icon10, { icon: "lucide:folder-open", width: 16, height: 16 }),
2997
- "\u6253\u5F00\u6587\u4EF6\u5939"
2998
- ]
2999
- }
3000
- ),
3001
- isCompleted && /* @__PURE__ */ jsx13("button", { className: "progress-dialog-btn progress-dialog-btn-close", onClick: handleClose, children: "\u5173\u95ED" })
3002
- ] })
3003
- ] }) }),
3004
- document.body
3005
- );
3006
- }
3007
-
3008
- // src/components/FileInfoDialog.tsx
3009
- import React from "react";
3010
- import { Icon as Icon11 } from "@iconify/react";
3011
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3012
- function getFileIcon(type, name) {
3013
- if (type === FileType.FOLDER) {
3014
- return /* @__PURE__ */ jsx14(Icon11, { icon: "ic:round-folder", width: 48, height: 48, className: "file-info-icon" });
3015
- }
3016
- if (name) {
3017
- const iconName2 = getFileTypeIcon(name, type);
3018
- return /* @__PURE__ */ jsx14(Icon11, { icon: iconName2, width: 48, height: 48, className: "file-info-icon" });
3019
- }
3020
- const iconMap = {
3021
- [FileType.IMAGE]: "material-icon-theme:image",
3022
- [FileType.VIDEO]: "material-icon-theme:video",
3023
- [FileType.MUSIC]: "material-icon-theme:audio",
3024
- [FileType.DOCUMENT]: "material-icon-theme:word",
3025
- [FileType.CODE]: "material-icon-theme:javascript",
3026
- [FileType.ARCHIVE]: "material-icon-theme:zip",
3027
- [FileType.PDF]: "material-icon-theme:pdf",
3028
- [FileType.TEXT]: "material-icon-theme:document",
3029
- [FileType.APPLICATION]: "material-icon-theme:exe"
3030
- };
3031
- const iconName = iconMap[type] || "material-icon-theme:document";
3032
- return /* @__PURE__ */ jsx14(Icon11, { icon: iconName, width: 48, height: 48, className: "file-info-icon" });
3033
- }
3034
- function getFileTypeName(type, extension) {
3035
- switch (type) {
3036
- case FileType.FOLDER:
3037
- return "\u6587\u4EF6\u5939";
3038
- case FileType.IMAGE:
3039
- return `\u56FE\u7247${extension ? ` (${extension.toUpperCase()})` : ""}`;
3040
- case FileType.VIDEO:
3041
- return `\u89C6\u9891${extension ? ` (${extension.toUpperCase()})` : ""}`;
3042
- case FileType.MUSIC:
3043
- return `\u97F3\u9891${extension ? ` (${extension.toUpperCase()})` : ""}`;
3044
- case FileType.DOCUMENT:
3045
- return `\u6587\u6863${extension ? ` (${extension.toUpperCase()})` : ""}`;
3046
- case FileType.CODE:
3047
- return `\u4EE3\u7801\u6587\u4EF6${extension ? ` (${extension.toUpperCase()})` : ""}`;
3048
- case FileType.ARCHIVE:
3049
- return `\u538B\u7F29\u5305${extension ? ` (${extension.toUpperCase()})` : ""}`;
3050
- default:
3051
- return extension ? `${extension.toUpperCase()} \u6587\u4EF6` : "\u6587\u4EF6";
3052
- }
3053
- }
3054
- function getExtension(filename) {
3055
- const lastDot = filename.lastIndexOf(".");
3056
- if (lastDot === -1 || lastDot === 0) return void 0;
3057
- return filename.substring(lastDot + 1).toLowerCase();
3058
- }
3059
- function getDirectory(path) {
3060
- const lastSlash = path.lastIndexOf("/");
3061
- if (lastSlash === -1) return path;
3062
- return path.substring(0, lastSlash) || "/";
3063
- }
3064
- function FileInfoDialog({ visible, item, onClose }) {
3065
- if (!visible || !item) return null;
3066
- const extension = getExtension(item.name);
3067
- const directory = getDirectory(item.id);
3068
- const handleBackdropClick = (e) => {
3069
- if (e.target === e.currentTarget) {
3070
- onClose();
3071
- }
3072
- };
3073
- React.useEffect(() => {
3074
- const handleKeyDown = (e) => {
3075
- if (e.key === "Escape") {
3076
- onClose();
3077
- }
3078
- };
3079
- if (visible) {
3080
- document.addEventListener("keydown", handleKeyDown);
3081
- }
3082
- return () => document.removeEventListener("keydown", handleKeyDown);
3083
- }, [visible, onClose]);
3084
- return /* @__PURE__ */ jsx14("div", { className: "file-info-dialog-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog", children: [
3085
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-header", children: [
3086
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-title", children: [
3087
- getFileIcon(item.type, item.name),
3088
- /* @__PURE__ */ jsx14("span", { className: "file-info-dialog-name", title: item.name, children: item.name })
3089
- ] }),
3090
- /* @__PURE__ */ jsx14("button", { className: "file-info-dialog-close", onClick: onClose, children: /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:x", width: 18, height: 18 }) })
3091
- ] }),
3092
- /* @__PURE__ */ jsxs12("div", { className: "file-info-dialog-content", children: [
3093
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3094
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3095
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:file", width: 14, height: 14 }),
3096
- /* @__PURE__ */ jsx14("span", { children: "\u7C7B\u578B" })
3097
- ] }),
3098
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: getFileTypeName(item.type, extension) })
3099
- ] }),
3100
- item.type !== FileType.FOLDER && item.size && /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3101
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3102
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:hard-drive", width: 14, height: 14 }),
3103
- /* @__PURE__ */ jsx14("span", { children: "\u5927\u5C0F" })
3104
- ] }),
3105
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: item.size })
3106
- ] }),
3107
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3108
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3109
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:map-pin", width: 14, height: 14 }),
3110
- /* @__PURE__ */ jsx14("span", { children: "\u4F4D\u7F6E" })
3111
- ] }),
3112
- /* @__PURE__ */ jsx14("div", { className: "file-info-value file-info-value--path", title: directory, children: directory })
3113
- ] }),
3114
- /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3115
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3116
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:map-pin", width: 14, height: 14 }),
3117
- /* @__PURE__ */ jsx14("span", { children: "\u5B8C\u6574\u8DEF\u5F84" })
3118
- ] }),
3119
- /* @__PURE__ */ jsx14("div", { className: "file-info-value file-info-value--path", title: item.id, children: item.id })
3120
- ] }),
3121
- item.dateModified && /* @__PURE__ */ jsxs12("div", { className: "file-info-row", children: [
3122
- /* @__PURE__ */ jsxs12("div", { className: "file-info-label", children: [
3123
- /* @__PURE__ */ jsx14(Icon11, { icon: "lucide:clock", width: 14, height: 14 }),
3124
- /* @__PURE__ */ jsx14("span", { children: "\u4FEE\u6539\u65F6\u95F4" })
3125
- ] }),
3126
- /* @__PURE__ */ jsx14("div", { className: "file-info-value", children: item.dateModified })
3127
- ] })
3128
- ] }),
3129
- /* @__PURE__ */ jsx14("div", { className: "file-info-dialog-footer", children: /* @__PURE__ */ jsx14("button", { className: "file-info-dialog-btn", onClick: onClose, children: "\u5173\u95ED" }) })
3130
- ] }) });
3131
- }
3132
-
3133
- // src/hooks/useSelection.ts
3134
- import { useState as useState7, useCallback as useCallback5 } from "react";
3135
- function useSelection() {
3136
- const [selectedIds, setSelectedIds] = useState7(/* @__PURE__ */ new Set());
3137
- const [lastSelectedId, setLastSelectedId] = useState7(null);
3138
- const [editingId, setEditingId] = useState7(null);
3139
- const clearSelection = useCallback5(() => {
3140
- setSelectedIds(/* @__PURE__ */ new Set());
3141
- setLastSelectedId(null);
3142
- }, []);
3143
- const selectItem = useCallback5((id, items, multi = false, range = false) => {
3144
- if (!id) {
3145
- clearSelection();
3146
- return;
3147
- }
3148
- setSelectedIds((prev) => {
3149
- setLastSelectedId((prevLast) => {
3150
- if (range && prevLast) {
3151
- const indexA = items.findIndex((i) => i.id === prevLast);
3152
- const indexB = items.findIndex((i) => i.id === id);
3153
- if (indexA !== -1 && indexB !== -1) {
3154
- const start = Math.min(indexA, indexB);
3155
- const end = Math.max(indexA, indexB);
3156
- const newSet = new Set(multi ? prev : []);
3157
- for (let i = start; i <= end; i++) {
3158
- const item = items[i];
3159
- if (item) {
3160
- newSet.add(item.id);
3161
- }
3162
- }
3163
- setSelectedIds(newSet);
3164
- return id;
3165
- }
3166
- }
3167
- if (multi) {
3168
- const newSet = new Set(prev);
3169
- if (newSet.has(id)) {
3170
- newSet.delete(id);
3171
- } else {
3172
- newSet.add(id);
3173
- }
3174
- setSelectedIds(newSet);
3175
- return id;
3176
- }
3177
- setSelectedIds(/* @__PURE__ */ new Set([id]));
3178
- return id;
3179
- });
3180
- return prev;
3181
- });
3182
- }, [clearSelection]);
3183
- const selectAll = useCallback5((items) => {
3184
- setSelectedIds(new Set(items.map((i) => i.id)));
3185
- }, []);
3186
- const setEditing = useCallback5((id) => {
3187
- setEditingId(id);
3188
- }, []);
3189
- const isSelected = useCallback5((id) => {
3190
- return selectedIds.has(id);
3191
- }, [selectedIds]);
3192
- return {
3193
- selectedIds,
3194
- lastSelectedId,
3195
- editingId,
3196
- clearSelection,
3197
- selectItem,
3198
- selectAll,
3199
- setEditing,
3200
- isSelected
3201
- };
3202
- }
3203
-
3204
- // src/hooks/useDragAndDrop.ts
3205
- import { useState as useState8, useCallback as useCallback6 } from "react";
3206
- function useDragAndDrop(getSelectedIds, onSelect, onMove) {
3207
- const [dragOverId, setDragOverId] = useState8(null);
3208
- const [isDragging, setIsDragging] = useState8(false);
3209
- const handleDragStart = useCallback6((e, itemId) => {
3210
- if (!e.dataTransfer) return;
3211
- const selectedIds = getSelectedIds();
3212
- if (!selectedIds.has(itemId)) {
3213
- onSelect(itemId, false, false);
3214
- }
3215
- const draggedIds = selectedIds.has(itemId) ? selectedIds : /* @__PURE__ */ new Set([itemId]);
3216
- e.dataTransfer.setData("text/plain", JSON.stringify([...draggedIds]));
3217
- e.dataTransfer.effectAllowed = "move";
3218
- setIsDragging(true);
3219
- }, [getSelectedIds, onSelect]);
3220
- const handleDragOver = useCallback6((e, item) => {
3221
- if (!isDragging) return;
3222
- if (item.type === FileType.FOLDER) {
3223
- const selectedIds = getSelectedIds();
3224
- if (!selectedIds.has(item.id)) {
3225
- e.preventDefault();
3226
- setDragOverId(item.id);
3227
- }
3228
- }
3229
- }, [isDragging, getSelectedIds]);
3230
- const handleDragLeave = useCallback6(() => {
3231
- setDragOverId(null);
3232
- }, []);
3233
- const handleDrop = useCallback6((e, targetItem) => {
3234
- setDragOverId(null);
3235
- setIsDragging(false);
3236
- if (!e.dataTransfer || targetItem.type !== FileType.FOLDER) return;
3237
- const data = e.dataTransfer.getData("text/plain");
3238
- if (!data) return;
3239
- try {
3240
- const draggedIds = JSON.parse(data);
3241
- const itemIds = new Set(draggedIds);
3242
- if (itemIds.has(targetItem.id)) return;
3243
- onMove(targetItem.id, itemIds);
3244
- } catch {
3245
- }
3246
- }, [onMove]);
3247
- const handleDragEnd = useCallback6(() => {
3248
- setDragOverId(null);
3249
- setIsDragging(false);
3250
- }, []);
3251
- return {
3252
- dragOverId,
3253
- isDragging,
3254
- handleDragStart,
3255
- handleDragOver,
3256
- handleDragLeave,
3257
- handleDrop,
3258
- handleDragEnd
3259
- };
3260
- }
3261
-
3262
- // src/hooks/useMediaPlayer.ts
3263
- import { useState as useState9, useCallback as useCallback7, useEffect as useEffect6 } from "react";
3264
- function useMediaPlayer(mediaType, mediaRef) {
3265
- const [isPlaying, setIsPlaying] = useState9(false);
3266
- const [progress, setProgress] = useState9(0);
3267
- const [currentTime, setCurrentTime] = useState9(0);
3268
- const [duration, setDuration] = useState9(0);
3269
- const [isMuted, setIsMuted] = useState9(false);
3270
- const [volume, setVolume] = useState9(1);
3271
- const [lastVolume, setLastVolume] = useState9(1);
3272
- const [showControls, setShowControls] = useState9(false);
3273
- const isAudio = mediaType === FileType.MUSIC;
3274
- const updateProgress = useCallback7(() => {
3275
- const media = mediaRef.current;
3276
- if (media) {
3277
- const curr = media.currentTime;
3278
- const dur = media.duration;
3279
- setCurrentTime(curr);
3280
- if (dur && !isNaN(dur)) {
3281
- setDuration(dur);
3282
- setProgress(curr / dur * 100);
3283
- }
3284
- }
3285
- }, [mediaRef]);
3286
- const togglePlay = useCallback7(() => {
3287
- const media = mediaRef.current;
3288
- if (media) {
3289
- if (isPlaying) {
3290
- media.pause();
3291
- setIsPlaying(false);
3292
- } else {
3293
- media.play();
3294
- setIsPlaying(true);
3295
- }
3296
- }
3297
- }, [isPlaying, mediaRef]);
3298
- const toggleMute = useCallback7(() => {
3299
- const media = mediaRef.current;
3300
- if (media) {
3301
- if (isMuted) {
3302
- const volToRestore = lastVolume || 1;
3303
- media.volume = volToRestore;
3304
- media.muted = false;
3305
- setVolume(volToRestore);
3306
- setIsMuted(false);
3307
- } else {
3308
- setLastVolume(volume);
3309
- media.volume = 0;
3310
- media.muted = true;
3311
- setVolume(0);
3312
- setIsMuted(true);
3313
- }
3314
- }
3315
- }, [isMuted, lastVolume, volume, mediaRef]);
3316
- const handleVolumeChange = useCallback7((val) => {
3317
- setVolume(val);
3318
- const media = mediaRef.current;
3319
- if (media) {
3320
- media.volume = val;
3321
- if (val === 0) {
3322
- setIsMuted(true);
3323
- media.muted = true;
3324
- } else {
3325
- setIsMuted(false);
3326
- media.muted = false;
3327
- }
3328
- }
3329
- }, [mediaRef]);
3330
- const seekTo = useCallback7((time) => {
3331
- const media = mediaRef.current;
3332
- if (media && duration) {
3333
- media.currentTime = time;
3334
- setCurrentTime(time);
3335
- setProgress(time / duration * 100);
3336
- }
3337
- }, [duration, mediaRef]);
3338
- const formatTime = useCallback7((time) => {
3339
- if (isNaN(time)) return "0:00";
3340
- const minutes = Math.floor(time / 60);
3341
- const seconds = Math.floor(time % 60);
3342
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
3343
- }, []);
3344
- const autoPlay = useCallback7(() => {
3345
- const media = mediaRef.current;
3346
- if ((mediaType === FileType.VIDEO || isAudio) && media) {
3347
- media.volume = volume;
3348
- media.play().catch(() => {
3349
- });
3350
- setIsPlaying(true);
3351
- }
3352
- }, [mediaType, isAudio, volume, mediaRef]);
3353
- useEffect6(() => {
3354
- const media = mediaRef.current;
3355
- if (media) {
3356
- media.addEventListener("timeupdate", updateProgress);
3357
- media.addEventListener("loadedmetadata", updateProgress);
3358
- media.addEventListener("ended", () => {
3359
- setIsPlaying(false);
3360
- });
3361
- return () => {
3362
- media.removeEventListener("timeupdate", updateProgress);
3363
- media.removeEventListener("loadedmetadata", updateProgress);
3364
- };
3365
- }
3366
- }, [mediaRef, updateProgress]);
3367
- return {
3368
- isPlaying,
3369
- progress,
3370
- currentTime,
3371
- duration,
3372
- isMuted,
3373
- volume,
3374
- showControls,
3375
- isAudio,
3376
- togglePlay,
3377
- toggleMute,
3378
- handleVolumeChange,
3379
- seekTo,
3380
- formatTime,
3381
- autoPlay,
3382
- updateProgress
3383
- };
3384
- }
3385
-
3386
- // src/hooks/useApplicationIcon.ts
3387
- import { useState as useState10, useCallback as useCallback8, useEffect as useEffect7 } from "react";
3388
- function useApplicationIcon(items) {
3389
- const appIconCache = /* @__PURE__ */ new Map();
3390
- const [appIconUrls, setAppIconUrls] = useState10(/* @__PURE__ */ new Map());
3391
- const loadApplicationIcon = useCallback8(async (item) => {
3392
- if (item.type !== FileType.APPLICATION || !item.id) return;
3393
- if (appIconCache.has(item.id)) {
3394
- const cachedUrl = appIconCache.get(item.id);
3395
- if (cachedUrl) {
3396
- setAppIconUrls((prev) => new Map(prev).set(item.id, cachedUrl));
3397
- }
3398
- return;
3399
- }
3400
- if (appIconUrls.has(item.id)) {
3401
- return;
3402
- }
3403
- if (typeof window.fileExplorerAPI !== "undefined" && window.fileExplorerAPI.getApplicationIcon) {
3404
- try {
3405
- const iconUrl = await window.fileExplorerAPI.getApplicationIcon(item.id);
3406
- if (iconUrl) {
3407
- appIconCache.set(item.id, iconUrl);
3408
- setAppIconUrls((prev) => new Map(prev).set(item.id, iconUrl));
3409
- }
3410
- } catch (error) {
3411
- console.error(`Failed to load application icon for ${item.name}:`, error);
3412
- }
3413
- }
3414
- }, [appIconUrls]);
3415
- useEffect7(() => {
3416
- items.forEach((item) => {
3417
- if (item.type === FileType.APPLICATION && !appIconUrls.has(item.id)) {
3418
- loadApplicationIcon(item);
3419
- }
3420
- });
3421
- }, [items, appIconUrls, loadApplicationIcon]);
3422
- const getAppIconUrl = useCallback8((item) => {
3423
- return appIconUrls.get(item.id);
3424
- }, [appIconUrls]);
3425
- return {
3426
- getAppIconUrl,
3427
- loadApplicationIcon
3428
- };
3429
- }
3430
- export {
3431
- Breadcrumb,
3432
- CompressDialog,
3433
- ContextMenu,
3434
- FileGrid,
3435
- FileIcon,
3436
- FileInfoDialog,
3437
- FileList,
3438
- FileListView,
3439
- FileSidebar,
3440
- FileType,
3441
- ProgressDialog,
3442
- SortIndicator,
3443
- StatusBar,
3444
- Toolbar,
3445
- Window,
3446
- useApplicationIcon,
3447
- useDragAndDrop,
3448
- useMediaPlayer,
3449
- useSelection,
3450
- useWindowDrag,
3451
- useWindowResize
3452
- };
3453
- //# 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};