@powerhousedao/codegen 5.0.0-staging.19 → 5.0.0-staging.20
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/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/CreateDocument.esm.t +13 -15
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/DriveExplorer.esm.t +53 -126
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/FolderTree.esm.t +92 -81
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/editor.esm.t +2 -44
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/index.esm.t +1 -3
- package/dist/tsconfig.hygen.tsbuildinfo +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/EditorContainer.esm.t +0 -103
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/types/css.d.esm.t +0 -8
- package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/utils/withDropZone.esm.t +0 -51
|
@@ -4,11 +4,10 @@ unless_exists: true
|
|
|
4
4
|
---
|
|
5
5
|
import { Button } from "@powerhousedao/design-system";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
isDocumentTypeSupported,
|
|
8
|
+
showPHModal,
|
|
8
9
|
useDocumentModelModules,
|
|
9
10
|
useSelectedDriveId,
|
|
10
|
-
useSelectedFolder,
|
|
11
|
-
isDocumentTypeSupported,
|
|
12
11
|
type VetraDocumentModelModule,
|
|
13
12
|
} from "@powerhousedao/reactor-browser";
|
|
14
13
|
|
|
@@ -24,34 +23,33 @@ export const CreateDocument = (props: CreateDocumentProps) => {
|
|
|
24
23
|
const { documentTypes = [] } = props;
|
|
25
24
|
|
|
26
25
|
const selectedDriveId = useSelectedDriveId();
|
|
27
|
-
const selectedFolder = useSelectedFolder();
|
|
28
26
|
const documentModelModules = useDocumentModelModules();
|
|
29
27
|
|
|
30
|
-
const filteredDocumentModelModules = documentModelModules
|
|
28
|
+
const filteredDocumentModelModules = documentModelModules.filter((module) =>
|
|
31
29
|
isDocumentTypeSupported(module.documentModel.id, documentTypes),
|
|
32
30
|
);
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
function handleAddDocument(module: VetraDocumentModelModule) {
|
|
35
33
|
if (!selectedDriveId) {
|
|
36
34
|
return;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
36
|
+
|
|
37
|
+
// Display the Create Document modal on the host app
|
|
38
|
+
showPHModal({
|
|
39
|
+
type: "createDocument",
|
|
40
|
+
documentType: module.documentModel.id,
|
|
41
|
+
});
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
return (
|
|
47
|
-
<div
|
|
45
|
+
<div>
|
|
48
46
|
{/* Customize section title here */}
|
|
49
47
|
<h3 className="mb-3 mt-4 text-sm font-bold text-gray-600">
|
|
50
|
-
|
|
48
|
+
Create document
|
|
51
49
|
</h3>
|
|
52
50
|
{/* Customize layout by changing flex-wrap, gap, or grid layout */}
|
|
53
51
|
<div className="flex w-full flex-wrap gap-4">
|
|
54
|
-
{filteredDocumentModelModules
|
|
52
|
+
{filteredDocumentModelModules.map((documentModelModule) => {
|
|
55
53
|
return (
|
|
56
54
|
<Button
|
|
57
55
|
key={documentModelModule.documentModel.id}
|
|
@@ -4,32 +4,28 @@ unless_exists: true
|
|
|
4
4
|
---
|
|
5
5
|
import {
|
|
6
6
|
Breadcrumbs,
|
|
7
|
-
|
|
7
|
+
Button,
|
|
8
8
|
FileItem,
|
|
9
9
|
FolderItem,
|
|
10
10
|
useBreadcrumbs,
|
|
11
11
|
} from "@powerhousedao/design-system";
|
|
12
12
|
import {
|
|
13
|
-
addDocument,
|
|
14
13
|
type DriveEditorProps,
|
|
15
14
|
getSyncStatusSync,
|
|
16
15
|
setSelectedNode,
|
|
17
|
-
|
|
18
|
-
useDocumentModelModules,
|
|
19
|
-
useDriveContext,
|
|
16
|
+
showDeleteNodeModal,
|
|
20
17
|
useDriveSharingType,
|
|
21
|
-
useEditorModules,
|
|
22
18
|
useFileChildNodesForId,
|
|
23
19
|
useFolderChildNodesForId,
|
|
24
|
-
|
|
20
|
+
useNodeActions,
|
|
21
|
+
useNodes,
|
|
22
|
+
useSelectedDriveDocument,
|
|
25
23
|
useSelectedFolder,
|
|
26
24
|
useSelectedNodePath,
|
|
27
25
|
useUserPermissions,
|
|
28
26
|
} from "@powerhousedao/reactor-browser";
|
|
29
|
-
import
|
|
30
|
-
import { useCallback, useRef, useState } from "react";
|
|
27
|
+
import { useCallback } from "react";
|
|
31
28
|
import { CreateDocument } from "./CreateDocument.js";
|
|
32
|
-
import { EditorContainer } from "./EditorContainer.js";
|
|
33
29
|
import { FolderTree } from "./FolderTree.js";
|
|
34
30
|
|
|
35
31
|
/**
|
|
@@ -37,14 +33,8 @@ import { FolderTree } from "./FolderTree.js";
|
|
|
37
33
|
* Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
|
|
38
34
|
*/
|
|
39
35
|
export function DriveExplorer(props: DriveEditorProps) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const [activeDocumentId, setActiveDocumentId] = useState<
|
|
43
|
-
string | undefined
|
|
44
|
-
>();
|
|
45
|
-
const [openModal, setOpenModal] = useState(false);
|
|
46
|
-
const selectedDocumentModel = useRef<DocumentModelModule | null>(null);
|
|
47
|
-
const editorModules = useEditorModules();
|
|
36
|
+
const { children, editorConfig } = props;
|
|
37
|
+
|
|
48
38
|
// === DRIVE CONTEXT HOOKS ===
|
|
49
39
|
// Core drive operations and document models
|
|
50
40
|
const {
|
|
@@ -54,16 +44,15 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
54
44
|
onDuplicateNode,
|
|
55
45
|
onMoveNode,
|
|
56
46
|
onRenameNode,
|
|
57
|
-
|
|
58
|
-
} = useDriveContext();
|
|
47
|
+
} = useNodeActions();
|
|
59
48
|
|
|
60
49
|
const { isAllowedToCreateDocuments } = useUserPermissions();
|
|
61
50
|
// === STATE MANAGEMENT HOOKS ===
|
|
62
51
|
// Core state hooks for drive navigation
|
|
63
|
-
const [selectedDrive] =
|
|
52
|
+
const [selectedDrive] = useSelectedDriveDocument(); // Currently selected drive
|
|
64
53
|
const selectedFolder = useSelectedFolder(); // Currently selected folder
|
|
65
54
|
const selectedNodePath = useSelectedNodePath();
|
|
66
|
-
const sharingType = useDriveSharingType(selectedDrive
|
|
55
|
+
const sharingType = useDriveSharingType(selectedDrive.header.id);
|
|
67
56
|
|
|
68
57
|
// === NAVIGATION SETUP ===
|
|
69
58
|
// Breadcrumbs for folder navigation
|
|
@@ -72,13 +61,13 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
72
61
|
setSelectedNode,
|
|
73
62
|
});
|
|
74
63
|
|
|
75
|
-
const selectedNodeId = selectedFolder?.id ||
|
|
64
|
+
const selectedNodeId = selectedFolder?.id || selectedDrive.header.id;
|
|
76
65
|
|
|
77
66
|
const folderChildren = useFolderChildNodesForId(selectedNodeId);
|
|
78
67
|
const fileChildren = useFileChildNodesForId(selectedNodeId);
|
|
79
68
|
|
|
80
|
-
// All folders for the sidebar tree view
|
|
81
|
-
const
|
|
69
|
+
// All nodes (folders and files) for the sidebar tree view
|
|
70
|
+
const allNodes = useNodes() || [];
|
|
82
71
|
|
|
83
72
|
// === EVENT HANDLERS ===
|
|
84
73
|
|
|
@@ -104,82 +93,31 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
104
93
|
[onAddFolder, selectedFolder],
|
|
105
94
|
);
|
|
106
95
|
|
|
107
|
-
//
|
|
108
|
-
const
|
|
109
|
-
async (fileName: string) => {
|
|
110
|
-
setOpenModal(false);
|
|
111
|
-
|
|
112
|
-
const documentModel = selectedDocumentModel.current;
|
|
113
|
-
if (!documentModel || !selectedDrive?.header.id) return;
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const node = await addDocument(
|
|
117
|
-
selectedDrive.header.id,
|
|
118
|
-
fileName,
|
|
119
|
-
documentModel.documentModel.id,
|
|
120
|
-
selectedFolder?.id,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
selectedDocumentModel.current = null;
|
|
124
|
-
|
|
125
|
-
if (node) {
|
|
126
|
-
// Customize: Auto-open created document by uncommenting below
|
|
127
|
-
// setActiveDocumentId(node.id);
|
|
128
|
-
}
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.error("Failed to create document:", error);
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
[addDocument, editorModules, selectedDrive?.header.id, selectedFolder?.id],
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// === DOCUMENT EDITOR DATA ===
|
|
137
|
-
// Filter available document types here if needed
|
|
138
|
-
const documentModelModules = useDocumentModelModules();
|
|
139
|
-
|
|
140
|
-
// Get active document and its editor components
|
|
141
|
-
const activeDocument = activeDocumentId
|
|
142
|
-
? fileChildren.find((file) => file.id === activeDocumentId)
|
|
143
|
-
: undefined;
|
|
144
|
-
|
|
145
|
-
const documentModelModule = activeDocument
|
|
146
|
-
? documentModelModules?.find(
|
|
147
|
-
(m) => m.documentModel.id === activeDocument.documentType,
|
|
148
|
-
)
|
|
149
|
-
: null;
|
|
150
|
-
|
|
151
|
-
const editorModule = activeDocument
|
|
152
|
-
? editorModules?.find((e) =>
|
|
153
|
-
e.documentTypes.includes(activeDocument.documentType),
|
|
154
|
-
)
|
|
155
|
-
: null;
|
|
96
|
+
// if a document is selected then it's editor will be passed as children
|
|
97
|
+
const showDocumentEditor = !!children;
|
|
156
98
|
|
|
157
99
|
// === RENDER ===
|
|
158
100
|
return (
|
|
159
101
|
<div className="flex h-full">
|
|
160
|
-
{/* === LEFT SIDEBAR: Folder Navigation === */}
|
|
161
|
-
{/*
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
{/* Folder tree navigation component */}
|
|
170
|
-
<FolderTree folders={allFolders} onSelectNode={setSelectedNode} />
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
102
|
+
{/* === LEFT SIDEBAR: Folder and File Navigation === */}
|
|
103
|
+
{/* Sidebar component manages its own width, styling, and overflow */}
|
|
104
|
+
<FolderTree
|
|
105
|
+
driveId={selectedDrive.header.id}
|
|
106
|
+
driveName={selectedDrive.state.global.name}
|
|
107
|
+
nodes={allNodes}
|
|
108
|
+
selectedNodeId={selectedNodeId}
|
|
109
|
+
onSelectNode={setSelectedNode}
|
|
110
|
+
/>
|
|
173
111
|
|
|
174
112
|
{/* === RIGHT CONTENT AREA: Files/Folders or Document Editor === */}
|
|
175
113
|
<div className="flex-1 overflow-y-auto p-4">
|
|
176
114
|
{/* Conditional rendering: Document editor or folder contents */}
|
|
177
|
-
{
|
|
115
|
+
{showDocumentEditor ? (
|
|
178
116
|
// Document editor view
|
|
179
|
-
|
|
117
|
+
children
|
|
180
118
|
) : (
|
|
181
119
|
/* Folder contents view */
|
|
182
|
-
<div className="space-y-6">
|
|
120
|
+
<div className="space-y-6 px-6">
|
|
183
121
|
{/* === HEADER SECTION === */}
|
|
184
122
|
<div className="space-y-3">
|
|
185
123
|
<div className="flex items-center justify-between">
|
|
@@ -191,36 +129,30 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
191
129
|
</h2>
|
|
192
130
|
{/* Customize: Add more action buttons here */}
|
|
193
131
|
{isAllowedToCreateDocuments && (
|
|
194
|
-
<
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
>
|
|
198
|
-
+ New Folder
|
|
199
|
-
</button>
|
|
132
|
+
<Button onClick={() => handleCreateFolder()}>
|
|
133
|
+
New Folder
|
|
134
|
+
</Button>
|
|
200
135
|
)}
|
|
201
136
|
</div>
|
|
202
137
|
|
|
203
138
|
{/* Navigation breadcrumbs */}
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
</div>
|
|
213
|
-
)}
|
|
139
|
+
<div className="border-b border-gray-200 pb-3">
|
|
140
|
+
<Breadcrumbs
|
|
141
|
+
breadcrumbs={breadcrumbs}
|
|
142
|
+
createEnabled={isAllowedToCreateDocuments}
|
|
143
|
+
onCreate={handleCreateFolder}
|
|
144
|
+
onBreadcrumbSelected={onBreadcrumbSelected}
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
214
147
|
</div>
|
|
215
148
|
|
|
216
149
|
{/* === FOLDERS SECTION === */}
|
|
217
|
-
{/* Customize grid layout by changing grid-cols-1 */}
|
|
218
150
|
{folderChildren.length > 0 && (
|
|
219
151
|
<div>
|
|
220
|
-
<h3 className="mb-2 text-sm font-
|
|
221
|
-
|
|
152
|
+
<h3 className="mb-2 text-sm font-bold text-gray-600">
|
|
153
|
+
Folders
|
|
222
154
|
</h3>
|
|
223
|
-
<div className="
|
|
155
|
+
<div className="flex flex-wrap gap-4">
|
|
224
156
|
{folderChildren.map((folderNode) => (
|
|
225
157
|
<FolderItem
|
|
226
158
|
key={folderNode.id}
|
|
@@ -236,7 +168,9 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
236
168
|
onDuplicateNode={onDuplicateNode}
|
|
237
169
|
onAddFolder={onAddFolder}
|
|
238
170
|
onAddAndSelectNewFolder={handleCreateFolder}
|
|
239
|
-
showDeleteNodeModal={
|
|
171
|
+
showDeleteNodeModal={(node) =>
|
|
172
|
+
showDeleteNodeModal(node.id)
|
|
173
|
+
}
|
|
240
174
|
/>
|
|
241
175
|
))}
|
|
242
176
|
</div>
|
|
@@ -244,13 +178,12 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
244
178
|
)}
|
|
245
179
|
|
|
246
180
|
{/* === FILES/DOCUMENTS SECTION === */}
|
|
247
|
-
{/* Customize grid layout by changing grid-cols-1 */}
|
|
248
181
|
{fileChildren.length > 0 && (
|
|
249
182
|
<div>
|
|
250
|
-
<h3 className="mb-2 text-sm font-
|
|
251
|
-
|
|
183
|
+
<h3 className="mb-2 text-sm font-semibold text-gray-600">
|
|
184
|
+
Documents
|
|
252
185
|
</h3>
|
|
253
|
-
<div className="
|
|
186
|
+
<div className="flex flex-wrap gap-4">
|
|
254
187
|
{fileChildren.map((fileNode) => (
|
|
255
188
|
<FileItem
|
|
256
189
|
key={fileNode.id}
|
|
@@ -259,7 +192,9 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
259
192
|
sharingType={sharingType || "LOCAL"}
|
|
260
193
|
getSyncStatusSync={getSyncStatusSync}
|
|
261
194
|
setSelectedNode={setSelectedNode}
|
|
262
|
-
showDeleteNodeModal={
|
|
195
|
+
showDeleteNodeModal={(node) =>
|
|
196
|
+
showDeleteNodeModal(node.id)
|
|
197
|
+
}
|
|
263
198
|
onRenameNode={onRenameNode}
|
|
264
199
|
onDuplicateNode={onDuplicateNode}
|
|
265
200
|
onAddFile={onAddFile}
|
|
@@ -277,7 +212,7 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
277
212
|
{/* Customize empty state message and styling here */}
|
|
278
213
|
{folderChildren.length === 0 && fileChildren.length === 0 && (
|
|
279
214
|
<div className="py-12 text-center text-gray-500">
|
|
280
|
-
<p className="text-lg"
|
|
215
|
+
<p className="text-lg">This folder is empty</p>
|
|
281
216
|
<p className="mt-2 text-sm">
|
|
282
217
|
Create your first document or folder below
|
|
283
218
|
</p>
|
|
@@ -286,18 +221,10 @@ export function DriveExplorer(props: DriveEditorProps) {
|
|
|
286
221
|
|
|
287
222
|
{/* === DOCUMENT CREATION SECTION === */}
|
|
288
223
|
{/* Component for creating new documents */}
|
|
289
|
-
<CreateDocument documentTypes={
|
|
224
|
+
<CreateDocument documentTypes={editorConfig?.documentTypes} />
|
|
290
225
|
</div>
|
|
291
226
|
)}
|
|
292
227
|
</div>
|
|
293
|
-
|
|
294
|
-
{/* === DOCUMENT CREATION MODAL === */}
|
|
295
|
-
{/* Modal for entering document name after selecting type */}
|
|
296
|
-
<CreateDocumentModal
|
|
297
|
-
onContinue={onCreateDocument}
|
|
298
|
-
onOpenChange={(open) => setOpenModal(open)}
|
|
299
|
-
open={openModal}
|
|
300
|
-
/>
|
|
301
228
|
</div>
|
|
302
229
|
);
|
|
303
230
|
}
|
|
@@ -2,102 +2,113 @@
|
|
|
2
2
|
to: "<%= rootDir %>/<%= h.changeCase.param(name) %>/components/FolderTree.tsx"
|
|
3
3
|
unless_exists: true
|
|
4
4
|
---
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
Sidebar,
|
|
7
|
+
SidebarProvider,
|
|
8
|
+
type SidebarNode,
|
|
9
|
+
} from "@powerhousedao/document-engineering";
|
|
10
|
+
import type { Node } from "document-drive";
|
|
11
|
+
import { useMemo } from "react";
|
|
7
12
|
|
|
8
13
|
interface FolderTreeProps {
|
|
9
|
-
|
|
14
|
+
driveId: string;
|
|
15
|
+
driveName: string;
|
|
16
|
+
nodes: Node[];
|
|
10
17
|
selectedNodeId?: string;
|
|
11
18
|
onSelectNode: (nodeId: string | undefined) => void;
|
|
12
19
|
}
|
|
13
20
|
|
|
21
|
+
function isFolder(node: Node): boolean {
|
|
22
|
+
return node.kind === "folder";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildSidebarNodes(
|
|
26
|
+
nodes: Node[],
|
|
27
|
+
parentId: string | null | undefined,
|
|
28
|
+
): SidebarNode[] {
|
|
29
|
+
return nodes
|
|
30
|
+
.filter((n) => {
|
|
31
|
+
if (parentId == null) {
|
|
32
|
+
return n.parentFolder == null;
|
|
33
|
+
}
|
|
34
|
+
return n.parentFolder === parentId;
|
|
35
|
+
})
|
|
36
|
+
.map((node): SidebarNode => {
|
|
37
|
+
if (isFolder(node)) {
|
|
38
|
+
return {
|
|
39
|
+
id: node.id,
|
|
40
|
+
title: node.name,
|
|
41
|
+
icon: "FolderClose" as const,
|
|
42
|
+
expandedIcon: "FolderOpen" as const,
|
|
43
|
+
children: buildSidebarNodes(nodes, node.id),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
id: node.id,
|
|
48
|
+
title: node.name,
|
|
49
|
+
icon: "File" as const,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function transformNodesToSidebarNodes(
|
|
55
|
+
nodes: Node[],
|
|
56
|
+
driveName: string,
|
|
57
|
+
): SidebarNode[] {
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
id: "root",
|
|
61
|
+
title: driveName,
|
|
62
|
+
icon: "Drive" as const,
|
|
63
|
+
children: buildSidebarNodes(nodes, null),
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
14
68
|
/**
|
|
15
|
-
* Hierarchical folder tree navigation component.
|
|
16
|
-
* Displays folders in a tree structure with expand/collapse functionality.
|
|
69
|
+
* Hierarchical folder tree navigation component using Sidebar from document-engineering.
|
|
70
|
+
* Displays folders and files in a tree structure with expand/collapse functionality, search, and resize support.
|
|
17
71
|
*/
|
|
18
72
|
export function FolderTree({
|
|
19
|
-
|
|
73
|
+
driveId,
|
|
74
|
+
driveName,
|
|
75
|
+
nodes,
|
|
20
76
|
selectedNodeId,
|
|
21
77
|
onSelectNode,
|
|
22
78
|
}: FolderTreeProps) {
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
79
|
+
// Transform Node[] to hierarchical SidebarNode structure
|
|
80
|
+
const sidebarNodes = useMemo(
|
|
81
|
+
() => transformNodesToSidebarNodes(nodes, driveName),
|
|
82
|
+
[nodes, driveName],
|
|
26
83
|
);
|
|
27
84
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
next.add(folderId);
|
|
36
|
-
}
|
|
37
|
-
return next;
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Recursive function to render folder tree structure
|
|
42
|
-
const renderFolder = (folder: FolderNode, level = 0) => {
|
|
43
|
-
const hasChildren = folders.some((f) => f.parentFolder === folder.id);
|
|
44
|
-
const isExpanded = expandedFolders.has(folder.id);
|
|
45
|
-
const isSelected = selectedNodeId === folder.id;
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div key={folder.id}>
|
|
49
|
-
<div
|
|
50
|
-
className={`flex cursor-pointer items-center rounded px-2 py-1 text-sm hover:bg-gray-100 ${
|
|
51
|
-
isSelected ? "bg-blue-100 text-blue-800" : ""
|
|
52
|
-
}`}
|
|
53
|
-
style={{ paddingLeft: `${level * 16 + 8}px` }} // Customize indentation here
|
|
54
|
-
onClick={() => onSelectNode(folder.id)}
|
|
55
|
-
>
|
|
56
|
-
{/* Expand/collapse button for folders with children */}
|
|
57
|
-
{hasChildren && (
|
|
58
|
-
<button
|
|
59
|
-
className="mr-1 flex h-4 w-4 items-center justify-center"
|
|
60
|
-
onClick={(e) => {
|
|
61
|
-
e.stopPropagation();
|
|
62
|
-
toggleFolder(folder.id);
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
{isExpanded ? "▼" : "▶"} {/* Customize expand icons here */}
|
|
66
|
-
</button>
|
|
67
|
-
)}
|
|
68
|
-
{!hasChildren && <div className="mr-1 w-5" />}
|
|
69
|
-
{/* Customize folder icon and styling here */}
|
|
70
|
-
<span>📁 {folder.name}</span>
|
|
71
|
-
</div>
|
|
72
|
-
{/* Recursively render child folders when expanded */}
|
|
73
|
-
{isExpanded && hasChildren && (
|
|
74
|
-
<div>
|
|
75
|
-
{folders
|
|
76
|
-
.filter((f) => f.parentFolder === folder.id)
|
|
77
|
-
.map((child) => renderFolder(child, level + 1))}
|
|
78
|
-
</div>
|
|
79
|
-
)}
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
85
|
+
const handleActiveNodeChange = (node: SidebarNode) => {
|
|
86
|
+
// If root node is selected, pass undefined to match existing behavior
|
|
87
|
+
if (node.id === "root") {
|
|
88
|
+
onSelectNode(undefined);
|
|
89
|
+
} else {
|
|
90
|
+
onSelectNode(node.id);
|
|
91
|
+
}
|
|
82
92
|
};
|
|
93
|
+
// Map selectedNodeId to activeNodeId (use "root" when undefined)
|
|
94
|
+
const activeNodeId =
|
|
95
|
+
!selectedNodeId || selectedNodeId === driveId ? "root" : selectedNodeId;
|
|
83
96
|
|
|
84
97
|
return (
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.map((folder) => renderFolder(folder))}
|
|
101
|
-
</div>
|
|
98
|
+
<SidebarProvider nodes={sidebarNodes}>
|
|
99
|
+
<Sidebar
|
|
100
|
+
className="pt-1"
|
|
101
|
+
nodes={sidebarNodes}
|
|
102
|
+
activeNodeId={activeNodeId}
|
|
103
|
+
onActiveNodeChange={handleActiveNodeChange}
|
|
104
|
+
sidebarTitle="Drive Explorer"
|
|
105
|
+
showSearchBar={true}
|
|
106
|
+
resizable={true}
|
|
107
|
+
allowPinning={false}
|
|
108
|
+
showStatusFilter={false}
|
|
109
|
+
initialWidth={256}
|
|
110
|
+
defaultLevel={2}
|
|
111
|
+
/>
|
|
112
|
+
</SidebarProvider>
|
|
102
113
|
);
|
|
103
|
-
}
|
|
114
|
+
}
|
|
@@ -2,49 +2,7 @@
|
|
|
2
2
|
to: "<%= rootDir %>/<%= h.changeCase.param(name) %>/editor.tsx"
|
|
3
3
|
unless_exists: true
|
|
4
4
|
---
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
AnalyticsProvider,
|
|
8
|
-
DriveContextProvider,
|
|
9
|
-
useAppConfig,
|
|
10
|
-
type DriveEditorProps,
|
|
11
|
-
} from "@powerhousedao/reactor-browser";
|
|
5
|
+
import { withDropZone } from "@powerhousedao/design-system";
|
|
12
6
|
import { DriveExplorer } from "./components/DriveExplorer.js";
|
|
13
|
-
import { withDropZone } from "./utils/withDropZone.js";
|
|
14
7
|
|
|
15
|
-
|
|
16
|
-
* Base editor component that renders the drive explorer interface.
|
|
17
|
-
* Customize document opening behavior and drive-level actions here.
|
|
18
|
-
*/
|
|
19
|
-
export function BaseEditor(props: DriveEditorProps) {
|
|
20
|
-
const { context, document, editorConfig } = props;
|
|
21
|
-
return (
|
|
22
|
-
<div className="new-drive-explorer" style={{ height: "100%" }}>
|
|
23
|
-
<DriveExplorer
|
|
24
|
-
document={document}
|
|
25
|
-
context={context}
|
|
26
|
-
editorConfig={editorConfig}
|
|
27
|
-
/>
|
|
28
|
-
</div>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const BaseEditorWithDropZone = withDropZone(BaseEditor);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Main editor entry point with required providers.
|
|
36
|
-
*/
|
|
37
|
-
export default function Editor(props: DriveEditorProps) {
|
|
38
|
-
const appConfig = useAppConfig();
|
|
39
|
-
const analyticsDatabaseName = appConfig?.analyticsDatabaseName;
|
|
40
|
-
return (
|
|
41
|
-
// Required context providers for drive functionality
|
|
42
|
-
<DriveContextProvider value={props.context}>
|
|
43
|
-
<WagmiContext>
|
|
44
|
-
<AnalyticsProvider databaseName={analyticsDatabaseName}>
|
|
45
|
-
<BaseEditorWithDropZone {...props} />
|
|
46
|
-
</AnalyticsProvider>
|
|
47
|
-
</WagmiContext>
|
|
48
|
-
</DriveContextProvider>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
8
|
+
export const Editor = withDropZone(DriveExplorer);
|
|
@@ -3,7 +3,7 @@ to: "<%= rootDir %>/<%= h.changeCase.param(name) %>/index.ts"
|
|
|
3
3
|
force: true
|
|
4
4
|
---
|
|
5
5
|
import { type DriveEditorModule } from "@powerhousedao/reactor-browser";
|
|
6
|
-
import Editor from "./editor.js";
|
|
6
|
+
import { Editor } from "./editor.js";
|
|
7
7
|
|
|
8
8
|
export const module: DriveEditorModule = {
|
|
9
9
|
Component: Editor,
|
|
@@ -19,5 +19,3 @@ export const module: DriveEditorModule = {
|
|
|
19
19
|
},<%_ } _%>
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
|
-
|
|
23
|
-
export default module;
|