listpage-next 0.0.246 → 0.0.247

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 (49) hide show
  1. package/dist/features/ChatClient/components/ChatContent/ClientContentHeader.js +3 -24
  2. package/dist/ui/Button/index.d.ts +1 -1
  3. package/dist/ui/Button/index.js +3 -1
  4. package/dist/ui/FileManager/FileManager.d.ts +7 -0
  5. package/dist/ui/FileManager/FileManager.js +278 -0
  6. package/dist/ui/FileManager/components/AddAssetModal.d.ts +11 -0
  7. package/dist/ui/FileManager/components/AddAssetModal.js +197 -0
  8. package/dist/ui/FileManager/components/AssetGrid.d.ts +11 -0
  9. package/dist/ui/FileManager/components/AssetGrid.js +188 -0
  10. package/dist/ui/FileManager/components/AssetSelectorModal.d.ts +12 -0
  11. package/dist/ui/FileManager/components/AssetSelectorModal.js +133 -0
  12. package/dist/ui/FileManager/components/Breadcrumbs.d.ts +10 -0
  13. package/dist/ui/FileManager/components/Breadcrumbs.js +25 -0
  14. package/dist/ui/FileManager/components/CreateFolderModal.d.ts +7 -0
  15. package/dist/ui/FileManager/components/CreateFolderModal.js +84 -0
  16. package/dist/ui/FileManager/components/DeleteConfirmModal.d.ts +9 -0
  17. package/dist/ui/FileManager/components/DeleteConfirmModal.js +33 -0
  18. package/dist/ui/FileManager/components/FileTypePreview.d.ts +7 -0
  19. package/dist/ui/FileManager/components/FileTypePreview.js +29 -0
  20. package/dist/ui/FileManager/components/FolderTree.d.ts +13 -0
  21. package/dist/ui/FileManager/components/FolderTree.js +137 -0
  22. package/dist/ui/FileManager/components/HeaderBar.d.ts +13 -0
  23. package/dist/ui/FileManager/components/HeaderBar.js +37 -0
  24. package/dist/ui/FileManager/components/InspectorPanel.d.ts +9 -0
  25. package/dist/ui/FileManager/components/InspectorPanel.js +119 -0
  26. package/dist/ui/FileManager/components/SearchInput.d.ts +7 -0
  27. package/dist/ui/FileManager/components/SearchInput.js +19 -0
  28. package/dist/ui/FileManager/components/Sidebar.d.ts +12 -0
  29. package/dist/ui/FileManager/components/Sidebar.js +79 -0
  30. package/dist/ui/FileManager/components/ViewModeToggle.d.ts +8 -0
  31. package/dist/ui/FileManager/components/ViewModeToggle.js +23 -0
  32. package/dist/ui/FileManager/index.d.ts +3 -0
  33. package/dist/ui/FileManager/index.js +3 -0
  34. package/dist/ui/FileManager/services/config.d.ts +8 -0
  35. package/dist/ui/FileManager/services/config.js +18 -0
  36. package/dist/ui/FileManager/services/storageService.d.ts +14 -0
  37. package/dist/ui/FileManager/services/storageService.js +249 -0
  38. package/dist/ui/FileManager/types.d.ts +36 -0
  39. package/dist/ui/FileManager/types.js +0 -0
  40. package/dist/ui/Modal/ConfirmModal.d.ts +11 -0
  41. package/dist/ui/Modal/ConfirmModal.js +62 -0
  42. package/dist/ui/Modal/Modal.d.ts +14 -0
  43. package/dist/ui/Modal/Modal.js +64 -0
  44. package/dist/ui/Modal/index.d.ts +2 -0
  45. package/dist/ui/Modal/index.js +3 -0
  46. package/dist/ui/index.d.ts +1 -0
  47. package/dist/ui/index.js +2 -1
  48. package/dist/ui.css +755 -0
  49. package/package.json +4 -2
