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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.css +0 -1
  2. package/dist/index.js +1 -3456
  3. package/package.json +4 -4
  4. package/dist/index.css.map +0 -1
  5. package/dist/index.js.map +0 -1
  6. package/src/components/Breadcrumb.css +0 -61
  7. package/src/components/Breadcrumb.tsx +0 -38
  8. package/src/components/CompressDialog.css +0 -267
  9. package/src/components/CompressDialog.tsx +0 -222
  10. package/src/components/ContextMenu.css +0 -155
  11. package/src/components/ContextMenu.tsx +0 -375
  12. package/src/components/FileGrid.css +0 -239
  13. package/src/components/FileGrid.tsx +0 -278
  14. package/src/components/FileIcon.css +0 -41
  15. package/src/components/FileIcon.tsx +0 -86
  16. package/src/components/FileInfoDialog.css +0 -214
  17. package/src/components/FileInfoDialog.tsx +0 -202
  18. package/src/components/FileList.css +0 -169
  19. package/src/components/FileList.tsx +0 -228
  20. package/src/components/FileListView.css +0 -36
  21. package/src/components/FileListView.tsx +0 -355
  22. package/src/components/FileSidebar.css +0 -94
  23. package/src/components/FileSidebar.tsx +0 -66
  24. package/src/components/ProgressDialog.css +0 -211
  25. package/src/components/ProgressDialog.tsx +0 -183
  26. package/src/components/SortIndicator.css +0 -7
  27. package/src/components/SortIndicator.tsx +0 -19
  28. package/src/components/StatusBar.css +0 -20
  29. package/src/components/StatusBar.tsx +0 -21
  30. package/src/components/Toolbar.css +0 -150
  31. package/src/components/Toolbar.tsx +0 -127
  32. package/src/components/Window.css +0 -246
  33. package/src/components/Window.tsx +0 -335
  34. package/src/hooks/useApplicationIcon.ts +0 -80
  35. package/src/hooks/useDragAndDrop.ts +0 -104
  36. package/src/hooks/useMediaPlayer.ts +0 -164
  37. package/src/hooks/useSelection.ts +0 -112
  38. package/src/hooks/useWindowDrag.ts +0 -60
  39. package/src/hooks/useWindowResize.ts +0 -126
  40. package/src/index.css +0 -184
  41. package/src/index.ts +0 -37
  42. package/src/types/index.ts +0 -274
  43. package/src/utils/fileTypeIcon.ts +0 -309
  44. package/src/utils/folderTypeIcon.ts +0 -132
