@huyooo/file-explorer-frontend-vue 0.4.2

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 (76) hide show
  1. package/dist/components/Breadcrumb.vue.d.ts +11 -0
  2. package/dist/components/Breadcrumb.vue.d.ts.map +1 -0
  3. package/dist/components/CompressDialog.vue.d.ts +16 -0
  4. package/dist/components/CompressDialog.vue.d.ts.map +1 -0
  5. package/dist/components/ContextMenu.vue.d.ts +18 -0
  6. package/dist/components/ContextMenu.vue.d.ts.map +1 -0
  7. package/dist/components/FileGrid.vue.d.ts +40 -0
  8. package/dist/components/FileGrid.vue.d.ts.map +1 -0
  9. package/dist/components/FileIcon.vue.d.ts +13 -0
  10. package/dist/components/FileIcon.vue.d.ts.map +1 -0
  11. package/dist/components/FileInfoDialog.vue.d.ts +14 -0
  12. package/dist/components/FileInfoDialog.vue.d.ts.map +1 -0
  13. package/dist/components/FileList.vue.d.ts +37 -0
  14. package/dist/components/FileList.vue.d.ts.map +1 -0
  15. package/dist/components/FileListView.vue.d.ts +43 -0
  16. package/dist/components/FileListView.vue.d.ts.map +1 -0
  17. package/dist/components/FileSidebar.vue.d.ts +17 -0
  18. package/dist/components/FileSidebar.vue.d.ts.map +1 -0
  19. package/dist/components/ProgressDialog.vue.d.ts +28 -0
  20. package/dist/components/ProgressDialog.vue.d.ts.map +1 -0
  21. package/dist/components/SortIndicator.vue.d.ts +6 -0
  22. package/dist/components/SortIndicator.vue.d.ts.map +1 -0
  23. package/dist/components/StatusBar.vue.d.ts +27 -0
  24. package/dist/components/StatusBar.vue.d.ts.map +1 -0
  25. package/dist/components/Toolbar.vue.d.ts +60 -0
  26. package/dist/components/Toolbar.vue.d.ts.map +1 -0
  27. package/dist/components/Window.vue.d.ts +65 -0
  28. package/dist/components/Window.vue.d.ts.map +1 -0
  29. package/dist/composables/useApplicationIcon.d.ts +16 -0
  30. package/dist/composables/useApplicationIcon.d.ts.map +1 -0
  31. package/dist/composables/useDragAndDrop.d.ts +14 -0
  32. package/dist/composables/useDragAndDrop.d.ts.map +1 -0
  33. package/dist/composables/useMediaPlayer.d.ts +24 -0
  34. package/dist/composables/useMediaPlayer.d.ts.map +1 -0
  35. package/dist/composables/useSelection.d.ts +15 -0
  36. package/dist/composables/useSelection.d.ts.map +1 -0
  37. package/dist/composables/useWindowDrag.d.ts +18 -0
  38. package/dist/composables/useWindowDrag.d.ts.map +1 -0
  39. package/dist/composables/useWindowResize.d.ts +12 -0
  40. package/dist/composables/useWindowResize.d.ts.map +1 -0
  41. package/dist/index.css +1 -0
  42. package/dist/index.d.ts +22 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +4051 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/types/index.d.ts +268 -0
  47. package/dist/types/index.d.ts.map +1 -0
  48. package/dist/utils/fileTypeIcon.d.ts +6 -0
  49. package/dist/utils/fileTypeIcon.d.ts.map +1 -0
  50. package/dist/utils/folderTypeIcon.d.ts +14 -0
  51. package/dist/utils/folderTypeIcon.d.ts.map +1 -0
  52. package/package.json +55 -0
  53. package/src/components/Breadcrumb.vue +111 -0
  54. package/src/components/CompressDialog.vue +478 -0
  55. package/src/components/ContextMenu.vue +550 -0
  56. package/src/components/FileGrid.vue +504 -0
  57. package/src/components/FileIcon.vue +132 -0
  58. package/src/components/FileInfoDialog.vue +465 -0
  59. package/src/components/FileList.vue +421 -0
  60. package/src/components/FileListView.vue +321 -0
  61. package/src/components/FileSidebar.vue +158 -0
  62. package/src/components/ProgressDialog.vue +368 -0
  63. package/src/components/SortIndicator.vue +22 -0
  64. package/src/components/StatusBar.vue +43 -0
  65. package/src/components/Toolbar.vue +271 -0
  66. package/src/components/Window.vue +561 -0
  67. package/src/composables/useApplicationIcon.ts +79 -0
  68. package/src/composables/useDragAndDrop.ts +103 -0
  69. package/src/composables/useMediaPlayer.ts +174 -0
  70. package/src/composables/useSelection.ts +107 -0
  71. package/src/composables/useWindowDrag.ts +66 -0
  72. package/src/composables/useWindowResize.ts +134 -0
  73. package/src/index.ts +32 -0
  74. package/src/types/index.ts +273 -0
  75. package/src/utils/fileTypeIcon.ts +309 -0
  76. package/src/utils/folderTypeIcon.ts +132 -0
