@saltcorn/builder 0.0.1-beta.1
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/.babelrc +3 -0
- package/CHANGELOG.md +8 -0
- package/dist/builder_bundle.js +80 -0
- package/package.json +47 -0
- package/src/components/Builder.js +477 -0
- package/src/components/Library.js +224 -0
- package/src/components/RenderNode.js +203 -0
- package/src/components/Toolbox.js +688 -0
- package/src/components/context.js +9 -0
- package/src/components/elements/Action.js +204 -0
- package/src/components/elements/Aggregation.js +179 -0
- package/src/components/elements/BoxModelEditor.js +398 -0
- package/src/components/elements/Card.js +152 -0
- package/src/components/elements/Column.js +63 -0
- package/src/components/elements/Columns.js +201 -0
- package/src/components/elements/Container.js +947 -0
- package/src/components/elements/DropDownFilter.js +154 -0
- package/src/components/elements/DropMenu.js +156 -0
- package/src/components/elements/Empty.js +30 -0
- package/src/components/elements/Field.js +239 -0
- package/src/components/elements/HTMLCode.js +61 -0
- package/src/components/elements/Image.js +320 -0
- package/src/components/elements/JoinField.js +206 -0
- package/src/components/elements/LineBreak.js +46 -0
- package/src/components/elements/Link.js +305 -0
- package/src/components/elements/SearchBar.js +141 -0
- package/src/components/elements/Tabs.js +347 -0
- package/src/components/elements/Text.js +330 -0
- package/src/components/elements/ToggleFilter.js +243 -0
- package/src/components/elements/View.js +189 -0
- package/src/components/elements/ViewLink.js +225 -0
- package/src/components/elements/boxmodel.html +253 -0
- package/src/components/elements/faicons.js +1643 -0
- package/src/components/elements/utils.js +1217 -0
- package/src/components/preview_context.js +9 -0
- package/src/components/storage.js +506 -0
- package/src/index.js +73 -0
- package/webpack.config.js +21 -0
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@saltcorn/builder",
|
|
3
|
+
"version": "0.0.1-beta.1",
|
|
4
|
+
"description": "Drag and drop view builder for Saltcorn, open-source no-code platform",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"homepage": "https://saltcorn.com",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "webpack --mode production",
|
|
9
|
+
"builddev": "webpack --mode none",
|
|
10
|
+
"test": "echo \"Error: no test specified\"",
|
|
11
|
+
"tsc": "echo \"Error: no TypeScript support yet\"",
|
|
12
|
+
"clean": "echo \"Error: no TypeScript support yet\""
|
|
13
|
+
},
|
|
14
|
+
"repository": "github:saltcorn/saltcorn",
|
|
15
|
+
"author": "Tom Nielsen",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@babel/core": "7.9.6",
|
|
19
|
+
"@babel/preset-env": "7.9.6",
|
|
20
|
+
"@babel/preset-react": "7.9.4",
|
|
21
|
+
"@craftjs/core": "0.1.0-beta.20",
|
|
22
|
+
"@craftjs/utils": "0.1.0-beta.20",
|
|
23
|
+
"saltcorn-craft-layers-noeye": "0.1.0-beta.22",
|
|
24
|
+
"@fonticonpicker/react-fonticonpicker": "1.2.0",
|
|
25
|
+
"@fortawesome/fontawesome-svg-core": "1.2.34",
|
|
26
|
+
"@fortawesome/free-regular-svg-icons": "5.15.2",
|
|
27
|
+
"@fortawesome/free-solid-svg-icons": "5.15.2",
|
|
28
|
+
"@fortawesome/react-fontawesome": "0.1.14",
|
|
29
|
+
"babel-loader": "8.1.0",
|
|
30
|
+
"ckeditor4-react": "1.4.2",
|
|
31
|
+
"classnames": "2.2.6",
|
|
32
|
+
"prop-types": "15.7.2",
|
|
33
|
+
"react": "16.13.1",
|
|
34
|
+
"react-bootstrap-icons": "1.5.0",
|
|
35
|
+
"react-contenteditable": "3.3.5",
|
|
36
|
+
"react-dom": "16.13.1",
|
|
37
|
+
"react-transition-group": "4.4.1",
|
|
38
|
+
"webpack": "4.43.0",
|
|
39
|
+
"webpack-cli": "3.3.11"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"styled-components": "4.4.1"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/Builder
|
|
4
|
+
* @subcategory components
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, {
|
|
8
|
+
useEffect,
|
|
9
|
+
useContext,
|
|
10
|
+
useState,
|
|
11
|
+
Fragment,
|
|
12
|
+
useRef,
|
|
13
|
+
} from "react";
|
|
14
|
+
import { Editor, Frame, Element, Selector, useEditor } from "@craftjs/core";
|
|
15
|
+
import { Text } from "./elements/Text";
|
|
16
|
+
import { Field } from "./elements/Field";
|
|
17
|
+
import { JoinField } from "./elements/JoinField";
|
|
18
|
+
import { Aggregation } from "./elements/Aggregation";
|
|
19
|
+
import { LineBreak } from "./elements/LineBreak";
|
|
20
|
+
import { ViewLink } from "./elements/ViewLink";
|
|
21
|
+
import { Columns } from "./elements/Columns";
|
|
22
|
+
import { SearchBar } from "./elements/SearchBar";
|
|
23
|
+
import { HTMLCode } from "./elements/HTMLCode";
|
|
24
|
+
import { Action } from "./elements/Action";
|
|
25
|
+
import { Image } from "./elements/Image";
|
|
26
|
+
import { Tabs } from "./elements/Tabs";
|
|
27
|
+
import { Empty } from "./elements/Empty";
|
|
28
|
+
import { DropDownFilter } from "./elements/DropDownFilter";
|
|
29
|
+
import { DropMenu } from "./elements/DropMenu";
|
|
30
|
+
import { ToggleFilter } from "./elements/ToggleFilter";
|
|
31
|
+
import optionsCtx from "./context";
|
|
32
|
+
import PreviewCtx from "./preview_context";
|
|
33
|
+
import {
|
|
34
|
+
ToolboxShow,
|
|
35
|
+
ToolboxEdit,
|
|
36
|
+
ToolboxPage,
|
|
37
|
+
ToolboxFilter,
|
|
38
|
+
} from "./Toolbox";
|
|
39
|
+
import { craftToSaltcorn, layoutToNodes } from "./storage";
|
|
40
|
+
import { Card } from "./elements/Card";
|
|
41
|
+
import { Link } from "./elements/Link";
|
|
42
|
+
import { View } from "./elements/View";
|
|
43
|
+
import { Container } from "./elements/Container";
|
|
44
|
+
import { Column } from "./elements/Column";
|
|
45
|
+
import { Layers } from "saltcorn-craft-layers-noeye";
|
|
46
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
47
|
+
import {
|
|
48
|
+
faCopy,
|
|
49
|
+
faUndo,
|
|
50
|
+
faRedo,
|
|
51
|
+
faTrashAlt,
|
|
52
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
53
|
+
import {
|
|
54
|
+
Accordion,
|
|
55
|
+
ErrorBoundary,
|
|
56
|
+
recursivelyCloneToElems,
|
|
57
|
+
} from "./elements/utils";
|
|
58
|
+
import { InitNewElement, Library } from "./Library";
|
|
59
|
+
import { RenderNode } from "./RenderNode";
|
|
60
|
+
const { Provider } = optionsCtx;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @returns {div}
|
|
65
|
+
* @category saltcorn-builder
|
|
66
|
+
* @subcategory components
|
|
67
|
+
* @namespace
|
|
68
|
+
*/
|
|
69
|
+
const SettingsPanel = () => {
|
|
70
|
+
const { actions, selected, query } = useEditor((state, query) => {
|
|
71
|
+
const currentNodeId = state.events.selected;
|
|
72
|
+
let selected;
|
|
73
|
+
|
|
74
|
+
if (currentNodeId) {
|
|
75
|
+
selected = {
|
|
76
|
+
id: currentNodeId,
|
|
77
|
+
name: state.nodes[currentNodeId].data.name,
|
|
78
|
+
parent: state.nodes[currentNodeId].data.parent,
|
|
79
|
+
displayName:
|
|
80
|
+
state.nodes[currentNodeId].data &&
|
|
81
|
+
state.nodes[currentNodeId].data.displayName,
|
|
82
|
+
settings:
|
|
83
|
+
state.nodes[currentNodeId].related &&
|
|
84
|
+
state.nodes[currentNodeId].related.settings,
|
|
85
|
+
isDeletable: query.node(currentNodeId).isDeletable(),
|
|
86
|
+
children:
|
|
87
|
+
state.nodes[currentNodeId].data &&
|
|
88
|
+
state.nodes[currentNodeId].data.nodes,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
selected,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/** */
|
|
98
|
+
const deleteThis = () => {
|
|
99
|
+
actions.delete(selected.id);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {number} offset
|
|
104
|
+
* @returns {NodeId}
|
|
105
|
+
*/
|
|
106
|
+
const otherSibling = (offset) => {
|
|
107
|
+
const siblings = query.node(selected.parent).childNodes();
|
|
108
|
+
const sibIx = siblings.findIndex((sib) => sib === selected.id);
|
|
109
|
+
return siblings[sibIx + offset];
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {object} event
|
|
114
|
+
*/
|
|
115
|
+
const handleUserKeyPress = (event) => {
|
|
116
|
+
const { keyCode, target } = event;
|
|
117
|
+
if (target.tagName.toLowerCase() === "body" && selected) {
|
|
118
|
+
//8 backsp, 46 del
|
|
119
|
+
if ((keyCode === 8 || keyCode === 46) && selected.id === "ROOT") {
|
|
120
|
+
deleteChildren();
|
|
121
|
+
}
|
|
122
|
+
if (keyCode === 8) {
|
|
123
|
+
//backspace
|
|
124
|
+
const prevSib = otherSibling(-1);
|
|
125
|
+
const parent = selected.parent;
|
|
126
|
+
deleteThis();
|
|
127
|
+
if (prevSib) actions.selectNode(prevSib);
|
|
128
|
+
else actions.selectNode(parent);
|
|
129
|
+
}
|
|
130
|
+
if (keyCode === 46) {
|
|
131
|
+
//del
|
|
132
|
+
const nextSib = otherSibling(1);
|
|
133
|
+
deleteThis();
|
|
134
|
+
if (nextSib) actions.selectNode(nextSib);
|
|
135
|
+
}
|
|
136
|
+
if (keyCode === 37 && selected.parent)
|
|
137
|
+
//left
|
|
138
|
+
actions.selectNode(selected.parent);
|
|
139
|
+
|
|
140
|
+
if (keyCode === 39) {
|
|
141
|
+
//right
|
|
142
|
+
if (selected.children && selected.children.length > 0) {
|
|
143
|
+
actions.selectNode(selected.children[0]);
|
|
144
|
+
} else if (selected.displayName === "Columns") {
|
|
145
|
+
const node = query.node(selected.id).get();
|
|
146
|
+
const child = node?.data?.linkedNodes?.Col0;
|
|
147
|
+
if (child) actions.selectNode(child);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (keyCode === 38 && selected.parent) {
|
|
151
|
+
//up
|
|
152
|
+
const prevSib = otherSibling(-1);
|
|
153
|
+
if (prevSib) actions.selectNode(prevSib);
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
}
|
|
156
|
+
if (keyCode === 40 && selected.parent) {
|
|
157
|
+
//down
|
|
158
|
+
const nextSib = otherSibling(1);
|
|
159
|
+
if (nextSib) actions.selectNode(nextSib);
|
|
160
|
+
event.preventDefault();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
window.addEventListener("keydown", handleUserKeyPress);
|
|
166
|
+
return () => {
|
|
167
|
+
window.removeEventListener("keydown", handleUserKeyPress);
|
|
168
|
+
};
|
|
169
|
+
}, [handleUserKeyPress]);
|
|
170
|
+
const hasChildren =
|
|
171
|
+
selected && selected.children && selected.children.length > 0;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @returns {void}
|
|
175
|
+
*/
|
|
176
|
+
const deleteChildren = () => {
|
|
177
|
+
selected.children.forEach((child) => {
|
|
178
|
+
actions.delete(child);
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @returns {void}
|
|
184
|
+
*/
|
|
185
|
+
const duplicate = () => {
|
|
186
|
+
const {
|
|
187
|
+
data: { parent },
|
|
188
|
+
} = query.node(selected.id).get();
|
|
189
|
+
const siblings = query.node(selected.parent).childNodes();
|
|
190
|
+
const sibIx = siblings.findIndex((sib) => sib === selected.id);
|
|
191
|
+
const elem = recursivelyCloneToElems(query)(selected.id);
|
|
192
|
+
//console.log(elem);
|
|
193
|
+
actions.addNodeTree(
|
|
194
|
+
query.parseReactElement(elem).toNodeTree(),
|
|
195
|
+
parent || "ROOT",
|
|
196
|
+
sibIx + 1
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
return (
|
|
200
|
+
<div className="settings-panel card mt-1">
|
|
201
|
+
<div className="card-header px-2 py-1">
|
|
202
|
+
{selected && selected.displayName ? (
|
|
203
|
+
<Fragment>
|
|
204
|
+
<b>{selected.displayName}</b> settings
|
|
205
|
+
</Fragment>
|
|
206
|
+
) : (
|
|
207
|
+
"Settings"
|
|
208
|
+
)}
|
|
209
|
+
</div>
|
|
210
|
+
<div className="card-body p-2">
|
|
211
|
+
{selected ? (
|
|
212
|
+
<Fragment>
|
|
213
|
+
{selected.isDeletable && (
|
|
214
|
+
<button className="btn btn-sm btn-danger" onClick={deleteThis}>
|
|
215
|
+
<FontAwesomeIcon icon={faTrashAlt} className="me-1" />
|
|
216
|
+
Delete
|
|
217
|
+
</button>
|
|
218
|
+
)}
|
|
219
|
+
{hasChildren && !selected.isDeletable ? (
|
|
220
|
+
<button
|
|
221
|
+
className="btn btn-sm btn-danger"
|
|
222
|
+
onClick={deleteChildren}
|
|
223
|
+
>
|
|
224
|
+
<FontAwesomeIcon icon={faTrashAlt} className="me-1" />
|
|
225
|
+
Delete contents
|
|
226
|
+
</button>
|
|
227
|
+
) : (
|
|
228
|
+
<button
|
|
229
|
+
title="Duplicate element with its children"
|
|
230
|
+
className="btn btn-sm btn-secondary ms-2"
|
|
231
|
+
onClick={duplicate}
|
|
232
|
+
>
|
|
233
|
+
<FontAwesomeIcon icon={faCopy} className="me-1" />
|
|
234
|
+
Clone
|
|
235
|
+
</button>
|
|
236
|
+
)}
|
|
237
|
+
<hr className="my-2" />
|
|
238
|
+
{selected.settings && React.createElement(selected.settings)}
|
|
239
|
+
</Fragment>
|
|
240
|
+
) : (
|
|
241
|
+
"No element selected"
|
|
242
|
+
)}
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @returns {button}
|
|
250
|
+
* @category saltcorn-builder
|
|
251
|
+
* @subcategory components
|
|
252
|
+
* @namespace
|
|
253
|
+
*/
|
|
254
|
+
const SaveButton = () => {
|
|
255
|
+
const { query, actions } = useEditor(() => {});
|
|
256
|
+
const options = useContext(optionsCtx);
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @returns {void}
|
|
260
|
+
*/
|
|
261
|
+
const onClick = () => {
|
|
262
|
+
const data = craftToSaltcorn(JSON.parse(query.serialize()));
|
|
263
|
+
const urlroot = options.page_id ? "pageedit" : "viewedit";
|
|
264
|
+
fetch(`/${urlroot}/savebuilder/${options.page_id || options.view_id}`, {
|
|
265
|
+
method: "POST", // or 'PUT'
|
|
266
|
+
headers: {
|
|
267
|
+
"Content-Type": "application/json",
|
|
268
|
+
"CSRF-Token": options.csrfToken,
|
|
269
|
+
},
|
|
270
|
+
body: JSON.stringify(data),
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
return options.page_id || options.view_id ? (
|
|
274
|
+
<button
|
|
275
|
+
className="btn btn-sm btn-outline-secondary me-2 builder-save-ajax"
|
|
276
|
+
onClick={onClick}
|
|
277
|
+
>
|
|
278
|
+
Save
|
|
279
|
+
</button>
|
|
280
|
+
) : (
|
|
281
|
+
""
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @returns {a|""}
|
|
287
|
+
* @category saltcorn-builder
|
|
288
|
+
* @subcategory components
|
|
289
|
+
* @namespace
|
|
290
|
+
*/
|
|
291
|
+
const ViewPageLink = () => {
|
|
292
|
+
const { query, actions } = useEditor(() => {});
|
|
293
|
+
const options = useContext(optionsCtx);
|
|
294
|
+
return options.page_id ? (
|
|
295
|
+
<a target="_blank" className="d-block" href={`/page/${options.page_name}`}>
|
|
296
|
+
View page in new tab »
|
|
297
|
+
</a>
|
|
298
|
+
) : (
|
|
299
|
+
""
|
|
300
|
+
);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @returns {Fragment}
|
|
305
|
+
* @category saltcorn-builder
|
|
306
|
+
* @subcategory components
|
|
307
|
+
* @namespace
|
|
308
|
+
*/
|
|
309
|
+
const HistoryPanel = () => {
|
|
310
|
+
const { canUndo, canRedo, actions } = useEditor((state, query) => ({
|
|
311
|
+
canUndo: query.history.canUndo(),
|
|
312
|
+
canRedo: query.history.canRedo(),
|
|
313
|
+
}));
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
<Fragment>
|
|
317
|
+
{canUndo && (
|
|
318
|
+
<button
|
|
319
|
+
className="btn btn-sm btn-secondary ms-2 me-2"
|
|
320
|
+
title="Undo"
|
|
321
|
+
onClick={() => actions.history.undo()}
|
|
322
|
+
>
|
|
323
|
+
<FontAwesomeIcon icon={faUndo} />
|
|
324
|
+
</button>
|
|
325
|
+
)}
|
|
326
|
+
{canRedo && (
|
|
327
|
+
<button
|
|
328
|
+
className="btn btn-sm btn-secondary"
|
|
329
|
+
title="Redo"
|
|
330
|
+
onClick={() => actions.history.redo()}
|
|
331
|
+
>
|
|
332
|
+
<FontAwesomeIcon icon={faRedo} />
|
|
333
|
+
</button>
|
|
334
|
+
)}
|
|
335
|
+
</Fragment>
|
|
336
|
+
);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @param {object} opts
|
|
341
|
+
* @param {object} opts.layout
|
|
342
|
+
* @returns {button}
|
|
343
|
+
* @category saltcorn-builder
|
|
344
|
+
* @subcategory components
|
|
345
|
+
* @namespace
|
|
346
|
+
*/
|
|
347
|
+
const NextButton = ({ layout }) => {
|
|
348
|
+
const { query, actions } = useEditor(() => {});
|
|
349
|
+
const options = useContext(optionsCtx);
|
|
350
|
+
|
|
351
|
+
useEffect(() => {
|
|
352
|
+
layoutToNodes(layout, query, actions);
|
|
353
|
+
}, []);
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @returns {void}
|
|
357
|
+
*/
|
|
358
|
+
const onClick = () => {
|
|
359
|
+
const { columns, layout } = craftToSaltcorn(JSON.parse(query.serialize()));
|
|
360
|
+
document
|
|
361
|
+
.querySelector("form#scbuildform input[name=columns]")
|
|
362
|
+
.setAttribute("value", encodeURIComponent(JSON.stringify(columns)));
|
|
363
|
+
document
|
|
364
|
+
.querySelector("form#scbuildform input[name=layout]")
|
|
365
|
+
.setAttribute("value", encodeURIComponent(JSON.stringify(layout)));
|
|
366
|
+
document.getElementById("scbuildform").submit();
|
|
367
|
+
};
|
|
368
|
+
return (
|
|
369
|
+
<button className="btn btn-sm btn-primary builder-save" onClick={onClick}>
|
|
370
|
+
{options.next_button_label || "Next"} »
|
|
371
|
+
</button>
|
|
372
|
+
);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @param {object} props
|
|
377
|
+
* @param {object} props.options
|
|
378
|
+
* @param {object} props.layout
|
|
379
|
+
* @param {string} props.mode
|
|
380
|
+
* @returns {ErrorBoundary}
|
|
381
|
+
* @category saltcorn-builder
|
|
382
|
+
* @subcategory components
|
|
383
|
+
* @namespace
|
|
384
|
+
*/
|
|
385
|
+
const Builder = ({ options, layout, mode }) => {
|
|
386
|
+
const [showLayers, setShowLayers] = useState(true);
|
|
387
|
+
const [previews, setPreviews] = useState({});
|
|
388
|
+
const [uploadedFiles, setUploadedFiles] = useState([]);
|
|
389
|
+
const nodekeys = useRef([]);
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<ErrorBoundary>
|
|
393
|
+
<Editor onRender={RenderNode}>
|
|
394
|
+
<Provider value={options}>
|
|
395
|
+
<PreviewCtx.Provider
|
|
396
|
+
value={{ previews, setPreviews, uploadedFiles, setUploadedFiles }}
|
|
397
|
+
>
|
|
398
|
+
<div className="row" style={{ marginTop: "-5px" }}>
|
|
399
|
+
<div className="col-sm-auto left-builder-col">
|
|
400
|
+
<div className="componets-and-library-accordion toolbox-card">
|
|
401
|
+
<InitNewElement nodekeys={nodekeys} />
|
|
402
|
+
<Accordion>
|
|
403
|
+
<div className="card mt-1" accordiontitle="Components">
|
|
404
|
+
{{
|
|
405
|
+
show: <ToolboxShow />,
|
|
406
|
+
edit: <ToolboxEdit />,
|
|
407
|
+
page: <ToolboxPage />,
|
|
408
|
+
filter: <ToolboxFilter />,
|
|
409
|
+
}[mode] || <div>Missing mode</div>}
|
|
410
|
+
</div>
|
|
411
|
+
<div accordiontitle="Library">
|
|
412
|
+
<Library />
|
|
413
|
+
</div>
|
|
414
|
+
</Accordion>
|
|
415
|
+
</div>
|
|
416
|
+
<div className="card toolbox-card pe-0">
|
|
417
|
+
<div className="card-header">Layers</div>
|
|
418
|
+
{showLayers && (
|
|
419
|
+
<div className="card-body p-0 builder-layers">
|
|
420
|
+
<Layers expandRootOnLoad={true} />
|
|
421
|
+
</div>
|
|
422
|
+
)}
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
<div
|
|
426
|
+
id="builder-main-canvas"
|
|
427
|
+
className={`col builder-mode-${options.mode}`}
|
|
428
|
+
>
|
|
429
|
+
<div>
|
|
430
|
+
<Frame
|
|
431
|
+
resolver={{
|
|
432
|
+
Text,
|
|
433
|
+
Empty,
|
|
434
|
+
Columns,
|
|
435
|
+
JoinField,
|
|
436
|
+
Field,
|
|
437
|
+
ViewLink,
|
|
438
|
+
Action,
|
|
439
|
+
HTMLCode,
|
|
440
|
+
LineBreak,
|
|
441
|
+
Aggregation,
|
|
442
|
+
Card,
|
|
443
|
+
Image,
|
|
444
|
+
Link,
|
|
445
|
+
View,
|
|
446
|
+
SearchBar,
|
|
447
|
+
Container,
|
|
448
|
+
Column,
|
|
449
|
+
DropDownFilter,
|
|
450
|
+
DropMenu,
|
|
451
|
+
Tabs,
|
|
452
|
+
ToggleFilter,
|
|
453
|
+
}}
|
|
454
|
+
>
|
|
455
|
+
<Element canvas is={Column}></Element>
|
|
456
|
+
</Frame>
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
<div className="col-sm-auto builder-sidebar">
|
|
460
|
+
<div style={{ width: "16rem" }}>
|
|
461
|
+
<SaveButton />
|
|
462
|
+
<NextButton layout={layout} />
|
|
463
|
+
<HistoryPanel />
|
|
464
|
+
<ViewPageLink />
|
|
465
|
+
<SettingsPanel />
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
</PreviewCtx.Provider>
|
|
470
|
+
</Provider>
|
|
471
|
+
<div className="d-none preview-scratchpad"></div>
|
|
472
|
+
</Editor>
|
|
473
|
+
</ErrorBoundary>
|
|
474
|
+
);
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
export default Builder;
|