@@ -1,183 +0,0 @@
1
- import { createPortal } from 'react-dom';
2
- import { Icon } from '@iconify/react';
3
- import './ProgressDialog.css';
4
-
5
- /** 进度状态 */
6
- export type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';
7
-
8
- /** 进度信息 */
9
- export interface ProgressInfo {
10
- /** 操作类型 */
11
- type: 'compress' | 'extract';
12
- /** 状态 */
13
- status: ProgressStatus;
14
- /** 进度百分比 0-100 */
15
- percent: number;
16
- /** 当前处理的文件 */
17
- currentFile?: string;
18
- /** 已处理文件数 */
19
- processedCount?: number;
20
- /** 总文件数 */
21
- totalCount?: number;
22
- /** 错误信息 */
23
- error?: string;
24
- /** 输出路径 */
25
- outputPath?: string;
26
- }
27
-
28
- interface ProgressDialogProps {
29
- visible: boolean;
30
- progress: ProgressInfo;
31
- onCancel?: () => void;
32
- onClose?: () => void;
33
- /** 打开输出文件夹 */
34
- onOpenFolder?: (path: string) => void;
35
- }
36
-
37
- /**
38
- * 进度对话框组件
39
- */
40
- export function ProgressDialog({
41
- visible,
42
- progress,
43
- onCancel,
44
- onClose,
45
- onOpenFolder,
46
- }: ProgressDialogProps) {
47
- const { type, status, percent, currentFile, processedCount, totalCount, error, outputPath } = progress;
48
-
49
- const title = type === 'compress' ? '压缩文件' : '解压文件';
50
- const isCompleted = status === 'success' || status === 'error';
51
-
52
- // 获取状态图标
53
- const StatusIcon = () => {
54
- switch (status) {
55
- case 'processing':
56
- return <Icon icon="lucide:loader-2" width={24} height={24} className="progress-dialog-icon-spin" />;
57
- case 'success':
58
- return <Icon icon="lucide:check-circle" width={24} height={24} className="progress-dialog-icon-success" />;
59
- case 'error':
60
- return <Icon icon="lucide:x-circle" width={24} height={24} className="progress-dialog-icon-error" />;
61
- default:
62
- return <Icon icon="lucide:archive" width={24} height={24} />;
63
- }
64
- };
65
-
66
- // 获取状态文本
67
- const getStatusText = () => {
68
- switch (status) {
69
- case 'pending':
70
- return '准备中...';
71
- case 'processing':
72
- return type === 'compress' ? '正在压缩...' : '正在解压...';
73
- case 'success':
74
- return type === 'compress' ? '压缩完成' : '解压完成';
75
- case 'error':
76
- return '操作失败';
77
- default:
78
- return '';
79
- }
80
- };
81
-
82
- const handleClose = () => {
83
- if (isCompleted) {
84
- onClose?.();
85
- } else {
86
- onCancel?.();
87
- }
88
- };
89
-
90
- if (!visible) return null;
91
-
92
- return createPortal(
93
- <div className="progress-dialog-overlay">
94
- <div className="progress-dialog">
95
- {/* 头部 */}
96
- <div className="progress-dialog-header">
97
- <div className="progress-dialog-title">
98
- <StatusIcon />
99
- <span>{title}</span>
100
- </div>
101
- {isCompleted && (
102
- <button className="progress-dialog-close" onClick={handleClose}>
103
- <Icon icon="lucide:x" width={18} height={18} />
104
- </button>
105
- )}
106
- </div>
107
-
108
- {/* 内容 */}
109
- <div className="progress-dialog-content">
110
- {/* 状态文本 */}
111
- <div className="progress-dialog-status">{getStatusText()}</div>
112
-
113
- {/* 进度条 */}
114
- {status === 'processing' && (
115
- <div className="progress-dialog-bar-container">
116
- <div className="progress-dialog-bar">
117
- <div
118
- className="progress-dialog-bar-fill"
119
- style={{ width: `${percent}%` }}
120
- />
121
- </div>
122
- <span className="progress-dialog-percent">{percent}%</span>
123
- </div>
124
- )}
125
-
126
- {/* 当前文件 */}
127
- {currentFile && status === 'processing' && (
128
- <div className="progress-dialog-current-file">
129
- {currentFile}
130
- </div>
131
- )}
132
-
133
- {/* 文件计数 */}
134
- {totalCount && totalCount > 0 && status === 'processing' && (
135
- <div className="progress-dialog-count">
136
- {processedCount || 0} / {totalCount} 个文件
137
- </div>
138
- )}
139
-
140
- {/* 错误信息 */}
141
- {error && (
142
- <div className="progress-dialog-error">
143
- {error}
144
- </div>
145
- )}
146
-
147
- {/* 成功后显示输出路径 */}
148
- {status === 'success' && outputPath && (
149
- <div className="progress-dialog-output">
150
- <span className="progress-dialog-output-label">输出位置:</span>
151
- <span className="progress-dialog-output-path">{outputPath}</span>
152
- </div>
153
- )}
154
- </div>
155
-
156
- {/* 底部按钮 */}
157
- <div className="progress-dialog-footer">
158
- {status === 'processing' && onCancel && (
159
- <button className="progress-dialog-btn progress-dialog-btn-cancel" onClick={onCancel}>
160
- 取消
161
- </button>
162
- )}
163
- {status === 'success' && outputPath && onOpenFolder && (
164
- <button
165
- className="progress-dialog-btn progress-dialog-btn-folder"
166
- onClick={() => onOpenFolder(outputPath)}
167
- >
168
- <Icon icon="lucide:folder-open" width={16} height={16} />
169
- 打开文件夹
170
- </button>
171
- )}
172
- {isCompleted && (
173
- <button className="progress-dialog-btn progress-dialog-btn-close" onClick={handleClose}>
174
- 关闭
175
- </button>
176
- )}
177
- </div>
178
- </div>
179
- </div>,
180
- document.body
181
- );
182
- }
183
-
@@ -1,7 +0,0 @@
1
- .sort-indicator {
2
- margin-left: 4px;
3
- display: inline-flex;
4
- align-items: center;
5
- color: var(--huyooo-primary);
6
- }
7
-
@@ -1,19 +0,0 @@
1
- import { Icon } from '@iconify/react';
2
- import './SortIndicator.css';
3
-
4
- interface SortIndicatorProps {
5
- direction: 'asc' | 'desc';
6
- }
7
-
8
- export function SortIndicator({ direction }: SortIndicatorProps) {
9
- return (
10
- <span className="sort-indicator">
11
- <Icon
12
- icon={direction === 'asc' ? 'lucide:chevron-up' : 'lucide:chevron-down'}
13
- width={12}
14
- height={12}
15
- />
16
- </span>
17
- );
18
- }
19
-
@@ -1,20 +0,0 @@
1
- .file-status-bar {
2
- height: 32px;
3
- background-color: var(--huyooo-surface-2);
4
- border-top: 1px solid var(--huyooo-border);
5
- display: flex;
6
- align-items: center;
7
- justify-content: center;
8
- padding: 0 8px;
9
- font-size: 10px;
10
- color: var(--huyooo-text-muted);
11
- user-select: none;
12
- flex-shrink: 0;
13
- z-index: 20;
14
- gap: 4px;
15
- }
16
-
17
- .file-status-bar > * {
18
- flex-shrink: 0;
19
- }
20
-
@@ -1,21 +0,0 @@
1
- import './StatusBar.css';
2
-
3
- interface StatusBarProps {
4
- itemCount?: number;
5
- selectedCount?: number;
6
- children?: React.ReactNode;
7
- }
8
-
9
- export function StatusBar({ itemCount = 0, selectedCount = 0, children }: StatusBarProps) {
10
- return (
11
- <div className="file-status-bar">
12
- {children || (
13
- <>
14
- <span>{itemCount} 个项目</span>
15
- {selectedCount > 0 && <span> • 已选择 {selectedCount} 个</span>}
16
- </>
17
- )}
18
- </div>
19
- );
20
- }
21
-
@@ -1,150 +0,0 @@
1
- .file-toolbar {
2
- height: 48px;
3
- background: var(--huyooo-surface);
4
- backdrop-filter: blur(12px);
5
- border-bottom: 1px solid var(--huyooo-border);
6
- display: flex;
7
- align-items: center;
8
- padding: 0 1rem;
9
- user-select: none;
10
- flex-shrink: 0;
11
- z-index: 30;
12
- position: relative;
13
- }
14
-
15
- .file-toolbar--draggable {
16
- -webkit-app-region: drag;
17
- }
18
-
19
- .file-toolbar-nav {
20
- display: flex;
21
- align-items: center;
22
- color: var(--huyooo-text-muted);
23
- background: var(--huyooo-muted);
24
- border-radius: 0.5rem;
25
- padding: 0.125rem;
26
- flex-shrink: 0;
27
- -webkit-app-region: no-drag;
28
- }
29
-
30
- .file-toolbar-button {
31
- padding: 0.25rem;
32
- border-radius: 0.375rem;
33
- transition: all 200ms;
34
- border: none;
35
- background: transparent;
36
- cursor: pointer;
37
- display: flex;
38
- align-items: center;
39
- justify-content: center;
40
- color: var(--huyooo-text);
41
- }
42
-
43
- .file-toolbar-button:hover:not(:disabled) {
44
- background: var(--huyooo-muted-hover);
45
- }
46
-
47
- .file-toolbar-button:disabled {
48
- color: var(--huyooo-text-disabled);
49
- cursor: default;
50
- }
51
-
52
- .file-toolbar-button--active {
53
- background: var(--huyooo-surface-2);
54
- box-shadow: var(--huyooo-shadow-sm);
55
- color: var(--huyooo-text);
56
- }
57
-
58
- .file-toolbar-breadcrumb {
59
- flex: 1;
60
- min-width: 0;
61
- overflow: hidden;
62
- margin-left: 1rem;
63
- /* 不设置 no-drag,让空白区域可拖拽 */
64
- }
65
-
66
- .file-toolbar-custom {
67
- display: flex;
68
- align-items: center;
69
- gap: 0.5rem;
70
- -webkit-app-region: no-drag;
71
- }
72
-
73
- .file-toolbar-actions {
74
- display: flex;
75
- align-items: center;
76
- gap: 0.75rem;
77
- flex-shrink: 0;
78
- margin-left: auto;
79
- -webkit-app-region: no-drag;
80
- }
81
-
82
- .file-toolbar-search {
83
- position: relative;
84
- display: none;
85
- }
86
-
87
- @media (min-width: 768px) {
88
- .file-toolbar-search {
89
- display: block;
90
- }
91
- }
92
-
93
- .file-toolbar-search-icon {
94
- position: absolute;
95
- left: 0.625rem;
96
- top: 50%;
97
- transform: translateY(-50%);
98
- color: var(--huyooo-text-disabled);
99
- transition: color 200ms;
100
- }
101
-
102
- .file-toolbar-search:focus-within .file-toolbar-search-icon {
103
- color: var(--huyooo-primary);
104
- }
105
-
106
- .file-toolbar-search-input {
107
- background: var(--huyooo-muted);
108
- border: 1px solid transparent;
109
- border-radius: 0.375rem;
110
- padding-left: 2rem;
111
- padding-right: 0.75rem;
112
- padding-top: 0.25rem;
113
- padding-bottom: 0.25rem;
114
- font-size: 0.875rem;
115
- outline: none;
116
- transition: all 200ms;
117
- width: 8rem;
118
- color: var(--huyooo-text);
119
- }
120
-
121
- .file-toolbar-search-input::placeholder {
122
- color: var(--huyooo-text-disabled);
123
- }
124
-
125
- .file-toolbar-search-input:focus {
126
- background: var(--huyooo-surface-2);
127
- border-color: var(--huyooo-primary);
128
- box-shadow: 0 0 0 2px var(--huyooo-focus-ring);
129
- width: 12rem;
130
- }
131
-
132
- .file-toolbar-view-toggle {
133
- display: flex;
134
- align-items: center;
135
- background: var(--huyooo-muted);
136
- border-radius: 0.5rem;
137
- padding: 0.125rem;
138
- color: var(--huyooo-text-muted);
139
- }
140
-
141
- .file-toolbar-view-toggle .file-toolbar-button--active {
142
- background: var(--huyooo-surface-2);
143
- box-shadow: var(--huyooo-shadow-sm);
144
- color: var(--huyooo-text);
145
- }
146
-
147
- .file-toolbar-view-toggle .file-toolbar-button:not(.file-toolbar-button--active):hover {
148
- background: var(--huyooo-muted-hover);
149
- }
150
-
@@ -1,127 +0,0 @@
1
- import { Icon } from '@iconify/react';
2
- import { Breadcrumb } from './Breadcrumb';
3
- import type { BreadcrumbItem } from '../types';
4
- import './Toolbar.css';
5
-
6
- interface ToolbarProps {
7
- canGoBack?: boolean;
8
- canGoForward?: boolean;
9
- breadcrumbs?: BreadcrumbItem[];
10
- viewMode?: 'grid' | 'list';
11
- searchQuery?: string;
12
- showSearch?: boolean;
13
- showViewToggle?: boolean;
14
- draggable?: boolean;
15
- onBack?: () => void;
16
- onForward?: () => void;
17
- onBreadcrumbNavigate?: (item: BreadcrumbItem) => void;
18
- onViewModeChange?: (mode: 'grid' | 'list') => void;
19
- onSearchQueryChange?: (query: string) => void;
20
- children?: React.ReactNode;
21
- breadcrumbSlot?: React.ReactNode;
22
- actionsSlot?: React.ReactNode;
23
- }
24
-
25
- export function Toolbar({
26
- canGoBack = false,
27
- canGoForward = false,
28
- breadcrumbs = [],
29
- viewMode = 'grid',
30
- searchQuery = '',
31
- showSearch = false,
32
- showViewToggle = true,
33
- draggable = false,
34
- onBack,
35
- onForward,
36
- onBreadcrumbNavigate,
37
- onViewModeChange,
38
- onSearchQueryChange,
39
- children,
40
- breadcrumbSlot,
41
- actionsSlot,
42
- }: ToolbarProps) {
43
- return (
44
- <div
45
- className={`file-toolbar ${draggable ? 'file-toolbar--draggable' : ''}`}
46
- >
47
- {/* 导航按钮 */}
48
- <div className="file-toolbar-nav">
49
- <button
50
- className="file-toolbar-button"
51
- onClick={onBack}
52
- disabled={!canGoBack}
53
- title="后退"
54
- >
55
- <Icon icon="lucide:chevron-left" width={18} height={18} />
56
- </button>
57
- <button
58
- className="file-toolbar-button"
59
- onClick={onForward}
60
- disabled={!canGoForward}
61
- title="前进"
62
- >
63
- <Icon icon="lucide:chevron-right" width={18} height={18} />
64
- </button>
65
- </div>
66
-
67
- {/* 面包屑插槽 */}
68
- <div className="file-toolbar-breadcrumb">
69
- {breadcrumbSlot || (
70
- breadcrumbs.length > 0 && (
71
- <Breadcrumb
72
- items={breadcrumbs}
73
- onNavigate={onBreadcrumbNavigate}
74
- />
75
- )
76
- )}
77
- </div>
78
-
79
- {/* 自定义内容插槽 */}
80
- {children && <div className="file-toolbar-custom">{children}</div>}
81
-
82
- {/* 操作区 */}
83
- <div className="file-toolbar-actions">
84
- {/* 搜索框 */}
85
- {showSearch && (
86
- <div className="file-toolbar-search">
87
- <Icon icon="lucide:search" width={16} height={16} className="file-toolbar-search-icon" />
88
- <input
89
- type="text"
90
- value={searchQuery}
91
- onChange={(e) => onSearchQueryChange?.(e.target.value)}
92
- placeholder="搜索"
93
- className="file-toolbar-search-input"
94
- />
95
- </div>
96
- )}
97
-
98
- {/* 视图切换 */}
99
- {showViewToggle && (
100
- <div className="file-toolbar-view-toggle">
101
- <button
102
- onClick={() => onViewModeChange?.('grid')}
103
- className={`file-toolbar-button ${
104
- viewMode === 'grid' ? 'file-toolbar-button--active' : ''
105
- }`}
106
- title="网格视图"
107
- >
108
- <Icon icon="lucide:layout-grid" width={18} height={18} />
109
- </button>
110
- <button
111
- onClick={() => onViewModeChange?.('list')}
112
- className={`file-toolbar-button ${
113
- viewMode === 'list' ? 'file-toolbar-button--active' : ''
114
- }`}
115
- title="列表视图"
116
- >
117
- <Icon icon="lucide:list" width={18} height={18} />
118
- </button>
119
- </div>
120
- )}
121
-
122
- {/* 额外操作插槽 */}
123
- {actionsSlot}
124
- </div>
125
- </div>
126
- );
127
- }