listpage-next 0.0.246 → 0.0.248
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/features/ChatClient/components/ChatContent/ClientContentHeader.js +3 -24
- package/dist/ui/Button/index.d.ts +1 -1
- package/dist/ui/Button/index.js +3 -1
- package/dist/ui/FileManager/FileManager.d.ts +7 -0
- package/dist/ui/FileManager/FileManager.js +278 -0
- package/dist/ui/FileManager/components/AddAssetModal.d.ts +11 -0
- package/dist/ui/FileManager/components/AddAssetModal.js +197 -0
- package/dist/ui/FileManager/components/AssetGrid.d.ts +11 -0
- package/dist/ui/FileManager/components/AssetGrid.js +188 -0
- package/dist/ui/FileManager/components/AssetSelectorModal.d.ts +12 -0
- package/dist/ui/FileManager/components/AssetSelectorModal.js +133 -0
- package/dist/ui/FileManager/components/Breadcrumbs.d.ts +10 -0
- package/dist/ui/FileManager/components/Breadcrumbs.js +25 -0
- package/dist/ui/FileManager/components/CreateFolderModal.d.ts +7 -0
- package/dist/ui/FileManager/components/CreateFolderModal.js +84 -0
- package/dist/ui/FileManager/components/DeleteConfirmModal.d.ts +9 -0
- package/dist/ui/FileManager/components/DeleteConfirmModal.js +33 -0
- package/dist/ui/FileManager/components/FileTypePreview.d.ts +7 -0
- package/dist/ui/FileManager/components/FileTypePreview.js +29 -0
- package/dist/ui/FileManager/components/FolderTree.d.ts +13 -0
- package/dist/ui/FileManager/components/FolderTree.js +137 -0
- package/dist/ui/FileManager/components/HeaderBar.d.ts +13 -0
- package/dist/ui/FileManager/components/HeaderBar.js +37 -0
- package/dist/ui/FileManager/components/InspectorPanel.d.ts +9 -0
- package/dist/ui/FileManager/components/InspectorPanel.js +119 -0
- package/dist/ui/FileManager/components/SearchInput.d.ts +7 -0
- package/dist/ui/FileManager/components/SearchInput.js +19 -0
- package/dist/ui/FileManager/components/Sidebar.d.ts +12 -0
- package/dist/ui/FileManager/components/Sidebar.js +79 -0
- package/dist/ui/FileManager/components/ViewModeToggle.d.ts +8 -0
- package/dist/ui/FileManager/components/ViewModeToggle.js +23 -0
- package/dist/ui/FileManager/index.d.ts +3 -0
- package/dist/ui/FileManager/index.js +3 -0
- package/dist/ui/FileManager/services/config.d.ts +8 -0
- package/dist/ui/FileManager/services/config.js +18 -0
- package/dist/ui/FileManager/services/storageService.d.ts +14 -0
- package/dist/ui/FileManager/services/storageService.js +249 -0
- package/dist/ui/FileManager/types.d.ts +36 -0
- package/dist/ui/FileManager/types.js +0 -0
- package/dist/ui/Modal/ConfirmModal.d.ts +11 -0
- package/dist/ui/Modal/ConfirmModal.js +62 -0
- package/dist/ui/Modal/Modal.d.ts +14 -0
- package/dist/ui/Modal/Modal.js +64 -0
- package/dist/ui/Modal/index.d.ts +2 -0
- package/dist/ui/Modal/index.js +3 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +2 -1
- package/dist/ui.css +755 -0
- package/package.json +4 -2
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import react from "react";
|
|
3
|
+
import dayjs from "dayjs";
|
|
4
|
+
import { Box, Check, ExternalLink, FileText, Folder, Image, Link, Music, Trash2, Video } from "lucide-react";
|
|
5
|
+
const AssetGrid = ({ items, viewMode, onSelect, onNavigate, onDelete, selectedIds })=>{
|
|
6
|
+
const [copiedId, setCopiedId] = react.useState(null);
|
|
7
|
+
const handleCopyLink = async (url, id)=>{
|
|
8
|
+
if (!url) return;
|
|
9
|
+
try {
|
|
10
|
+
await navigator.clipboard.writeText(url);
|
|
11
|
+
setCopiedId(id);
|
|
12
|
+
setTimeout(()=>setCopiedId(null), 2000);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.error('Failed to copy', err);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const sortedItems = [
|
|
18
|
+
...items
|
|
19
|
+
].sort((a, b)=>{
|
|
20
|
+
if ('folder' === a.type && 'folder' !== b.type) return -1;
|
|
21
|
+
if ('folder' !== a.type && 'folder' === b.type) return 1;
|
|
22
|
+
return a.name.localeCompare(b.name);
|
|
23
|
+
});
|
|
24
|
+
if (0 === sortedItems.length) return /*#__PURE__*/ jsxs("div", {
|
|
25
|
+
className: "flex flex-col items-center justify-center h-full text-slate-500",
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ jsx("div", {
|
|
28
|
+
className: "w-16 h-16 border-2 border-slate-800 border-dashed rounded-xl flex items-center justify-center mb-4",
|
|
29
|
+
children: /*#__PURE__*/ jsx(Folder, {
|
|
30
|
+
className: "w-8 h-8 opacity-50"
|
|
31
|
+
})
|
|
32
|
+
}),
|
|
33
|
+
/*#__PURE__*/ jsx("p", {
|
|
34
|
+
className: "text-lg font-medium",
|
|
35
|
+
children: "此文件夹为空"
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ jsx("p", {
|
|
38
|
+
className: "text-sm",
|
|
39
|
+
children: "拖拽文件到此处或新建"
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
const FileTypeIcon = ({ type, className })=>{
|
|
44
|
+
const cls = className || 'w-8 h-8';
|
|
45
|
+
switch(type){
|
|
46
|
+
case 'folder':
|
|
47
|
+
return /*#__PURE__*/ jsx(Folder, {
|
|
48
|
+
className: `${cls} text-indigo-400 fill-indigo-400/20`
|
|
49
|
+
});
|
|
50
|
+
case 'image':
|
|
51
|
+
return /*#__PURE__*/ jsx(Image, {
|
|
52
|
+
className: `${cls} text-blue-400`
|
|
53
|
+
});
|
|
54
|
+
case 'video':
|
|
55
|
+
return /*#__PURE__*/ jsx(Video, {
|
|
56
|
+
className: `${cls} text-red-400`
|
|
57
|
+
});
|
|
58
|
+
case 'audio':
|
|
59
|
+
return /*#__PURE__*/ jsx(Music, {
|
|
60
|
+
className: `${cls} text-yellow-400`
|
|
61
|
+
});
|
|
62
|
+
case 'model':
|
|
63
|
+
return /*#__PURE__*/ jsx(Box, {
|
|
64
|
+
className: `${cls} text-emerald-400`
|
|
65
|
+
});
|
|
66
|
+
default:
|
|
67
|
+
return /*#__PURE__*/ jsx(FileText, {
|
|
68
|
+
className: `${cls} text-slate-400`
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return /*#__PURE__*/ jsx("div", {
|
|
73
|
+
className: "p-6 overflow-y-auto h-full scrollbar-thin",
|
|
74
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
75
|
+
className: `${'grid' === viewMode ? 'flex flex-wrap gap-4 content-start' : 'flex flex-col gap-2'}`,
|
|
76
|
+
children: sortedItems.map((item)=>{
|
|
77
|
+
const isSelected = selectedIds ? selectedIds.has(item.id) : false;
|
|
78
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
79
|
+
className: `group relative bg-slate-900 border rounded-xl overflow-hidden transition-all duration-200 cursor-pointer ${isSelected ? 'border-indigo-500 bg-indigo-500/10 ring-1 ring-indigo-500' : 'border-slate-800 hover:border-indigo-500/50 hover:bg-slate-800/50'} ${'list' === viewMode ? 'flex items-center px-4 py-3 h-16 w-full' : 'flex flex-col p-4 w-44 h-56 items-center justify-center gap-4 shrink-0'}`,
|
|
80
|
+
onClick: ()=>{
|
|
81
|
+
onSelect(item);
|
|
82
|
+
},
|
|
83
|
+
onDoubleClick: (e)=>{
|
|
84
|
+
e.stopPropagation();
|
|
85
|
+
if ('folder' === item.type) onNavigate(item.id);
|
|
86
|
+
},
|
|
87
|
+
children: [
|
|
88
|
+
selectedIds && 'folder' !== item.type && /*#__PURE__*/ jsx("div", {
|
|
89
|
+
className: `absolute top-2 left-2 w-5 h-5 rounded border flex items-center justify-center z-10 ${isSelected ? 'bg-indigo-600 border-indigo-600' : 'bg-slate-900/80 border-slate-600 opacity-0 group-hover:opacity-100'}`,
|
|
90
|
+
children: isSelected && /*#__PURE__*/ jsx(Check, {
|
|
91
|
+
className: "w-3 h-3 text-white"
|
|
92
|
+
})
|
|
93
|
+
}),
|
|
94
|
+
/*#__PURE__*/ jsx("div", {
|
|
95
|
+
className: `${'list' === viewMode ? 'mr-4' : 'flex-1 flex items-center justify-center w-full min-h-0'}`,
|
|
96
|
+
children: 'folder' === item.type ? /*#__PURE__*/ jsx(Folder, {
|
|
97
|
+
className: `${'list' === viewMode ? 'w-8 h-8' : 'w-20 h-20'} text-indigo-400 fill-indigo-400/20 transition-transform group-hover:scale-105`
|
|
98
|
+
}) : 'image' === item.type && item.url ? /*#__PURE__*/ jsx("div", {
|
|
99
|
+
className: `${'list' === viewMode ? 'w-10 h-10' : 'w-full h-full'} rounded-lg overflow-hidden bg-slate-950 relative border border-slate-800 flex items-center justify-center`,
|
|
100
|
+
children: /*#__PURE__*/ jsx("img", {
|
|
101
|
+
src: item.url,
|
|
102
|
+
alt: item.name,
|
|
103
|
+
className: "w-full h-full object-cover"
|
|
104
|
+
})
|
|
105
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
106
|
+
className: `${'list' === viewMode ? 'w-10 h-10' : 'w-24 h-24'} flex items-center justify-center rounded-lg bg-slate-800/30`,
|
|
107
|
+
children: /*#__PURE__*/ jsx(FileTypeIcon, {
|
|
108
|
+
type: item.type,
|
|
109
|
+
className: 'list' === viewMode ? 'w-5 h-5' : 'w-12 h-12'
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
}),
|
|
113
|
+
/*#__PURE__*/ jsxs("div", {
|
|
114
|
+
className: `${'list' === viewMode ? 'flex-1 grid grid-cols-12 gap-4 items-center' : 'w-full text-center mt-2'}`,
|
|
115
|
+
children: [
|
|
116
|
+
/*#__PURE__*/ jsx("div", {
|
|
117
|
+
className: `${'list' === viewMode ? 'col-span-6' : ''} min-w-0`,
|
|
118
|
+
children: /*#__PURE__*/ jsx("h3", {
|
|
119
|
+
className: `text-sm font-medium truncate transition-colors select-none ${isSelected ? 'text-indigo-300' : 'text-slate-200 group-hover:text-indigo-300'}`,
|
|
120
|
+
title: item.name,
|
|
121
|
+
children: item.name
|
|
122
|
+
})
|
|
123
|
+
}),
|
|
124
|
+
'list' === viewMode && /*#__PURE__*/ jsxs(Fragment, {
|
|
125
|
+
children: [
|
|
126
|
+
/*#__PURE__*/ jsx("div", {
|
|
127
|
+
className: "col-span-3 text-xs text-slate-500",
|
|
128
|
+
children: dayjs(item.createdAt).format('YYYY-MM-DD')
|
|
129
|
+
}),
|
|
130
|
+
/*#__PURE__*/ jsx("div", {
|
|
131
|
+
className: "col-span-2 text-xs text-slate-500",
|
|
132
|
+
children: item.size || '--'
|
|
133
|
+
})
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
]
|
|
137
|
+
}),
|
|
138
|
+
onDelete && /*#__PURE__*/ jsxs("div", {
|
|
139
|
+
className: `absolute ${'list' === viewMode ? 'right-4 top-1/2 -translate-y-1/2' : 'top-2 right-2'} opacity-0 group-hover:opacity-100 transition-opacity flex gap-2 bg-slate-900/80 rounded-lg p-1`,
|
|
140
|
+
children: [
|
|
141
|
+
'folder' !== item.type && item.url && /*#__PURE__*/ jsxs(Fragment, {
|
|
142
|
+
children: [
|
|
143
|
+
/*#__PURE__*/ jsx("button", {
|
|
144
|
+
onClick: (e)=>{
|
|
145
|
+
e.stopPropagation();
|
|
146
|
+
handleCopyLink(item.url, item.id);
|
|
147
|
+
},
|
|
148
|
+
className: `p-1.5 rounded-lg hover:bg-slate-600 text-white ${copiedId === item.id ? 'bg-green-600' : 'bg-slate-700'}`,
|
|
149
|
+
title: "复制链接",
|
|
150
|
+
children: copiedId === item.id ? /*#__PURE__*/ jsx(Check, {
|
|
151
|
+
className: "w-3 h-3"
|
|
152
|
+
}) : /*#__PURE__*/ jsx(Link, {
|
|
153
|
+
className: "w-3 h-3"
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
/*#__PURE__*/ jsx("button", {
|
|
157
|
+
onClick: (e)=>{
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
window.open(item.url, '_blank');
|
|
160
|
+
},
|
|
161
|
+
className: "p-1.5 bg-slate-700 rounded-lg hover:bg-slate-600 text-white",
|
|
162
|
+
title: "打开",
|
|
163
|
+
children: /*#__PURE__*/ jsx(ExternalLink, {
|
|
164
|
+
className: "w-3 h-3"
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
}),
|
|
169
|
+
/*#__PURE__*/ jsx("button", {
|
|
170
|
+
onClick: (e)=>{
|
|
171
|
+
e.stopPropagation();
|
|
172
|
+
onDelete(item.id, 'folder' === item.type ? 'folder' : 'asset', item.name);
|
|
173
|
+
},
|
|
174
|
+
className: "p-1.5 bg-red-900/50 rounded-lg hover:bg-red-600 text-white",
|
|
175
|
+
title: "删除",
|
|
176
|
+
children: /*#__PURE__*/ jsx(Trash2, {
|
|
177
|
+
className: "w-3 h-3"
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
]
|
|
181
|
+
})
|
|
182
|
+
]
|
|
183
|
+
}, item.id);
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
export { AssetGrid };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Asset, Folder } from '../types';
|
|
3
|
+
export interface AssetSelectorModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
onSubmit: (selectedAssets: Asset[]) => void;
|
|
7
|
+
assets: Asset[];
|
|
8
|
+
folders: Folder[];
|
|
9
|
+
title?: string;
|
|
10
|
+
multiSelect?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const AssetSelectorModal: React.FC<AssetSelectorModalProps>;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { Check, Search } from "lucide-react";
|
|
4
|
+
import { AssetGrid } from "./AssetGrid.js";
|
|
5
|
+
import { FolderTree } from "./FolderTree.js";
|
|
6
|
+
import { Modal } from "../../Modal/index.js";
|
|
7
|
+
const AssetSelectorModal = ({ isOpen, onClose, onSubmit, assets, folders, title = '选择文件', multiSelect = true })=>{
|
|
8
|
+
const [currentFolderId, setCurrentFolderId] = useState(null);
|
|
9
|
+
const [selectedIds, setSelectedIds] = useState(new Set());
|
|
10
|
+
const [filters, setFilters] = useState({
|
|
11
|
+
search: '',
|
|
12
|
+
source: 'all'
|
|
13
|
+
});
|
|
14
|
+
const currentViewItems = useMemo(()=>{
|
|
15
|
+
const currentFolders = folders.filter((f)=>f.parentId === currentFolderId);
|
|
16
|
+
const currentAssets = assets.filter((a)=>a.parentId === currentFolderId);
|
|
17
|
+
let items = [
|
|
18
|
+
...currentFolders,
|
|
19
|
+
...currentAssets
|
|
20
|
+
];
|
|
21
|
+
if (filters.search) {
|
|
22
|
+
const allFolders = folders.filter((f)=>f.name.toLowerCase().includes(filters.search.toLowerCase()));
|
|
23
|
+
const allAssets = assets.filter((a)=>a.name.toLowerCase().includes(filters.search.toLowerCase()));
|
|
24
|
+
return [
|
|
25
|
+
...allFolders,
|
|
26
|
+
...allAssets
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
return items;
|
|
30
|
+
}, [
|
|
31
|
+
assets,
|
|
32
|
+
folders,
|
|
33
|
+
currentFolderId,
|
|
34
|
+
filters.search
|
|
35
|
+
]);
|
|
36
|
+
const handleSelect = (item)=>{
|
|
37
|
+
if ('folder' === item.type) return;
|
|
38
|
+
setSelectedIds((prev)=>{
|
|
39
|
+
const next = new Set(prev);
|
|
40
|
+
if (next.has(item.id)) next.delete(item.id);
|
|
41
|
+
else {
|
|
42
|
+
if (!multiSelect) next.clear();
|
|
43
|
+
next.add(item.id);
|
|
44
|
+
}
|
|
45
|
+
return next;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const handleSubmit = ()=>{
|
|
49
|
+
const selectedAssets = assets.filter((a)=>selectedIds.has(a.id));
|
|
50
|
+
onSubmit(selectedAssets);
|
|
51
|
+
onClose();
|
|
52
|
+
setSelectedIds(new Set());
|
|
53
|
+
};
|
|
54
|
+
return /*#__PURE__*/ jsx(Modal, {
|
|
55
|
+
open: isOpen,
|
|
56
|
+
onOk: handleSubmit,
|
|
57
|
+
onCancel: onClose,
|
|
58
|
+
className: "fixed inset-0 z-50",
|
|
59
|
+
title: /*#__PURE__*/ jsxs(Fragment, {
|
|
60
|
+
children: [
|
|
61
|
+
title,
|
|
62
|
+
selectedIds.size > 0 && /*#__PURE__*/ jsxs("span", {
|
|
63
|
+
className: "text-sm font-normal text-indigo-400 bg-indigo-500/10 px-2 py-0.5 rounded-full border border-indigo-500/20",
|
|
64
|
+
children: [
|
|
65
|
+
"已选 ",
|
|
66
|
+
selectedIds.size,
|
|
67
|
+
" 项"
|
|
68
|
+
]
|
|
69
|
+
})
|
|
70
|
+
]
|
|
71
|
+
}),
|
|
72
|
+
headerExtra: /*#__PURE__*/ jsxs("div", {
|
|
73
|
+
className: "relative",
|
|
74
|
+
children: [
|
|
75
|
+
/*#__PURE__*/ jsx(Search, {
|
|
76
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500"
|
|
77
|
+
}),
|
|
78
|
+
/*#__PURE__*/ jsx("input", {
|
|
79
|
+
type: "text",
|
|
80
|
+
placeholder: "搜索...",
|
|
81
|
+
value: filters.search,
|
|
82
|
+
onChange: (e)=>setFilters((prev)=>({
|
|
83
|
+
...prev,
|
|
84
|
+
search: e.target.value
|
|
85
|
+
})),
|
|
86
|
+
className: "w-48 bg-slate-950 border border-slate-700 rounded-lg pl-9 pr-3 py-1.5 text-sm text-slate-200 focus:ring-1 focus:ring-indigo-500 outline-none"
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
}),
|
|
90
|
+
okButtonProps: {
|
|
91
|
+
disabled: 0 === selectedIds.size,
|
|
92
|
+
children: /*#__PURE__*/ jsxs(Fragment, {
|
|
93
|
+
children: [
|
|
94
|
+
/*#__PURE__*/ jsx(Check, {
|
|
95
|
+
className: "w-4 h-4"
|
|
96
|
+
}),
|
|
97
|
+
"确认选择"
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
},
|
|
101
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
102
|
+
className: "flex px-1.5 py-1",
|
|
103
|
+
children: [
|
|
104
|
+
/*#__PURE__*/ jsxs("div", {
|
|
105
|
+
className: "w-[200px] shrink-0 grow-0",
|
|
106
|
+
children: [
|
|
107
|
+
/*#__PURE__*/ jsx("div", {
|
|
108
|
+
className: "flex items-center justify-between mb-2 px-3",
|
|
109
|
+
children: /*#__PURE__*/ jsx("h3", {
|
|
110
|
+
className: "text-xs font-semibold text-slate-500 uppercase tracking-wider",
|
|
111
|
+
children: "文件夹"
|
|
112
|
+
})
|
|
113
|
+
}),
|
|
114
|
+
/*#__PURE__*/ jsx(FolderTree, {
|
|
115
|
+
parentId: null,
|
|
116
|
+
folders: folders,
|
|
117
|
+
currentFolderId: currentFolderId,
|
|
118
|
+
onNavigate: setCurrentFolderId
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}),
|
|
122
|
+
/*#__PURE__*/ jsx(AssetGrid, {
|
|
123
|
+
items: currentViewItems,
|
|
124
|
+
viewMode: 'grid',
|
|
125
|
+
onSelect: handleSelect,
|
|
126
|
+
onNavigate: setCurrentFolderId,
|
|
127
|
+
selectedIds: selectedIds
|
|
128
|
+
})
|
|
129
|
+
]
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
export { AssetSelectorModal };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface BreadcrumbItem {
|
|
3
|
+
id: string | null;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BreadcrumbsProps {
|
|
7
|
+
items: BreadcrumbItem[];
|
|
8
|
+
onNavigate: (folderId: string | null) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const Breadcrumbs: React.FC<BreadcrumbsProps>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { ChevronRight, Home } from "lucide-react";
|
|
4
|
+
const Breadcrumbs = ({ items, onNavigate })=>/*#__PURE__*/ jsx("nav", {
|
|
5
|
+
className: "flex items-center text-sm font-medium text-slate-400",
|
|
6
|
+
children: items.map((crumb, index)=>/*#__PURE__*/ jsxs("div", {
|
|
7
|
+
className: "flex items-center",
|
|
8
|
+
children: [
|
|
9
|
+
index > 0 && /*#__PURE__*/ jsx(ChevronRight, {
|
|
10
|
+
className: "w-4 h-4 mx-2 text-slate-600"
|
|
11
|
+
}),
|
|
12
|
+
/*#__PURE__*/ jsxs("button", {
|
|
13
|
+
onClick: ()=>onNavigate(crumb.id),
|
|
14
|
+
className: `shrink-0 hover:text-white transition-colors flex items-center gap-2 ${index === items.length - 1 ? 'text-white' : ''}`,
|
|
15
|
+
children: [
|
|
16
|
+
0 === index && /*#__PURE__*/ jsx(Home, {
|
|
17
|
+
className: "w-4 h-4"
|
|
18
|
+
}),
|
|
19
|
+
crumb.name
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
]
|
|
23
|
+
}, crumb.id || 'root'))
|
|
24
|
+
});
|
|
25
|
+
export { Breadcrumbs };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { FolderPlus, X } from "lucide-react";
|
|
4
|
+
const CreateFolderModal = ({ isOpen, onClose, onCreate })=>{
|
|
5
|
+
const [folderName, setFolderName] = useState('新建文件夹');
|
|
6
|
+
if (!isOpen) return null;
|
|
7
|
+
const handleSubmit = (e)=>{
|
|
8
|
+
e.preventDefault();
|
|
9
|
+
if (folderName.trim()) {
|
|
10
|
+
onCreate(folderName.trim());
|
|
11
|
+
setFolderName('新建文件夹');
|
|
12
|
+
onClose();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
return /*#__PURE__*/ jsx("div", {
|
|
16
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm p-4",
|
|
17
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
18
|
+
className: "bg-slate-900 border border-slate-700 w-full max-w-md rounded-xl shadow-2xl p-6 transform transition-all scale-100",
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ jsxs("div", {
|
|
21
|
+
className: "flex items-center justify-between mb-6",
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ jsxs("h2", {
|
|
24
|
+
className: "text-xl font-bold text-white flex items-center gap-2",
|
|
25
|
+
children: [
|
|
26
|
+
/*#__PURE__*/ jsx(FolderPlus, {
|
|
27
|
+
className: "w-5 h-5 text-indigo-400"
|
|
28
|
+
}),
|
|
29
|
+
"新建文件夹"
|
|
30
|
+
]
|
|
31
|
+
}),
|
|
32
|
+
/*#__PURE__*/ jsx("button", {
|
|
33
|
+
onClick: onClose,
|
|
34
|
+
className: "text-slate-400 hover:text-white transition-colors",
|
|
35
|
+
children: /*#__PURE__*/ jsx(X, {
|
|
36
|
+
className: "w-5 h-5"
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
]
|
|
40
|
+
}),
|
|
41
|
+
/*#__PURE__*/ jsxs("form", {
|
|
42
|
+
onSubmit: handleSubmit,
|
|
43
|
+
children: [
|
|
44
|
+
/*#__PURE__*/ jsxs("div", {
|
|
45
|
+
className: "mb-6",
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ jsx("label", {
|
|
48
|
+
className: "block text-sm font-medium text-slate-400 mb-2",
|
|
49
|
+
children: "文件夹名称"
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ jsx("input", {
|
|
52
|
+
type: "text",
|
|
53
|
+
value: folderName,
|
|
54
|
+
onChange: (e)=>setFolderName(e.target.value),
|
|
55
|
+
className: "w-full bg-slate-950 border border-slate-700 rounded-lg px-4 py-2 text-white focus:ring-2 focus:ring-indigo-500/50 outline-none placeholder-slate-600",
|
|
56
|
+
placeholder: "例如:环境贴图",
|
|
57
|
+
autoFocus: true
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ jsxs("div", {
|
|
62
|
+
className: "flex justify-end gap-3",
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ jsx("button", {
|
|
65
|
+
type: "button",
|
|
66
|
+
onClick: onClose,
|
|
67
|
+
className: "px-4 py-2 text-slate-300 hover:text-white transition-colors text-sm font-medium",
|
|
68
|
+
children: "取消"
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ jsx("button", {
|
|
71
|
+
type: "submit",
|
|
72
|
+
disabled: !folderName.trim(),
|
|
73
|
+
className: "px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-lg shadow-indigo-500/20",
|
|
74
|
+
children: "创建"
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
})
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
]
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
export { CreateFolderModal };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface DeleteConfirmModalProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onConfirm: () => void;
|
|
6
|
+
itemName: string;
|
|
7
|
+
itemType: 'folder' | 'asset' | null;
|
|
8
|
+
}
|
|
9
|
+
export declare const DeleteConfirmModal: React.FC<DeleteConfirmModalProps>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { ConfirmModal } from "../../Modal/ConfirmModal.js";
|
|
4
|
+
const DeleteConfirmModal = ({ isOpen, onClose, onConfirm, itemName, itemType })=>/*#__PURE__*/ jsx(ConfirmModal, {
|
|
5
|
+
title: `${'folder' === itemType ? '删除文件夹' : '删除文件'}?`,
|
|
6
|
+
onOk: onConfirm,
|
|
7
|
+
onCancel: onClose,
|
|
8
|
+
open: isOpen,
|
|
9
|
+
className: "fixed inset-0 z-50",
|
|
10
|
+
children: /*#__PURE__*/ jsxs(Fragment, {
|
|
11
|
+
children: [
|
|
12
|
+
"确认要删除",
|
|
13
|
+
/*#__PURE__*/ jsxs("span", {
|
|
14
|
+
className: "font-semibold text-white",
|
|
15
|
+
children: [
|
|
16
|
+
'"',
|
|
17
|
+
itemName,
|
|
18
|
+
'"'
|
|
19
|
+
]
|
|
20
|
+
}),
|
|
21
|
+
" 吗?",
|
|
22
|
+
'folder' === itemType && /*#__PURE__*/ jsx("span", {
|
|
23
|
+
className: "block mt-2 text-red-400 text-xs",
|
|
24
|
+
children: "这将永久删除其中所有内容。"
|
|
25
|
+
}),
|
|
26
|
+
/*#__PURE__*/ jsx("span", {
|
|
27
|
+
className: "block mt-2",
|
|
28
|
+
children: "此操作无法撤销。"
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
export { DeleteConfirmModal };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Box, FileText, Image, Music, Video } from "lucide-react";
|
|
4
|
+
const FileTypePreview_FileTypePreview = ({ asset })=>{
|
|
5
|
+
if ('image' === asset.type && asset.url) return /*#__PURE__*/ jsx("img", {
|
|
6
|
+
src: asset.url,
|
|
7
|
+
className: "w-full h-full object-contain",
|
|
8
|
+
alt: "Preview"
|
|
9
|
+
});
|
|
10
|
+
let Icon = FileText;
|
|
11
|
+
if ('video' === asset.type) Icon = Video;
|
|
12
|
+
if ('audio' === asset.type) Icon = Music;
|
|
13
|
+
if ('model' === asset.type) Icon = Box;
|
|
14
|
+
if ('image' === asset.type) Icon = Image;
|
|
15
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
16
|
+
className: "w-full h-full flex flex-col items-center justify-center text-slate-500",
|
|
17
|
+
children: [
|
|
18
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
19
|
+
className: "w-20 h-20 mb-4"
|
|
20
|
+
}),
|
|
21
|
+
/*#__PURE__*/ jsx("span", {
|
|
22
|
+
className: "text-sm",
|
|
23
|
+
children: "暂无预览"
|
|
24
|
+
})
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
const FileTypePreview = FileTypePreview_FileTypePreview;
|
|
29
|
+
export { FileTypePreview as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Folder } from '../types';
|
|
2
|
+
export interface FolderTreeProps {
|
|
3
|
+
parentId: string | null;
|
|
4
|
+
depth?: number;
|
|
5
|
+
folders: Folder[];
|
|
6
|
+
expandedFolders?: Set<string>;
|
|
7
|
+
currentFolderId: string | null;
|
|
8
|
+
onNavigate: (folderId: string | null) => void;
|
|
9
|
+
onToggleExpand?: (folderId: string) => void;
|
|
10
|
+
onAddFolder?: (folder: Folder | null) => void;
|
|
11
|
+
showRoot?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const FolderTree: ({ parentId, depth, folders, expandedFolders: controlledExpandedFolders, currentFolderId, onNavigate, onToggleExpand: controlledOnToggleExpand, onAddFolder, showRoot, }: FolderTreeProps) => import("react/jsx-runtime").JSX.Element | null;
|