@@ -0,0 +1,249 @@
1
+ import { DeleteObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
2
+ import { getStorageConfig } from "./config.js";
3
+ const getS3Client = ()=>{
4
+ const cfg = getStorageConfig();
5
+ return new S3Client({
6
+ region: cfg.region || 'us-east-1',
7
+ endpoint: cfg.endpoint,
8
+ credentials: {
9
+ accessKeyId: cfg.accessKeyId,
10
+ secretAccessKey: cfg.secretAccessKey
11
+ },
12
+ forcePathStyle: true
13
+ });
14
+ };
15
+ const listAssets = async ()=>{
16
+ try {
17
+ const cfg = getStorageConfig();
18
+ const s3 = getS3Client();
19
+ const command = new ListObjectsV2Command({
20
+ Bucket: cfg.bucketName
21
+ });
22
+ const response = await s3.send(command);
23
+ const assets = [];
24
+ const foldersMap = new Map();
25
+ const getParentPath = (path)=>{
26
+ const cleanPath = path.endsWith('/') ? path.slice(0, -1) : path;
27
+ const parts = cleanPath.split('/');
28
+ if (parts.length <= 1) return null;
29
+ parts.pop();
30
+ return parts.join('/') + '/';
31
+ };
32
+ const ensureFolderExists = (path, date)=>{
33
+ if (!path || foldersMap.has(path)) return;
34
+ const parentId = getParentPath(path);
35
+ if (parentId) ensureFolderExists(parentId, date);
36
+ const cleanPath = path.slice(0, -1);
37
+ const name = cleanPath.split('/').pop() || 'Unknown';
38
+ foldersMap.set(path, {
39
+ id: path,
40
+ name: name,
41
+ parentId: parentId,
42
+ createdAt: date.toISOString(),
43
+ type: 'folder'
44
+ });
45
+ };
46
+ (response.Contents || []).forEach((item)=>{
47
+ const key = item.Key || '';
48
+ const date = item.LastModified || new Date();
49
+ if (key.endsWith('/')) return void ensureFolderExists(key, date);
50
+ const parts = key.split('/');
51
+ let parentId = null;
52
+ if (parts.length > 1) {
53
+ parts.pop();
54
+ parentId = parts.join('/') + '/';
55
+ ensureFolderExists(parentId, date);
56
+ }
57
+ const ext = key.split('.').pop()?.toLowerCase();
58
+ let type = 'file';
59
+ if ([
60
+ 'png',
61
+ 'jpg',
62
+ 'jpeg',
63
+ 'gif',
64
+ 'webp',
65
+ 'svg'
66
+ ].includes(ext || '')) type = 'image';
67
+ else if ([
68
+ 'mp4',
69
+ 'webm',
70
+ 'mov',
71
+ 'avi'
72
+ ].includes(ext || '')) type = 'video';
73
+ else if ([
74
+ 'mp3',
75
+ 'wav',
76
+ 'ogg'
77
+ ].includes(ext || '')) type = 'audio';
78
+ else if ([
79
+ 'obj',
80
+ 'fbx',
81
+ 'glb',
82
+ 'gltf'
83
+ ].includes(ext || '')) type = 'model';
84
+ const url = `${cfg.endpoint}/${cfg.bucketName}/${key}`;
85
+ const name = key.split('/').pop() || key;
86
+ assets.push({
87
+ id: key,
88
+ name: name,
89
+ url: url,
90
+ type: type,
91
+ width: 0,
92
+ height: 0,
93
+ size: formatBytes(item.Size || 0),
94
+ createdAt: date.toISOString(),
95
+ source: 'upload',
96
+ parentId: parentId
97
+ });
98
+ });
99
+ return {
100
+ assets,
101
+ folders: Array.from(foldersMap.values())
102
+ };
103
+ } catch (error) {
104
+ console.error('List assets failed', error);
105
+ return {
106
+ assets: [],
107
+ folders: []
108
+ };
109
+ }
110
+ };
111
+ const createFolder = async (folderName, parentPath)=>{
112
+ const prefix = parentPath ? parentPath : '';
113
+ const key = `${prefix}${folderName}/`;
114
+ try {
115
+ const cfg = getStorageConfig();
116
+ const s3 = getS3Client();
117
+ const command = new PutObjectCommand({
118
+ Bucket: cfg.bucketName,
119
+ Key: key,
120
+ Body: new Uint8Array(0)
121
+ });
122
+ await s3.send(command);
123
+ return {
124
+ id: key,
125
+ name: folderName,
126
+ parentId: parentPath,
127
+ createdAt: new Date().toISOString(),
128
+ type: 'folder'
129
+ };
130
+ } catch (error) {
131
+ console.error('Create folder failed', error);
132
+ throw error;
133
+ }
134
+ };
135
+ const deleteFolder = async (folderPath)=>{
136
+ try {
137
+ const cfg = getStorageConfig();
138
+ const s3 = getS3Client();
139
+ let continuationToken;
140
+ do {
141
+ const listResp = await s3.send(new ListObjectsV2Command({
142
+ Bucket: cfg.bucketName,
143
+ Prefix: folderPath,
144
+ ContinuationToken: continuationToken
145
+ }));
146
+ const contents = listResp.Contents || [];
147
+ for (const item of contents){
148
+ const key = item.Key;
149
+ if (key) await s3.send(new DeleteObjectCommand({
150
+ Bucket: cfg.bucketName,
151
+ Key: key
152
+ }));
153
+ }
154
+ continuationToken = listResp.IsTruncated ? listResp.NextContinuationToken : void 0;
155
+ }while (continuationToken);
156
+ } catch (error) {
157
+ console.error('Recursive delete failed', error);
158
+ throw error;
159
+ }
160
+ };
161
+ const uploadObject = async (file, folderId)=>{
162
+ const prefix = folderId || '';
163
+ const cleanName = file.name.replace(/[^a-zA-Z0-9.-]/g, '_');
164
+ const key = `${prefix}${Date.now()}-${cleanName}`;
165
+ try {
166
+ const cfg = getStorageConfig();
167
+ const s3 = getS3Client();
168
+ const buffer = await file.arrayBuffer();
169
+ const body = new Uint8Array(buffer);
170
+ const command = new PutObjectCommand({
171
+ Bucket: cfg.bucketName,
172
+ Key: key,
173
+ Body: body,
174
+ ContentType: file.type
175
+ });
176
+ await s3.send(command);
177
+ const publicUrl = `${cfg.endpoint}/${cfg.bucketName}/${key}`;
178
+ let type = 'file';
179
+ if (file.type.startsWith('image/')) type = 'image';
180
+ else if (file.type.startsWith('video/')) type = 'video';
181
+ else if (file.type.startsWith('audio/')) type = 'audio';
182
+ else if (file.name.endsWith('.obj') || file.name.endsWith('.fbx') || file.name.endsWith('.glb')) type = 'model';
183
+ let width, height;
184
+ if ('image' === type) try {
185
+ const dimensions = await getImageDimensions(publicUrl);
186
+ width = dimensions.width;
187
+ height = dimensions.height;
188
+ } catch (e) {}
189
+ return {
190
+ id: key,
191
+ name: key.split('/').pop(),
192
+ url: publicUrl,
193
+ type,
194
+ width,
195
+ height,
196
+ size: formatBytes(file.size),
197
+ createdAt: new Date().toISOString(),
198
+ source: 'upload',
199
+ parentId: folderId
200
+ };
201
+ } catch (error) {
202
+ console.error('Upload failed', error);
203
+ throw new Error('Failed to upload to storage');
204
+ }
205
+ };
206
+ const deleteObject = async (assetId)=>{
207
+ try {
208
+ const cfg = getStorageConfig();
209
+ const s3 = getS3Client();
210
+ const command = new DeleteObjectCommand({
211
+ Bucket: cfg.bucketName,
212
+ Key: assetId
213
+ });
214
+ await s3.send(command);
215
+ } catch (error) {
216
+ console.error('Delete failed', error);
217
+ }
218
+ };
219
+ const getImageDimensions = (url)=>new Promise((resolve, reject)=>{
220
+ const img = new Image();
221
+ img.onload = ()=>resolve({
222
+ width: img.width,
223
+ height: img.height
224
+ });
225
+ img.onerror = reject;
226
+ img.src = url;
227
+ });
228
+ const formatBytes = (bytes, decimals = 2)=>{
229
+ if (!+bytes) return '0 Bytes';
230
+ const k = 1024;
231
+ const dm = decimals < 0 ? 0 : decimals;
232
+ const sizes = [
233
+ 'Bytes',
234
+ 'KB',
235
+ 'MB',
236
+ 'GB',
237
+ 'TB'
238
+ ];
239
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
240
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
241
+ };
242
+ const adapter = {
243
+ createFolder,
244
+ deleteFolder,
245
+ uploadObject,
246
+ deleteObject,
247
+ listAssets
248
+ };
249
+ export { adapter, createFolder, deleteFolder, deleteObject, listAssets, uploadObject };
@@ -0,0 +1,36 @@
1
+ export interface Folder {
2
+ id: string;
3
+ name: string;
4
+ parentId: string | null;
5
+ createdAt: string;
6
+ type: 'folder';
7
+ }
8
+ export type AssetType = 'image' | 'video' | 'audio' | 'model' | 'file';
9
+ export interface Asset {
10
+ id: string;
11
+ name: string;
12
+ url: string;
13
+ type: AssetType;
14
+ parentId: string | null;
15
+ width?: number;
16
+ height?: number;
17
+ size?: string;
18
+ createdAt: string;
19
+ source: 'upload' | 'ai-generated';
20
+ }
21
+ export type FileSystemItem = Folder | Asset;
22
+ export type ViewMode = 'grid' | 'list';
23
+ export interface FilterState {
24
+ search: string;
25
+ source: 'all' | 'upload' | 'ai-generated';
26
+ }
27
+ export interface StorageAdapter {
28
+ listAssets: () => Promise<{
29
+ assets: Asset[];
30
+ folders: Folder[];
31
+ }>;
32
+ createFolder: (name: string, parentPath: string | null) => Promise<Folder>;
33
+ deleteFolder: (folderPath: string) => Promise<void>;
34
+ deleteObject: (assetId: string) => Promise<void>;
35
+ uploadObject: (file: File, folderId: string | null) => Promise<Partial<Asset>>;
36
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ConfirmModalProps {
3
+ open?: boolean;
4
+ onOk?: () => void;
5
+ onCancel?: () => void;
6
+ type?: 'error';
7
+ title?: ReactNode;
8
+ children?: ReactNode;
9
+ className?: string;
10
+ }
11
+ export declare const ConfirmModal: (props: ConfirmModalProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,62 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { AlertTriangle, X } from "lucide-react";
3
+ import { Button } from "../Button/index.js";
4
+ const ConfirmModal = (props)=>{
5
+ const { title, onCancel, onOk, children, open, type, className = '' } = props;
6
+ if (!open) return /*#__PURE__*/ jsx(Fragment, {});
7
+ return /*#__PURE__*/ jsx("div", {
8
+ className: `flex items-center justify-center bg-black/80 backdrop-blur-sm p-4 ${className}`,
9
+ children: /*#__PURE__*/ jsxs("div", {
10
+ className: "bg-slate-900 border border-slate-700 w-full max-w-sm rounded-xl shadow-2xl p-6 transform transition-all scale-100",
11
+ children: [
12
+ /*#__PURE__*/ jsxs("div", {
13
+ className: "flex items-center justify-between mb-4",
14
+ children: [
15
+ /*#__PURE__*/ jsxs("div", {
16
+ className: "flex items-center gap-1",
17
+ children: [
18
+ /*#__PURE__*/ jsx("div", {
19
+ className: "rounded-full bg-red-900/30 flex items-center justify-center",
20
+ children: /*#__PURE__*/ jsx(AlertTriangle, {
21
+ className: "w-5 h-5 text-red-500"
22
+ })
23
+ }),
24
+ /*#__PURE__*/ jsx("h2", {
25
+ className: "text-lg font-bold text-white mb-0",
26
+ children: title
27
+ })
28
+ ]
29
+ }),
30
+ /*#__PURE__*/ jsx("button", {
31
+ onClick: onCancel,
32
+ className: "text-slate-400 hover:text-white transition-colors",
33
+ children: /*#__PURE__*/ jsx(X, {
34
+ className: "w-5 h-5"
35
+ })
36
+ })
37
+ ]
38
+ }),
39
+ /*#__PURE__*/ jsx("p", {
40
+ className: "text-slate-400 text-sm mb-6",
41
+ children: children
42
+ }),
43
+ /*#__PURE__*/ jsxs("div", {
44
+ className: "flex justify-end gap-3",
45
+ children: [
46
+ /*#__PURE__*/ jsx(Button, {
47
+ onClick: onCancel,
48
+ type: "text",
49
+ children: "取消"
50
+ }),
51
+ /*#__PURE__*/ jsx(Button, {
52
+ type: "error",
53
+ onClick: onOk,
54
+ children: "删除"
55
+ })
56
+ ]
57
+ })
58
+ ]
59
+ })
60
+ });
61
+ };
62
+ export { ConfirmModal };
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+ import { ButtonProps } from '../Button';
3
+ export interface ModalProps {
4
+ open?: boolean;
5
+ onCancel?: () => void;
6
+ onOk?: () => void;
7
+ title?: ReactNode;
8
+ children?: ReactNode;
9
+ headerExtra?: ReactNode;
10
+ okButtonProps?: ButtonProps;
11
+ cancelButtonProps?: ButtonProps;
12
+ className?: string;
13
+ }
14
+ export declare const Modal: (props: ModalProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,64 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { X } from "lucide-react";
3
+ import { Button } from "../Button/index.js";
4
+ const Modal = (props)=>{
5
+ const { open, onCancel, onOk, title, children, headerExtra, okButtonProps, cancelButtonProps, className = '' } = props;
6
+ if (!open) return /*#__PURE__*/ jsx(Fragment, {});
7
+ return /*#__PURE__*/ jsx("div", {
8
+ className: `fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm p-4 ${className}`,
9
+ children: /*#__PURE__*/ jsxs("div", {
10
+ className: "bg-slate-950 border border-slate-700 w-full max-w-5xl h-[85vh] rounded-2xl shadow-2xl flex flex-col overflow-hidden",
11
+ children: [
12
+ /*#__PURE__*/ jsxs("div", {
13
+ className: "flex items-center justify-between px-6 py-4 border-b border-slate-800 bg-slate-900",
14
+ children: [
15
+ /*#__PURE__*/ jsx("h2", {
16
+ className: "text-xl font-bold text-white flex items-center gap-2",
17
+ children: title
18
+ }),
19
+ /*#__PURE__*/ jsxs("div", {
20
+ className: "flex items-center gap-4",
21
+ children: [
22
+ /*#__PURE__*/ jsx("div", {
23
+ className: "relative",
24
+ children: headerExtra
25
+ }),
26
+ /*#__PURE__*/ jsx("button", {
27
+ onClick: onCancel,
28
+ className: "text-slate-400 hover:text-white transition-colors",
29
+ children: /*#__PURE__*/ jsx(X, {
30
+ className: "w-6 h-6"
31
+ })
32
+ })
33
+ ]
34
+ })
35
+ ]
36
+ }),
37
+ /*#__PURE__*/ jsx("div", {
38
+ className: "flex-1 flex overflow-hidden",
39
+ children: /*#__PURE__*/ jsx("div", {
40
+ className: "flex-1 bg-slate-950 relative",
41
+ children: children
42
+ })
43
+ }),
44
+ /*#__PURE__*/ jsxs("div", {
45
+ className: "p-4 border-t border-slate-800 bg-slate-900 flex justify-end gap-3",
46
+ children: [
47
+ /*#__PURE__*/ jsx(Button, {
48
+ onClick: onCancel,
49
+ type: "text",
50
+ ...cancelButtonProps,
51
+ children: "取消"
52
+ }),
53
+ /*#__PURE__*/ jsx(Button, {
54
+ onClick: onOk,
55
+ ...okButtonProps,
56
+ children: "确认"
57
+ })
58
+ ]
59
+ })
60
+ ]
61
+ })
62
+ });
63
+ };
64
+ export { Modal };
@@ -0,0 +1,2 @@
1
+ export { ConfirmModal, type ConfirmModalProps } from './ConfirmModal';
2
+ export { Modal, type ModalProps } from './Modal';
@@ -0,0 +1,3 @@
1
+ import { ConfirmModal } from "./ConfirmModal.js";
2
+ import { Modal } from "./Modal.js";
3
+ export { ConfirmModal, Modal };
@@ -4,3 +4,4 @@ export { LogPreview, type LogPreviewProps, type LogEntry } from './LogPreview';
4
4
  export { StatusTag, type StatusTagProps } from './StatusTag';
5
5
  export { Tabs, type TabsProps } from './Tabs';
6
6
  export { Menu, type MenuProps } from './Menu';
7
+ export { FileManager, AssetSelectorModal } from './FileManager';
package/dist/ui/index.js CHANGED
@@ -4,4 +4,5 @@ import { LogPreview } from "./LogPreview/index.js";
4
4
  import { StatusTag } from "./StatusTag/index.js";
5
5
  import { Tabs } from "./Tabs/index.js";
6
6
  import { Menu } from "./Menu/index.js";
7
- export { Button, LogPreview, Menu, PromptEditor, StatusTag, Tabs };
7
+ import { AssetSelectorModal, FileManager } from "./FileManager/index.js";
8
+ export { AssetSelectorModal, Button, FileManager, LogPreview, Menu, PromptEditor, StatusTag, Tabs };