@saltcorn/builder 1.6.0-alpha.12 → 1.6.0-alpha.13
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/builder_bundle.js +4 -4
- package/package.json +2 -2
- package/src/components/Builder.js +121 -9
- package/src/components/Toolbox.js +78 -1
- package/src/components/elements/BoxModelEditor.js +24 -23
- package/src/components/elements/Card.js +26 -1
- package/src/components/elements/Columns.js +51 -10
- package/src/components/elements/Container.js +27 -5
- package/src/components/elements/Prompt.js +285 -0
- package/src/components/elements/Text.js +58 -14
- package/src/components/elements/utils.js +3 -1
- package/src/components/storage.js +24 -0
- package/src/utils/responsive_utils.js +139 -0
|
@@ -135,11 +135,21 @@ const Container = ({
|
|
|
135
135
|
const {
|
|
136
136
|
selected,
|
|
137
137
|
connectors: { connect, drag },
|
|
138
|
-
|
|
138
|
+
mobileWidth,
|
|
139
|
+
tabletWidth,
|
|
140
|
+
mobileHeight,
|
|
141
|
+
tabletHeight,
|
|
142
|
+
} = useNode((node) => ({
|
|
143
|
+
selected: node.events.selected,
|
|
144
|
+
mobileWidth: node.data.props.mobileWidth,
|
|
145
|
+
tabletWidth: node.data.props.tabletWidth,
|
|
146
|
+
mobileHeight: node.data.props.mobileHeight,
|
|
147
|
+
tabletHeight: node.data.props.tabletHeight,
|
|
148
|
+
}));
|
|
139
149
|
const { previewDevice } = useContext(previewCtx);
|
|
140
150
|
|
|
141
151
|
const BP_MIN = { "": 0, sm: 576, md: 768, lg: 992, xl: 1200 };
|
|
142
|
-
const DEVICE_W = { desktop: Infinity, tablet: 768, mobile:
|
|
152
|
+
const DEVICE_W = { desktop: Infinity, tablet: 768, mobile: 576 };
|
|
143
153
|
{
|
|
144
154
|
const dw = DEVICE_W[previewDevice] || Infinity;
|
|
145
155
|
if (minScreenWidth && dw < (BP_MIN[minScreenWidth] || 0)) {
|
|
@@ -175,7 +185,7 @@ const Container = ({
|
|
|
175
185
|
style: {
|
|
176
186
|
...parseStyles(customCSS || ""),
|
|
177
187
|
...reactifyStyles(style, transform, rotate),
|
|
178
|
-
display,
|
|
188
|
+
...(display && display !== "block" ? { display } : {}),
|
|
179
189
|
minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
|
|
180
190
|
...(bgType === "Image" && bgFileId
|
|
181
191
|
? {
|
|
@@ -207,16 +217,20 @@ const Container = ({
|
|
|
207
217
|
color: textColor,
|
|
208
218
|
}
|
|
209
219
|
: {}),
|
|
210
|
-
...(
|
|
220
|
+
...(height
|
|
211
221
|
? {
|
|
212
222
|
height: `${height}${heightUnit || "px"}`,
|
|
213
223
|
}
|
|
214
224
|
: {}),
|
|
215
|
-
...(
|
|
225
|
+
...(width
|
|
216
226
|
? {
|
|
217
227
|
width: `${width}${widthUnit || "px"}`,
|
|
218
228
|
}
|
|
219
229
|
: {}),
|
|
230
|
+
...(previewDevice === "mobile" && mobileWidth ? { width: mobileWidth } : {}),
|
|
231
|
+
...(previewDevice === "mobile" && mobileHeight ? { height: mobileHeight } : {}),
|
|
232
|
+
...(previewDevice === "tablet" && tabletWidth ? { width: tabletWidth } : {}),
|
|
233
|
+
...(previewDevice === "tablet" && tabletHeight ? { height: tabletHeight } : {}),
|
|
220
234
|
},
|
|
221
235
|
},
|
|
222
236
|
<Element canvas id="container-canvas" is={Column}>
|
|
@@ -238,6 +252,10 @@ const ContainerSettings = () => {
|
|
|
238
252
|
minHeight: node.data.props.minHeight,
|
|
239
253
|
height: node.data.props.height,
|
|
240
254
|
width: node.data.props.width,
|
|
255
|
+
mobileWidth: node.data.props.mobileWidth,
|
|
256
|
+
tabletWidth: node.data.props.tabletWidth,
|
|
257
|
+
mobileHeight: node.data.props.mobileHeight,
|
|
258
|
+
tabletHeight: node.data.props.tabletHeight,
|
|
241
259
|
minHeightUnit: node.data.props.minHeightUnit,
|
|
242
260
|
heightUnit: node.data.props.heightUnit,
|
|
243
261
|
widthUnit: node.data.props.widthUnit,
|
|
@@ -1259,6 +1277,10 @@ Container.craft = {
|
|
|
1259
1277
|
{ name: "minHeight", default: 20 },
|
|
1260
1278
|
{ name: "height" },
|
|
1261
1279
|
{ name: "width" },
|
|
1280
|
+
{ name: "mobileWidth" },
|
|
1281
|
+
{ name: "tabletWidth" },
|
|
1282
|
+
{ name: "mobileHeight" },
|
|
1283
|
+
{ name: "tabletHeight" },
|
|
1262
1284
|
{ name: "click_action" },
|
|
1263
1285
|
{ name: "url", canBeFormula: true },
|
|
1264
1286
|
{ name: "hoverColor" },
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/elements/Prompt
|
|
4
|
+
* @subcategory components / elements
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState, useContext, Fragment } from "react";
|
|
8
|
+
import { useNode, useEditor } from "@craftjs/core";
|
|
9
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
10
|
+
import optionsCtx from "../context";
|
|
11
|
+
import StorageCtx from "../storage_context";
|
|
12
|
+
|
|
13
|
+
const PROMPT_ICONS = {
|
|
14
|
+
container: "fas fa-box",
|
|
15
|
+
view: "fas fa-eye",
|
|
16
|
+
field: "fas fa-i-cursor",
|
|
17
|
+
action: "fas fa-bolt",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const PROMPT_LABELS = {
|
|
21
|
+
container: "Container",
|
|
22
|
+
view: "View",
|
|
23
|
+
field: "Field",
|
|
24
|
+
action: "Action",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Prompt = ({ promptType, promptText }) => {
|
|
28
|
+
const {
|
|
29
|
+
connectors: { connect, drag },
|
|
30
|
+
selected,
|
|
31
|
+
actions: { setProp },
|
|
32
|
+
id,
|
|
33
|
+
parent,
|
|
34
|
+
} = useNode((state) => ({
|
|
35
|
+
selected: state.events.selected,
|
|
36
|
+
parent: state.data.parent,
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const { query, actions: editorActions } = useEditor();
|
|
40
|
+
const options = useContext(optionsCtx);
|
|
41
|
+
const { layoutToNodes } = useContext(StorageCtx);
|
|
42
|
+
const { t } = useTranslation();
|
|
43
|
+
|
|
44
|
+
const [generating, setGenerating] = useState(false);
|
|
45
|
+
|
|
46
|
+
const icon = PROMPT_ICONS[promptType] || "fas fa-robot";
|
|
47
|
+
|
|
48
|
+
const handleGenerate = async (e) => {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
if (!promptText.trim()) return;
|
|
51
|
+
|
|
52
|
+
setGenerating(true);
|
|
53
|
+
setProp((props) => {
|
|
54
|
+
props.generateError = null;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const combinedPrompt = `[${promptType}]: ${promptText}`;
|
|
59
|
+
|
|
60
|
+
const res = await fetch("/viewedit/copilot-generate-layout", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: {
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
"CSRF-Token": options.csrfToken,
|
|
65
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
66
|
+
},
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
prompt: combinedPrompt,
|
|
69
|
+
mode: options.mode,
|
|
70
|
+
table: options.tableName,
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const data = await res.json();
|
|
75
|
+
if (data.error) {
|
|
76
|
+
setProp((props) => {
|
|
77
|
+
props.generateError = data.error;
|
|
78
|
+
});
|
|
79
|
+
} else if (data.layout) {
|
|
80
|
+
editorActions.delete(id);
|
|
81
|
+
layoutToNodes(data.layout, query, editorActions, parent, options);
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
setProp((props) => {
|
|
85
|
+
props.generateError = err.message || "Generation failed";
|
|
86
|
+
});
|
|
87
|
+
} finally {
|
|
88
|
+
setGenerating(false);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
ref={(dom) => connect(drag(dom))}
|
|
95
|
+
className={`prompt-placeholder ${selected ? "selected-node" : ""}`}
|
|
96
|
+
style={{
|
|
97
|
+
border: "2px dashed #6c8ebf",
|
|
98
|
+
borderRadius: "8px",
|
|
99
|
+
padding: "12px",
|
|
100
|
+
margin: "4px 0",
|
|
101
|
+
backgroundColor: "#e8f0fe",
|
|
102
|
+
minHeight: "60px",
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
<div
|
|
106
|
+
style={{
|
|
107
|
+
display: "flex",
|
|
108
|
+
alignItems: "center",
|
|
109
|
+
gap: "6px",
|
|
110
|
+
marginBottom: "6px",
|
|
111
|
+
fontWeight: "bold",
|
|
112
|
+
fontSize: "13px",
|
|
113
|
+
color: "#1a73e8",
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<i className={icon}></i>
|
|
117
|
+
<span>{t("Prompt")}</span>
|
|
118
|
+
</div>
|
|
119
|
+
<textarea
|
|
120
|
+
rows="3"
|
|
121
|
+
className="form-control form-control-sm"
|
|
122
|
+
style={{
|
|
123
|
+
fontSize: "13px",
|
|
124
|
+
backgroundColor: "transparent",
|
|
125
|
+
border: "1px solid #b0c4de",
|
|
126
|
+
resize: "vertical",
|
|
127
|
+
marginBottom: "8px",
|
|
128
|
+
}}
|
|
129
|
+
value={promptText}
|
|
130
|
+
placeholder={t("Describe what you want to generate...")}
|
|
131
|
+
onChange={(e) =>
|
|
132
|
+
setProp((props) => {
|
|
133
|
+
props.promptText = e.target.value;
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
onClick={(e) => e.stopPropagation()}
|
|
137
|
+
/>
|
|
138
|
+
<button
|
|
139
|
+
className="btn btn-sm btn-success w-100"
|
|
140
|
+
onClick={handleGenerate}
|
|
141
|
+
disabled={generating || !promptText.trim()}
|
|
142
|
+
style={{ fontSize: "12px" }}
|
|
143
|
+
>
|
|
144
|
+
{generating ? (
|
|
145
|
+
<Fragment>
|
|
146
|
+
<span
|
|
147
|
+
className="spinner-border spinner-border-sm me-1"
|
|
148
|
+
role="status"
|
|
149
|
+
></span>
|
|
150
|
+
{t("Generating...")}
|
|
151
|
+
</Fragment>
|
|
152
|
+
) : (
|
|
153
|
+
<Fragment>
|
|
154
|
+
<i className="fas fa-robot me-1"></i>
|
|
155
|
+
{t("Generate")}
|
|
156
|
+
</Fragment>
|
|
157
|
+
)}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const PromptSettings = () => {
|
|
164
|
+
const { t } = useTranslation();
|
|
165
|
+
const {
|
|
166
|
+
actions: { setProp },
|
|
167
|
+
promptType,
|
|
168
|
+
promptText,
|
|
169
|
+
generateError,
|
|
170
|
+
id,
|
|
171
|
+
parent,
|
|
172
|
+
} = useNode((node) => ({
|
|
173
|
+
promptType: node.data.props.promptType,
|
|
174
|
+
promptText: node.data.props.promptText,
|
|
175
|
+
generateError: node.data.props.generateError,
|
|
176
|
+
id: node.id,
|
|
177
|
+
parent: node.data.parent,
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
const { query, actions: editorActions } = useEditor();
|
|
181
|
+
const options = useContext(optionsCtx);
|
|
182
|
+
const { layoutToNodes } = useContext(StorageCtx);
|
|
183
|
+
|
|
184
|
+
const [generating, setGenerating] = useState(false);
|
|
185
|
+
|
|
186
|
+
const handleGenerate = async () => {
|
|
187
|
+
if (!promptText.trim()) return;
|
|
188
|
+
|
|
189
|
+
setGenerating(true);
|
|
190
|
+
setProp((props) => {
|
|
191
|
+
props.generateError = null;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const combinedPrompt = `[${promptType}]: ${promptText}`;
|
|
196
|
+
|
|
197
|
+
const res = await fetch("/viewedit/copilot-generate-layout", {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: {
|
|
200
|
+
"Content-Type": "application/json",
|
|
201
|
+
"CSRF-Token": options.csrfToken,
|
|
202
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
203
|
+
},
|
|
204
|
+
body: JSON.stringify({
|
|
205
|
+
prompt: combinedPrompt,
|
|
206
|
+
mode: options.mode,
|
|
207
|
+
table: options.tableName,
|
|
208
|
+
}),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const data = await res.json();
|
|
212
|
+
if (data.error) {
|
|
213
|
+
setProp((props) => {
|
|
214
|
+
props.generateError = data.error;
|
|
215
|
+
});
|
|
216
|
+
} else if (data.layout) {
|
|
217
|
+
editorActions.delete(id);
|
|
218
|
+
layoutToNodes(data.layout, query, editorActions, parent, options);
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
setProp((props) => {
|
|
222
|
+
props.generateError = err.message || "Generation failed";
|
|
223
|
+
});
|
|
224
|
+
} finally {
|
|
225
|
+
setGenerating(false);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<div>
|
|
231
|
+
<div className="mb-2">
|
|
232
|
+
<label className="form-label">{t("Prompt")}</label>
|
|
233
|
+
<textarea
|
|
234
|
+
rows="4"
|
|
235
|
+
className="form-control"
|
|
236
|
+
value={promptText}
|
|
237
|
+
placeholder={t("Describe what you want to generate...")}
|
|
238
|
+
onChange={(e) =>
|
|
239
|
+
setProp((props) => {
|
|
240
|
+
props.promptText = e.target.value;
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
/>
|
|
244
|
+
{generateError && (
|
|
245
|
+
<div className="text-danger small mt-1">{generateError}</div>
|
|
246
|
+
)}
|
|
247
|
+
</div>
|
|
248
|
+
<div className="mb-2">
|
|
249
|
+
<button
|
|
250
|
+
className="btn btn-sm btn-success w-100"
|
|
251
|
+
onClick={handleGenerate}
|
|
252
|
+
disabled={generating || !promptText.trim()}
|
|
253
|
+
>
|
|
254
|
+
{generating ? (
|
|
255
|
+
<Fragment>
|
|
256
|
+
<span
|
|
257
|
+
className="spinner-border spinner-border-sm me-1"
|
|
258
|
+
role="status"
|
|
259
|
+
></span>
|
|
260
|
+
{t("Generating...")}
|
|
261
|
+
</Fragment>
|
|
262
|
+
) : (
|
|
263
|
+
<Fragment>
|
|
264
|
+
<i className="fas fa-robot me-1"></i>
|
|
265
|
+
{t("Generate")}
|
|
266
|
+
</Fragment>
|
|
267
|
+
)}
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
Prompt.craft = {
|
|
275
|
+
displayName: "Prompt",
|
|
276
|
+
defaultProps: {
|
|
277
|
+
promptType: "container",
|
|
278
|
+
promptText: "",
|
|
279
|
+
},
|
|
280
|
+
related: {
|
|
281
|
+
settings: PromptSettings,
|
|
282
|
+
segment_type: "prompt",
|
|
283
|
+
fields: ["promptType", "promptText"],
|
|
284
|
+
},
|
|
285
|
+
};
|
|
@@ -19,8 +19,10 @@ import {
|
|
|
19
19
|
SettingsRow,
|
|
20
20
|
setAPropGen,
|
|
21
21
|
} from "./utils";
|
|
22
|
+
import { getDeviceValue } from "../../utils/responsive_utils";
|
|
22
23
|
import ContentEditable from "react-contenteditable";
|
|
23
24
|
import optionsCtx from "../context";
|
|
25
|
+
import PreviewCtx from "../preview_context";
|
|
24
26
|
import { CKEditor } from "ckeditor4-react";
|
|
25
27
|
import FontIconPicker from "@fonticonpicker/react-fonticonpicker";
|
|
26
28
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
@@ -89,6 +91,8 @@ const Text = ({
|
|
|
89
91
|
font,
|
|
90
92
|
style,
|
|
91
93
|
customClass,
|
|
94
|
+
mobileFontSize,
|
|
95
|
+
tabletFontSize,
|
|
92
96
|
}) => {
|
|
93
97
|
const {
|
|
94
98
|
connectors: { connect, drag },
|
|
@@ -99,6 +103,19 @@ const Text = ({
|
|
|
99
103
|
dragged: state.events.dragged,
|
|
100
104
|
}));
|
|
101
105
|
const [editable, setEditable] = useState(false);
|
|
106
|
+
const { previewDevice } = useContext(PreviewCtx);
|
|
107
|
+
|
|
108
|
+
const baseStyle = {
|
|
109
|
+
...(font ? { fontFamily: font } : {}),
|
|
110
|
+
...reactifyStyles(style || {}),
|
|
111
|
+
};
|
|
112
|
+
const activeFontSize = getDeviceValue(
|
|
113
|
+
baseStyle.fontSize,
|
|
114
|
+
tabletFontSize,
|
|
115
|
+
mobileFontSize,
|
|
116
|
+
previewDevice
|
|
117
|
+
);
|
|
118
|
+
if (activeFontSize) baseStyle.fontSize = activeFontSize;
|
|
102
119
|
|
|
103
120
|
useEffect(() => {
|
|
104
121
|
!selected && setEditable(false);
|
|
@@ -112,10 +129,7 @@ const Text = ({
|
|
|
112
129
|
} ${selected ? "selected-node" : ""}`}
|
|
113
130
|
ref={(dom) => connect(drag(dom))}
|
|
114
131
|
onDoubleClick={(e) => selected && setEditable(true)}
|
|
115
|
-
style={
|
|
116
|
-
...(font ? { fontFamily: font } : {}),
|
|
117
|
-
...reactifyStyles(style || {}),
|
|
118
|
-
}}
|
|
132
|
+
style={baseStyle}
|
|
119
133
|
>
|
|
120
134
|
<DynamicFontAwesomeIcon icon={icon} className="me-1" />
|
|
121
135
|
{isFormula.text ? (
|
|
@@ -158,6 +172,7 @@ export /**
|
|
|
158
172
|
*/
|
|
159
173
|
const TextSettings = () => {
|
|
160
174
|
const { t } = useTranslation();
|
|
175
|
+
const { previewDevice } = useContext(PreviewCtx);
|
|
161
176
|
const node = useNode((node) => ({
|
|
162
177
|
id: node.id,
|
|
163
178
|
text: node.data.props.text,
|
|
@@ -170,6 +185,8 @@ const TextSettings = () => {
|
|
|
170
185
|
icon: node.data.props.icon,
|
|
171
186
|
font: node.data.props.font,
|
|
172
187
|
style: node.data.props.style,
|
|
188
|
+
mobileFontSize: node.data.props.mobileFontSize,
|
|
189
|
+
tabletFontSize: node.data.props.tabletFontSize,
|
|
173
190
|
}));
|
|
174
191
|
const {
|
|
175
192
|
actions: { setProp },
|
|
@@ -183,6 +200,8 @@ const TextSettings = () => {
|
|
|
183
200
|
font,
|
|
184
201
|
style,
|
|
185
202
|
customClass,
|
|
203
|
+
mobileFontSize,
|
|
204
|
+
tabletFontSize,
|
|
186
205
|
} = node;
|
|
187
206
|
const { mode, fields, icons } = useContext(optionsCtx);
|
|
188
207
|
const setAProp = setAPropGen(setProp);
|
|
@@ -269,16 +288,41 @@ const TextSettings = () => {
|
|
|
269
288
|
node={node}
|
|
270
289
|
setProp={setProp}
|
|
271
290
|
/>
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
291
|
+
{previewDevice === "desktop" ? (
|
|
292
|
+
<SettingsRow
|
|
293
|
+
field={{
|
|
294
|
+
name: "font-size",
|
|
295
|
+
label: t("Font size"),
|
|
296
|
+
type: "DimUnits",
|
|
297
|
+
}}
|
|
298
|
+
node={node}
|
|
299
|
+
setProp={setProp}
|
|
300
|
+
isStyle={true}
|
|
301
|
+
/>
|
|
302
|
+
) : (
|
|
303
|
+
<SettingsRow
|
|
304
|
+
field={{
|
|
305
|
+
name: "font-size",
|
|
306
|
+
label: `${t("Font size")} (${previewDevice})`,
|
|
307
|
+
type: "DimUnits",
|
|
308
|
+
}}
|
|
309
|
+
node={{
|
|
310
|
+
...node,
|
|
311
|
+
style: {
|
|
312
|
+
"font-size": previewDevice === "mobile" ? mobileFontSize : tabletFontSize,
|
|
313
|
+
},
|
|
314
|
+
}}
|
|
315
|
+
setProp={(fn) => {
|
|
316
|
+
// Write to mobileFontSize/tabletFontSize instead of style
|
|
317
|
+
const proxy = { style: {} };
|
|
318
|
+
fn(proxy);
|
|
319
|
+
const val = proxy.style["font-size"];
|
|
320
|
+
const propName = previewDevice === "mobile" ? "mobileFontSize" : "tabletFontSize";
|
|
321
|
+
setProp((prop) => { prop[propName] = val; });
|
|
322
|
+
}}
|
|
323
|
+
isStyle={true}
|
|
324
|
+
/>
|
|
325
|
+
)}
|
|
282
326
|
<SettingsRow
|
|
283
327
|
field={{
|
|
284
328
|
name: "font-weight",
|
|
@@ -1350,7 +1350,9 @@ const ConfigField = ({
|
|
|
1350
1350
|
e?.target &&
|
|
1351
1351
|
myOnChange(
|
|
1352
1352
|
isStyle || subProp
|
|
1353
|
-
?
|
|
1353
|
+
? e.target.value === ""
|
|
1354
|
+
? ""
|
|
1355
|
+
: `${e.target.value}${styleDim || "px"}`
|
|
1354
1356
|
: e.target.value
|
|
1355
1357
|
)
|
|
1356
1358
|
}
|
|
@@ -30,6 +30,7 @@ import { DropDownFilter } from "./elements/DropDownFilter";
|
|
|
30
30
|
import { ToggleFilter } from "./elements/ToggleFilter";
|
|
31
31
|
import { DropMenu } from "./elements/DropMenu";
|
|
32
32
|
import { Container } from "./elements/Container";
|
|
33
|
+
import { Prompt } from "./elements/Prompt";
|
|
33
34
|
import { rand_ident } from "./elements/utils";
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -80,6 +81,7 @@ const allElements = [
|
|
|
80
81
|
Table,
|
|
81
82
|
ListColumn,
|
|
82
83
|
ListColumns,
|
|
84
|
+
Prompt,
|
|
83
85
|
];
|
|
84
86
|
|
|
85
87
|
export /**
|
|
@@ -183,6 +185,8 @@ const layoutToNodes = (
|
|
|
183
185
|
style={segment.style || {}}
|
|
184
186
|
icon={segment.icon}
|
|
185
187
|
font={segment.font || ""}
|
|
188
|
+
mobileFontSize={segment.mobileFontSize}
|
|
189
|
+
tabletFontSize={segment.tabletFontSize}
|
|
186
190
|
/>
|
|
187
191
|
);
|
|
188
192
|
} else if (segment.type === "view") {
|
|
@@ -318,6 +322,12 @@ const layoutToNodes = (
|
|
|
318
322
|
colClasses={segment.colClasses}
|
|
319
323
|
colStyles={segment.colStyles}
|
|
320
324
|
aligns={segment.aligns}
|
|
325
|
+
mobileAligns={segment.mobileAligns}
|
|
326
|
+
tabletAligns={segment.tabletAligns}
|
|
327
|
+
mobileWidth={segment.mobileWidth}
|
|
328
|
+
tabletWidth={segment.tabletWidth}
|
|
329
|
+
mobileHeight={segment.mobileHeight}
|
|
330
|
+
tabletHeight={segment.tabletHeight}
|
|
321
331
|
setting_col_n={segment.setting_col_n !== undefined ? segment.setting_col_n : 0}
|
|
322
332
|
contents={segment.besides.map(toTag)}
|
|
323
333
|
/>
|
|
@@ -354,6 +364,12 @@ const layoutToNodes = (
|
|
|
354
364
|
colClasses={segment.colClasses}
|
|
355
365
|
colStyles={segment.colStyles}
|
|
356
366
|
aligns={segment.aligns}
|
|
367
|
+
mobileAligns={segment.mobileAligns}
|
|
368
|
+
tabletAligns={segment.tabletAligns}
|
|
369
|
+
mobileWidth={segment.mobileWidth}
|
|
370
|
+
tabletWidth={segment.tabletWidth}
|
|
371
|
+
mobileHeight={segment.mobileHeight}
|
|
372
|
+
tabletHeight={segment.tabletHeight}
|
|
357
373
|
setting_col_n={segment.setting_col_n !== undefined ? segment.setting_col_n : 0}
|
|
358
374
|
contents={segment.besides.map(toTag)}
|
|
359
375
|
/>
|
|
@@ -489,6 +505,8 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
489
505
|
style: node.props.style,
|
|
490
506
|
icon: node.props.icon,
|
|
491
507
|
font: node.props.font,
|
|
508
|
+
mobileFontSize: node.props.mobileFontSize,
|
|
509
|
+
tabletFontSize: node.props.tabletFontSize,
|
|
492
510
|
...customProps,
|
|
493
511
|
};
|
|
494
512
|
}
|
|
@@ -525,10 +543,16 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
525
543
|
gx: node.props.gx != null ? +node.props.gx : undefined,
|
|
526
544
|
gy: node.props.gy != null ? +node.props.gy : undefined,
|
|
527
545
|
aligns: node.props.aligns,
|
|
546
|
+
mobileAligns: node.props.mobileAligns,
|
|
547
|
+
tabletAligns: node.props.tabletAligns,
|
|
528
548
|
vAligns: node.props.vAligns,
|
|
529
549
|
colClasses: node.props.colClasses,
|
|
530
550
|
colStyles: node.props.colStyles,
|
|
531
551
|
style: node.props.style,
|
|
552
|
+
mobileWidth: node.props.mobileWidth,
|
|
553
|
+
tabletWidth: node.props.tabletWidth,
|
|
554
|
+
mobileHeight: node.props.mobileHeight,
|
|
555
|
+
tabletHeight: node.props.tabletHeight,
|
|
532
556
|
widths,
|
|
533
557
|
setting_col_n: node.props.setting_col_n,
|
|
534
558
|
...customProps,
|