@@ -0,0 +1,478 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <div v-if="visible" class="compress-dialog-overlay" @click="emit('cancel')">
4
+ <div class="compress-dialog" @click.stop>
5
+ <!-- 头部 -->
6
+ <div class="compress-dialog-header">
7
+ <div class="compress-dialog-title">
8
+ <Archive :size="20" />
9
+ <span>压缩文件</span>
10
+ </div>
11
+ <button class="compress-dialog-close" @click="emit('cancel')">
12
+ <X :size="18" />
13
+ </button>
14
+ </div>
15
+
16
+ <!-- 内容 -->
17
+ <div class="compress-dialog-content">
18
+ <!-- 文件信息 -->
19
+ <div class="compress-dialog-info">
20
+ <FileArchive :size="16" />
21
+ <span>{{ fileDisplayName }}</span>
22
+ </div>
23
+
24
+ <!-- 输出文件名 -->
25
+ <div class="compress-dialog-field">
26
+ <label>文件名</label>
27
+ <div class="compress-dialog-input-group">
28
+ <input
29
+ type="text"
30
+ v-model="outputName"
31
+ placeholder="输入文件名"
32
+ />
33
+ <span class="compress-dialog-ext">{{ currentExt }}</span>
34
+ </div>
35
+ </div>
36
+
37
+ <!-- 压缩格式 -->
38
+ <div class="compress-dialog-field">
39
+ <label>压缩格式</label>
40
+ <select v-model="format">
41
+ <option v-for="opt in FORMAT_OPTIONS" :key="opt.value" :value="opt.value">
42
+ {{ opt.label }}
43
+ </option>
44
+ </select>
45
+ </div>
46
+
47
+ <!-- 压缩级别 -->
48
+ <div class="compress-dialog-field">
49
+ <label>压缩级别</label>
50
+ <div class="compress-dialog-levels">
51
+ <label v-for="opt in LEVEL_OPTIONS" :key="opt.value" class="compress-dialog-level">
52
+ <input
53
+ type="radio"
54
+ name="level"
55
+ :value="opt.value"
56
+ v-model="level"
57
+ />
58
+ <span class="compress-dialog-level-label">{{ opt.label }}</span>
59
+ <span class="compress-dialog-level-desc">{{ opt.desc }}</span>
60
+ </label>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- 密码保护(仅 zip/7z) -->
65
+ <div v-if="supportsPassword" class="compress-dialog-field">
66
+ <label>密码保护(可选)</label>
67
+ <div class="compress-dialog-input-group">
68
+ <input
69
+ :type="showPassword ? 'text' : 'password'"
70
+ v-model="password"
71
+ placeholder="设置密码"
72
+ />
73
+ <button
74
+ type="button"
75
+ class="compress-dialog-toggle-password"
76
+ @click="showPassword = !showPassword"
77
+ >
78
+ {{ showPassword ? '隐藏' : '显示' }}
79
+ </button>
80
+ </div>
81
+ </div>
82
+
83
+ <!-- 删除源文件选项 -->
84
+ <div class="compress-dialog-field compress-dialog-checkbox">
85
+ <label>
86
+ <input type="checkbox" v-model="deleteSource" />
87
+ <span>压缩后删除源文件</span>
88
+ </label>
89
+ </div>
90
+
91
+ <!-- 输出路径预览 -->
92
+ <div class="compress-dialog-preview">
93
+ <span class="compress-dialog-preview-label">输出位置:</span>
94
+ <span class="compress-dialog-preview-path">{{ fullOutputPath }}</span>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- 底部按钮 -->
99
+ <div class="compress-dialog-footer">
100
+ <button class="compress-dialog-btn compress-dialog-btn-cancel" @click="emit('cancel')">
101
+ 取消
102
+ </button>
103
+ <button
104
+ class="compress-dialog-btn compress-dialog-btn-confirm"
105
+ @click="handleConfirm"
106
+ :disabled="!outputName.trim()"
107
+ >
108
+ 压缩
109
+ </button>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </Teleport>
114
+ </template>
115
+
116
+ <script setup lang="ts">
117
+ import { ref, computed, watch } from 'vue';
118
+ import { Archive, FileArchive, X } from 'lucide-vue-next';
119
+ import type { CompressFormat, CompressLevel, CompressOptions } from '../types';
120
+
121
+ type CompressDialogOptions = Omit<CompressOptions, 'outputDir'>;
122
+
123
+ interface Props {
124
+ visible: boolean;
125
+ filePaths: string[];
126
+ outputDir: string;
127
+ }
128
+
129
+ const props = defineProps<Props>();
130
+
131
+ const emit = defineEmits<{
132
+ confirm: [options: CompressDialogOptions];
133
+ cancel: [];
134
+ }>();
135
+
136
+ /** 格式选项配置 */
137
+ const FORMAT_OPTIONS: { value: CompressFormat; label: string; ext: string }[] = [
138
+ { value: 'zip', label: 'ZIP', ext: '.zip' },
139
+ { value: 'tgz', label: 'TAR.GZ (gzip)', ext: '.tar.gz' },
140
+ { value: 'tarbz2', label: 'TAR.BZ2 (bzip2)', ext: '.tar.bz2' },
141
+ { value: 'tar', label: 'TAR (无压缩)', ext: '.tar' },
142
+ ];
143
+
144
+ /** 压缩级别选项 */
145
+ const LEVEL_OPTIONS = [
146
+ { value: 'fast', label: '快速', desc: '压缩速度快,文件较大' },
147
+ { value: 'normal', label: '标准', desc: '平衡速度和大小' },
148
+ { value: 'best', label: '最佳', desc: '文件最小,速度较慢' },
149
+ ] as const;
150
+
151
+ const format = ref<CompressFormat>('zip');
152
+ const level = ref<CompressLevel>('normal');
153
+ const outputName = ref('');
154
+ const deleteSource = ref(false);
155
+ const password = ref('');
156
+ const showPassword = ref(false);
157
+
158
+ // 根据选中文件生成默认输出名称
159
+ const defaultOutputName = computed(() => {
160
+ if (props.filePaths.length === 0) return 'archive';
161
+ if (props.filePaths.length === 1) {
162
+ const name = props.filePaths[0].split('/').pop() || 'archive';
163
+ return name.replace(/\.[^.]+$/, '');
164
+ }
165
+ return '压缩文件';
166
+ });
167
+
168
+ // 文件显示名称
169
+ const fileDisplayName = computed(() => {
170
+ if (props.filePaths.length === 1) {
171
+ return props.filePaths[0].split('/').pop();
172
+ }
173
+ return `${props.filePaths.length} 个项目`;
174
+ });
175
+
176
+ // 当前格式的扩展名
177
+ const currentExt = computed(() => {
178
+ return FORMAT_OPTIONS.find(f => f.value === format.value)?.ext || '.zip';
179
+ });
180
+
181
+ // 完整输出路径预览
182
+ const fullOutputPath = computed(() => {
183
+ return `${props.outputDir}/${outputName.value}${currentExt.value}`;
184
+ });
185
+
186
+ // 是否支持密码
187
+ const supportsPassword = computed(() => {
188
+ // 当前后端未实现密码压缩,避免 UI 误导:直接关闭密码选项
189
+ return false;
190
+ });
191
+
192
+ // 初始化
193
+ watch(() => props.visible, (visible) => {
194
+ if (visible) {
195
+ outputName.value = defaultOutputName.value;
196
+ format.value = 'zip';
197
+ level.value = 'normal';
198
+ deleteSource.value = false;
199
+ password.value = '';
200
+ }
201
+ });
202
+
203
+ const handleConfirm = () => {
204
+ emit('confirm', {
205
+ format: format.value,
206
+ level: level.value,
207
+ outputName: outputName.value + currentExt.value,
208
+ deleteSource: deleteSource.value,
209
+ });
210
+ };
211
+ </script>
212
+
213
+ <style scoped>
214
+ .compress-dialog-overlay {
215
+ position: fixed;
216
+ inset: 0;
217
+ background: rgba(0, 0, 0, 0.5);
218
+ display: flex;
219
+ align-items: center;
220
+ justify-content: center;
221
+ z-index: 10000;
222
+ }
223
+
224
+ .compress-dialog {
225
+ background: white;
226
+ border-radius: 12px;
227
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
228
+ width: 420px;
229
+ max-width: 90vw;
230
+ max-height: 90vh;
231
+ overflow: hidden;
232
+ display: flex;
233
+ flex-direction: column;
234
+ }
235
+
236
+ .compress-dialog-header {
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: space-between;
240
+ padding: 16px 20px;
241
+ border-bottom: 1px solid rgb(229, 231, 233);
242
+ }
243
+
244
+ .compress-dialog-title {
245
+ display: flex;
246
+ align-items: center;
247
+ gap: 8px;
248
+ font-weight: 600;
249
+ font-size: 16px;
250
+ color: rgb(17, 24, 39);
251
+ }
252
+
253
+ .compress-dialog-close {
254
+ background: none;
255
+ border: none;
256
+ padding: 4px;
257
+ cursor: pointer;
258
+ color: rgb(107, 114, 128);
259
+ border-radius: 4px;
260
+ display: flex;
261
+ align-items: center;
262
+ justify-content: center;
263
+ }
264
+
265
+ .compress-dialog-close:hover {
266
+ background: rgb(243, 244, 246);
267
+ color: rgb(55, 65, 81);
268
+ }
269
+
270
+ .compress-dialog-content {
271
+ padding: 20px;
272
+ overflow-y: auto;
273
+ display: flex;
274
+ flex-direction: column;
275
+ gap: 16px;
276
+ }
277
+
278
+ .compress-dialog-info {
279
+ display: flex;
280
+ align-items: center;
281
+ gap: 8px;
282
+ padding: 12px;
283
+ background: rgb(249, 250, 251);
284
+ border-radius: 8px;
285
+ color: rgb(55, 65, 81);
286
+ font-size: 14px;
287
+ }
288
+
289
+ .compress-dialog-field {
290
+ display: flex;
291
+ flex-direction: column;
292
+ gap: 6px;
293
+ }
294
+
295
+ .compress-dialog-field > label {
296
+ font-size: 13px;
297
+ font-weight: 500;
298
+ color: rgb(55, 65, 81);
299
+ }
300
+
301
+ .compress-dialog-input-group {
302
+ display: flex;
303
+ align-items: stretch;
304
+ }
305
+
306
+ .compress-dialog-input-group input {
307
+ flex: 1;
308
+ padding: 8px 12px;
309
+ border: 1px solid rgb(209, 213, 219);
310
+ border-radius: 6px 0 0 6px;
311
+ font-size: 14px;
312
+ outline: none;
313
+ transition: border-color 0.2s;
314
+ }
315
+
316
+ .compress-dialog-input-group input:focus {
317
+ border-color: rgb(59, 130, 246);
318
+ }
319
+
320
+ .compress-dialog-ext {
321
+ padding: 8px 12px;
322
+ background: rgb(243, 244, 246);
323
+ border: 1px solid rgb(209, 213, 219);
324
+ border-left: none;
325
+ border-radius: 0 6px 6px 0;
326
+ font-size: 14px;
327
+ color: rgb(107, 114, 128);
328
+ }
329
+
330
+ .compress-dialog-toggle-password {
331
+ padding: 8px 12px;
332
+ background: rgb(243, 244, 246);
333
+ border: 1px solid rgb(209, 213, 219);
334
+ border-left: none;
335
+ border-radius: 0 6px 6px 0;
336
+ font-size: 12px;
337
+ color: rgb(59, 130, 246);
338
+ cursor: pointer;
339
+ }
340
+
341
+ .compress-dialog-toggle-password:hover {
342
+ background: rgb(229, 231, 235);
343
+ }
344
+
345
+ .compress-dialog-field select {
346
+ padding: 8px 12px;
347
+ border: 1px solid rgb(209, 213, 219);
348
+ border-radius: 6px;
349
+ font-size: 14px;
350
+ outline: none;
351
+ background: white;
352
+ cursor: pointer;
353
+ }
354
+
355
+ .compress-dialog-field select:focus {
356
+ border-color: rgb(59, 130, 246);
357
+ }
358
+
359
+ .compress-dialog-levels {
360
+ display: flex;
361
+ flex-direction: column;
362
+ gap: 8px;
363
+ }
364
+
365
+ .compress-dialog-level {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: 8px;
369
+ padding: 8px 12px;
370
+ border: 1px solid rgb(229, 231, 233);
371
+ border-radius: 6px;
372
+ cursor: pointer;
373
+ transition: all 0.2s;
374
+ }
375
+
376
+ .compress-dialog-level:hover {
377
+ background: rgb(249, 250, 251);
378
+ }
379
+
380
+ .compress-dialog-level:has(input:checked) {
381
+ border-color: rgb(59, 130, 246);
382
+ background: rgb(239, 246, 255);
383
+ }
384
+
385
+ .compress-dialog-level input {
386
+ margin: 0;
387
+ }
388
+
389
+ .compress-dialog-level-label {
390
+ font-size: 14px;
391
+ font-weight: 500;
392
+ color: rgb(17, 24, 39);
393
+ }
394
+
395
+ .compress-dialog-level-desc {
396
+ font-size: 12px;
397
+ color: rgb(107, 114, 128);
398
+ margin-left: auto;
399
+ }
400
+
401
+ .compress-dialog-checkbox label {
402
+ display: flex;
403
+ align-items: center;
404
+ gap: 8px;
405
+ cursor: pointer;
406
+ font-size: 14px;
407
+ color: rgb(55, 65, 81);
408
+ }
409
+
410
+ .compress-dialog-checkbox input {
411
+ margin: 0;
412
+ width: 16px;
413
+ height: 16px;
414
+ }
415
+
416
+ .compress-dialog-preview {
417
+ padding: 10px 12px;
418
+ background: rgb(249, 250, 251);
419
+ border-radius: 6px;
420
+ font-size: 12px;
421
+ display: flex;
422
+ flex-direction: column;
423
+ gap: 4px;
424
+ }
425
+
426
+ .compress-dialog-preview-label {
427
+ color: rgb(107, 114, 128);
428
+ }
429
+
430
+ .compress-dialog-preview-path {
431
+ color: rgb(55, 65, 81);
432
+ word-break: break-all;
433
+ }
434
+
435
+ .compress-dialog-footer {
436
+ display: flex;
437
+ justify-content: flex-end;
438
+ gap: 12px;
439
+ padding: 16px 20px;
440
+ border-top: 1px solid rgb(229, 231, 233);
441
+ }
442
+
443
+ .compress-dialog-btn {
444
+ padding: 8px 20px;
445
+ border-radius: 6px;
446
+ font-size: 14px;
447
+ font-weight: 500;
448
+ cursor: pointer;
449
+ transition: all 0.2s;
450
+ }
451
+
452
+ .compress-dialog-btn-cancel {
453
+ background: white;
454
+ border: 1px solid rgb(209, 213, 219);
455
+ color: rgb(55, 65, 81);
456
+ }
457
+
458
+ .compress-dialog-btn-cancel:hover {
459
+ background: rgb(249, 250, 251);
460
+ }
461
+
462
+ .compress-dialog-btn-confirm {
463
+ background: rgb(59, 130, 246);
464
+ border: 1px solid rgb(59, 130, 246);
465
+ color: white;
466
+ }
467
+
468
+ .compress-dialog-btn-confirm:hover {
469
+ background: rgb(37, 99, 235);
470
+ }
471
+
472
+ .compress-dialog-btn-confirm:disabled {
473
+ background: rgb(156, 163, 175);
474
+ border-color: rgb(156, 163, 175);
475
+ cursor: not-allowed;
476
+ }
477
+ </style>
478
+