@saltcorn/builder 0.8.1-rc.3 → 0.8.2-beta.0

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.
@@ -90,99 +90,102 @@ export /**
90
90
  * @category saltcorn-builder
91
91
  * @subcategory components
92
92
  */
93
- const Container = ({
94
- children,
95
- minHeight,
96
- height,
97
- width,
98
- minHeightUnit,
99
- heightUnit,
100
- widthUnit,
101
- vAlign,
102
- hAlign,
103
- bgFileId,
104
- imageSize,
105
- bgType,
106
- display,
107
- bgColor,
108
- setTextColor,
109
- textColor,
110
- customClass,
111
- customCSS,
112
- margin,
113
- padding,
114
- minScreenWidth,
115
- gradStartColor,
116
- gradEndColor,
117
- gradDirection,
118
- rotate,
119
- style,
93
+ const Container = ({
94
+ children,
95
+ minHeight,
96
+ height,
97
+ width,
98
+ minHeightUnit,
99
+ heightUnit,
100
+ widthUnit,
101
+ vAlign,
102
+ hAlign,
103
+ bgFileId,
104
+ imageSize,
105
+ bgType,
106
+ display,
107
+ bgColor,
108
+ setTextColor,
109
+ textColor,
110
+ customClass,
111
+ customCSS,
112
+ margin,
113
+ padding,
114
+ minScreenWidth,
115
+ gradStartColor,
116
+ gradEndColor,
117
+ gradDirection,
118
+ rotate,
119
+ style,
120
+ htmlElement,
121
+ }) => {
122
+ const {
123
+ selected,
124
+ connectors: { connect, drag },
125
+ } = useNode((node) => ({ selected: node.events.selected }));
126
+ //console.log("container style", style);
127
+ return React.createElement(
120
128
  htmlElement,
121
- }) => {
122
- const {
123
- selected,
124
- connectors: { connect, drag },
125
- } = useNode((node) => ({ selected: node.events.selected }));
126
- //console.log("container style", style);
127
- return React.createElement(
128
- htmlElement,
129
- {
130
- ref: (dom) => connect(drag(dom)),
131
- className: `${customClass || ""} canvas text-${hAlign} ${vAlign === "middle" ? "d-flex align-items-center" : ""
132
- } ${vAlign === "middle" && hAlign === "center" && "justify-content-center"
133
- } ${selected ? "selected-node" : ""}`,
134
- style: {
135
- ...parseStyles(customCSS || ""),
136
- ...reactifyStyles(style),
137
- display,
138
- //padding: padding.map((p) => p + "px").join(" "),
139
- //margin: margin.map((p) => p + "px").join(" "),
140
- minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
141
- ...(bgType === "Image" && bgFileId
142
- ? {
129
+ {
130
+ ref: (dom) => connect(drag(dom)),
131
+ className: `${customClass || ""} canvas text-${hAlign} ${
132
+ vAlign === "middle" ? "d-flex align-items-center" : ""
133
+ } ${
134
+ vAlign === "middle" && hAlign === "center" && "justify-content-center"
135
+ } ${selected ? "selected-node" : ""}`,
136
+ style: {
137
+ ...parseStyles(customCSS || ""),
138
+ ...reactifyStyles(style),
139
+ display,
140
+ //padding: padding.map((p) => p + "px").join(" "),
141
+ //margin: margin.map((p) => p + "px").join(" "),
142
+ minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
143
+ ...(bgType === "Image" && bgFileId
144
+ ? {
143
145
  backgroundImage: `url('/files/serve/${bgFileId}')`,
144
146
  backgroundSize:
145
147
  imageSize === "repeat" ? undefined : imageSize || "contain",
146
148
  backgroundRepeat:
147
149
  imageSize === "repeat" ? imageSize : "no-repeat",
148
150
  }
149
- : {}),
150
- ...(bgType === "Color"
151
- ? {
151
+ : {}),
152
+ ...(bgType === "Color"
153
+ ? {
152
154
  backgroundColor: bgColor,
153
155
  }
154
- : {}),
155
- ...(bgType === "Gradient"
156
- ? {
157
- backgroundImage: `linear-gradient(${gradDirection || 0
158
- }deg, ${gradStartColor}, ${gradEndColor})`,
156
+ : {}),
157
+ ...(bgType === "Gradient"
158
+ ? {
159
+ backgroundImage: `linear-gradient(${
160
+ gradDirection || 0
161
+ }deg, ${gradStartColor}, ${gradEndColor})`,
159
162
  }
160
- : {}),
161
- ...(setTextColor
162
- ? {
163
+ : {}),
164
+ ...(setTextColor
165
+ ? {
163
166
  color: textColor,
164
167
  }
165
- : {}),
166
- ...(typeof height !== "undefined"
167
- ? {
168
+ : {}),
169
+ ...(typeof height !== "undefined"
170
+ ? {
168
171
  height: `${height}${heightUnit || "px"}`,
169
172
  }
170
- : {}),
171
- ...(typeof width !== "undefined"
172
- ? {
173
+ : {}),
174
+ ...(typeof width !== "undefined"
175
+ ? {
173
176
  width: `${width}${widthUnit || "px"}`,
174
177
  }
175
- : {}),
176
- ...(rotate
177
- ? {
178
+ : {}),
179
+ ...(rotate
180
+ ? {
178
181
  transform: `rotate(${rotate}deg)`,
179
182
  }
180
- : {}),
181
- },
183
+ : {}),
182
184
  },
183
- children
184
- );
185
- };
185
+ },
186
+ children
187
+ );
188
+ };
186
189
 
187
190
  export /**
188
191
  * @returns {div}
@@ -191,710 +194,712 @@ export /**
191
194
  * @category saltcorn-builder
192
195
  * @subcategory components
193
196
  */
194
- const ContainerSettings = () => {
195
- const node = useNode((node) => ({
196
- minHeight: node.data.props.minHeight,
197
- height: node.data.props.height,
198
- width: node.data.props.width,
199
- minHeightUnit: node.data.props.minHeightUnit,
200
- heightUnit: node.data.props.heightUnit,
201
- widthUnit: node.data.props.widthUnit,
202
- bgType: node.data.props.bgType,
203
- bgColor: node.data.props.bgColor,
204
- isFormula: node.data.props.isFormula,
205
- bgFileId: node.data.props.bgFileId,
206
- imageSize: node.data.props.imageSize,
207
- htmlElement: node.data.props.htmlElement,
208
- vAlign: node.data.props.vAlign,
209
- hAlign: node.data.props.hAlign,
210
- fullPageWidth: node.data.props.fullPageWidth,
211
- showIfFormula: node.data.props.showIfFormula,
212
- setTextColor: node.data.props.setTextColor,
213
- showForRole: node.data.props.showForRole,
214
- textColor: node.data.props.textColor,
215
- customClass: node.data.props.customClass,
216
- customCSS: node.data.props.customCSS,
217
- minScreenWidth: node.data.props.minScreenWidth,
218
- maxScreenWidth: node.data.props.maxScreenWidth,
219
- show_for_owner: node.data.props.show_for_owner,
220
- margin: node.data.props.margin,
221
- padding: node.data.props.padding,
222
- url: node.data.props.url,
223
- hoverColor: node.data.props.hoverColor,
224
- gradStartColor: node.data.props.gradStartColor,
225
- gradEndColor: node.data.props.gradEndColor,
226
- gradDirection: node.data.props.gradDirection,
227
- overflow: node.data.props.overflow,
228
- rotate: node.data.props.rotate,
229
- display: node.data.props.display,
230
- style: node.data.props.style,
231
- imgResponsiveWidths: node.data.props.imgResponsiveWidths,
232
- }));
233
- const {
234
- actions: { setProp },
235
- bgFileId,
236
- imageSize,
237
- bgType,
238
- display,
239
- bgColor,
240
- setTextColor,
241
- textColor,
242
- showIfFormula,
243
- isFormula,
244
- showForRole,
245
- customClass,
246
- customCSS,
247
- minScreenWidth,
248
- maxScreenWidth,
249
- show_for_owner,
250
- margin,
251
- padding,
252
- url,
253
- hoverColor,
254
- gradStartColor,
255
- gradEndColor,
256
- gradDirection,
257
- fullPageWidth,
258
- overflow,
259
- htmlElement,
260
- imgResponsiveWidths,
261
- } = node;
262
- const options = useContext(optionsCtx);
263
- const { uploadedFiles } = useContext(previewCtx);
264
-
265
- const ownership = !!options.ownership;
266
-
267
- /**
268
- * @param {string} key
269
- * @returns {function}
270
- */
271
- const setAProp = setAPropGen(setProp);
272
- return (
273
- <Accordion>
274
- <div accordiontitle="Box" className="w-100">
275
- <BoxModelEditor setProp={setProp} node={node} />
276
- </div>
277
- <table className="w-100" accordiontitle="Display">
278
- <tbody>
279
- <SettingsRow
280
- field={{
281
- name: "display",
282
- label: "Display",
283
- type: "select",
284
- options: [
285
- "block",
286
- "inline",
287
- "inline-block",
288
- "none",
289
- "flex",
290
- "inline-flex",
291
- ],
292
- }}
293
- node={node}
294
- setProp={setProp}
295
- />
296
- <SettingsRow
297
- field={{
298
- name: "htmlElement",
299
- label: "HTML element",
300
- type: "select",
301
- options: [
302
- "div",
303
- "span",
304
- "article",
305
- "section",
306
- "header",
307
- "nav",
308
- "main",
309
- "aside",
310
- "footer",
311
- ],
312
- }}
313
- node={node}
314
- setProp={setProp}
315
- />
316
- <SettingsRow
317
- field={{
318
- name: "overflow",
319
- label: "Overflow",
320
- type: "btn_select",
321
- options: [
322
- { value: "visible", title: "Visible", label: <EyeFill /> },
323
- { value: "hidden", title: "Hidden", label: <EyeSlashFill /> },
324
- {
325
- value: "scroll",
326
- title: "Scroll",
327
- label: <FontAwesomeIcon icon={faScroll} />,
328
- },
329
- {
330
- value: "auto",
331
- title: "Auto",
332
- label: <FontAwesomeIcon icon={faRobot} />,
333
- },
334
- ],
335
- }}
336
- node={node}
337
- setProp={setProp}
338
- />
339
- <tr>
340
- <td colSpan="2">
341
- <div className="form-check">
342
- <input
343
- className="form-check-input"
344
- name="block"
345
- type="checkbox"
346
- checked={fullPageWidth}
347
- onChange={setAProp("fullPageWidth", { checked: true })}
348
- />
349
- <label className="form-check-label">
350
- Expand to full page width
351
- </label>
352
- </div>
353
- </td>
354
- </tr>
355
- </tbody>
356
- </table>
357
- <table className="w-100" accordiontitle="Contents">
358
- <tbody>
359
- <SettingsRow
360
- field={{
361
- name: "rotate",
362
- label: "Rotate °",
363
- type: "Integer",
364
- }}
365
- node={node}
366
- setProp={setProp}
367
- />
368
- <SettingsSectionHeaderRow title="Align" />
369
- <SettingsRow
370
- field={{
371
- name: "vAlign",
372
- label: "Vertical",
373
- type: "btn_select",
374
- options: [
375
- { value: "top", title: "All", label: <AlignTop /> },
376
- { value: "middle", title: "All", label: <AlignMiddle /> },
377
- { value: "bottom", title: "All", label: <AlignBottom /> },
378
- ],
379
- }}
380
- node={node}
381
- setProp={setProp}
382
- />
383
- <SettingsRow
384
- field={{
385
- name: "hAlign",
386
- label: "Horizontal",
387
- type: "btn_select",
388
- options: [
389
- { value: "left", title: "Left", label: <AlignStart /> },
390
- { value: "center", title: "Center", label: <AlignCenter /> },
391
- { value: "right", title: "Right", label: <AlignEnd /> },
392
- ],
393
- }}
394
- node={node}
395
- setProp={setProp}
396
- />
397
- <SettingsSectionHeaderRow title="Background" />
398
- <SettingsRow
399
- field={{
400
- name: "bgType",
401
- label: "Type",
402
- type: "btn_select",
403
- options: [
404
- { value: "None", label: <SlashCircle /> },
405
- { value: "Image", label: <Image /> },
406
- { value: "Color", label: <Palette /> },
407
- { value: "Gradient", label: <Rainbow /> },
408
- ],
409
- }}
410
- node={node}
411
- setProp={setProp}
412
- onChange={(v) =>
413
- setProp((prop) => {
414
- prop.bgFileId =
415
- prop.bgFileId ||
416
- (options.images.length + uploadedFiles.length > 0 &&
417
- options.images[0].location);
418
- })
419
- }
420
- />
421
- {bgType === "Gradient" && (
422
- <Fragment>
423
- <tr>
424
- <td>Start</td>
425
- <td>
426
- <OrFormula
427
- nodekey="gradStartColor"
428
- {...{ setProp, isFormula, node }}
429
- >
430
- <input
431
- type="color"
432
- value={gradStartColor}
433
- className="form-control-sm w-50"
434
- onChange={setAProp("gradStartColor")}
435
- />
436
- </OrFormula>
437
- </td>
438
- </tr>
439
- <tr>
440
- <td>End</td>
441
- <td>
442
- <OrFormula
443
- nodekey="gradEndColor"
444
- {...{ setProp, isFormula, node }}
445
- >
446
- <input
447
- type="color"
448
- value={gradEndColor}
449
- className="form-control-sm w-50"
450
- onChange={setAProp("gradEndColor")}
451
- />
452
- </OrFormula>
453
- </td>
454
- </tr>
455
- <tr>
456
- <td>Direction (&deg;)</td>
457
- <td>
458
- <OrFormula
459
- nodekey="gradDirection"
460
- {...{ setProp, isFormula, node }}
461
- >
462
- <input
463
- type="number"
464
- min="0"
465
- max="360"
466
- value={gradDirection}
467
- className="form-control-sm w-50"
468
- onChange={setAProp("gradDirection")}
469
- />
470
- </OrFormula>
471
- </td>
472
- </tr>
473
- </Fragment>
474
- )}
475
- {bgType === "Image" && (
476
- <Fragment>
477
- <tr>
478
- <td>
479
- <label>File</label>
480
- </td>
481
- <td>
482
- <select
483
- value={bgFileId}
484
- className="form-control-sm w-100 form-select"
485
- onChange={setAProp("bgFileId")}
486
- >
487
- {options.images.map((f, ix) => (
488
- <option key={ix} value={f.location}>
489
- {f.filename}
490
- </option>
491
- ))}
492
- {(uploadedFiles || []).map((uf, ix) => (
493
- <option key={ix} value={uf.location}>
494
- {uf.filename}
495
- </option>
496
- ))}{" "}
497
- </select>
498
- </td>
499
- </tr>
500
- <tr>
501
- <td>
502
- <label>Size</label>
503
- </td>
197
+ const ContainerSettings = () => {
198
+ const node = useNode((node) => ({
199
+ minHeight: node.data.props.minHeight,
200
+ height: node.data.props.height,
201
+ width: node.data.props.width,
202
+ minHeightUnit: node.data.props.minHeightUnit,
203
+ heightUnit: node.data.props.heightUnit,
204
+ widthUnit: node.data.props.widthUnit,
205
+ bgType: node.data.props.bgType,
206
+ bgColor: node.data.props.bgColor,
207
+ isFormula: node.data.props.isFormula,
208
+ bgFileId: node.data.props.bgFileId,
209
+ imageSize: node.data.props.imageSize,
210
+ htmlElement: node.data.props.htmlElement,
211
+ vAlign: node.data.props.vAlign,
212
+ hAlign: node.data.props.hAlign,
213
+ fullPageWidth: node.data.props.fullPageWidth,
214
+ showIfFormula: node.data.props.showIfFormula,
215
+ setTextColor: node.data.props.setTextColor,
216
+ showForRole: node.data.props.showForRole,
217
+ textColor: node.data.props.textColor,
218
+ customClass: node.data.props.customClass,
219
+ customCSS: node.data.props.customCSS,
220
+ minScreenWidth: node.data.props.minScreenWidth,
221
+ maxScreenWidth: node.data.props.maxScreenWidth,
222
+ show_for_owner: node.data.props.show_for_owner,
223
+ margin: node.data.props.margin,
224
+ padding: node.data.props.padding,
225
+ url: node.data.props.url,
226
+ hoverColor: node.data.props.hoverColor,
227
+ gradStartColor: node.data.props.gradStartColor,
228
+ gradEndColor: node.data.props.gradEndColor,
229
+ gradDirection: node.data.props.gradDirection,
230
+ overflow: node.data.props.overflow,
231
+ rotate: node.data.props.rotate,
232
+ display: node.data.props.display,
233
+ style: node.data.props.style,
234
+ imgResponsiveWidths: node.data.props.imgResponsiveWidths,
235
+ }));
236
+ const {
237
+ actions: { setProp },
238
+ bgFileId,
239
+ imageSize,
240
+ bgType,
241
+ display,
242
+ bgColor,
243
+ setTextColor,
244
+ textColor,
245
+ showIfFormula,
246
+ isFormula,
247
+ showForRole,
248
+ customClass,
249
+ customCSS,
250
+ minScreenWidth,
251
+ maxScreenWidth,
252
+ show_for_owner,
253
+ margin,
254
+ padding,
255
+ url,
256
+ hoverColor,
257
+ gradStartColor,
258
+ gradEndColor,
259
+ gradDirection,
260
+ fullPageWidth,
261
+ overflow,
262
+ htmlElement,
263
+ imgResponsiveWidths,
264
+ } = node;
265
+ const options = useContext(optionsCtx);
266
+ const { uploadedFiles } = useContext(previewCtx);
504
267
 
505
- <td>
506
- <select
507
- value={imageSize}
508
- className="form-control-sm form-select"
509
- onChange={setAProp("imageSize")}
510
- >
511
- <option>contain</option>
512
- <option>cover</option>
513
- <option>repeat</option>
514
- </select>
515
- </td>
516
- </tr>
517
- {imageSize !== "repeat" && (
518
- <tr>
519
- <td>
520
- <label>Responsive widths</label>
521
- </td>
268
+ const ownership = !!options.ownership;
522
269
 
523
- <td>
524
- <input
525
- type="text"
526
- value={imgResponsiveWidths}
527
- className="form-control"
528
- onChange={setAProp("imgResponsiveWidths")}
529
- />
530
- <small>
531
- <i>
532
- List of widths to serve resized images, e.g. 300, 400,
533
- 600
534
- </i>
535
- </small>
536
- </td>
537
- </tr>
538
- )}
539
- </Fragment>
540
- )}
541
- {bgType === "Color" && (
270
+ /**
271
+ * @param {string} key
272
+ * @returns {function}
273
+ */
274
+ const setAProp = setAPropGen(setProp);
275
+ return (
276
+ <Accordion>
277
+ <div accordiontitle="Box" className="w-100">
278
+ <BoxModelEditor setProp={setProp} node={node} />
279
+ </div>
280
+ <table className="w-100" accordiontitle="Display">
281
+ <tbody>
282
+ <SettingsRow
283
+ field={{
284
+ name: "display",
285
+ label: "Display",
286
+ type: "select",
287
+ options: [
288
+ "block",
289
+ "inline",
290
+ "inline-block",
291
+ "none",
292
+ "flex",
293
+ "inline-flex",
294
+ ],
295
+ }}
296
+ node={node}
297
+ setProp={setProp}
298
+ />
299
+ <SettingsRow
300
+ field={{
301
+ name: "htmlElement",
302
+ label: "HTML element",
303
+ type: "select",
304
+ options: [
305
+ "div",
306
+ "span",
307
+ "article",
308
+ "section",
309
+ "header",
310
+ "nav",
311
+ "main",
312
+ "aside",
313
+ "footer",
314
+ ],
315
+ }}
316
+ node={node}
317
+ setProp={setProp}
318
+ />
319
+ <SettingsRow
320
+ field={{
321
+ name: "overflow",
322
+ label: "Overflow",
323
+ type: "btn_select",
324
+ options: [
325
+ { value: "visible", title: "Visible", label: <EyeFill /> },
326
+ { value: "hidden", title: "Hidden", label: <EyeSlashFill /> },
327
+ {
328
+ value: "scroll",
329
+ title: "Scroll",
330
+ label: <FontAwesomeIcon icon={faScroll} />,
331
+ },
332
+ {
333
+ value: "auto",
334
+ title: "Auto",
335
+ label: <FontAwesomeIcon icon={faRobot} />,
336
+ },
337
+ ],
338
+ }}
339
+ node={node}
340
+ setProp={setProp}
341
+ />
342
+ <tr>
343
+ <td colSpan="2">
344
+ <div className="form-check">
345
+ <input
346
+ className="form-check-input"
347
+ name="block"
348
+ type="checkbox"
349
+ checked={fullPageWidth}
350
+ onChange={setAProp("fullPageWidth", { checked: true })}
351
+ />
352
+ <label className="form-check-label">
353
+ Expand to full page width
354
+ </label>
355
+ </div>
356
+ </td>
357
+ </tr>
358
+ </tbody>
359
+ </table>
360
+ <table className="w-100" accordiontitle="Contents">
361
+ <tbody>
362
+ <SettingsRow
363
+ field={{
364
+ name: "rotate",
365
+ label: "Rotate °",
366
+ type: "Integer",
367
+ }}
368
+ node={node}
369
+ setProp={setProp}
370
+ />
371
+ <SettingsSectionHeaderRow title="Align" />
372
+ <SettingsRow
373
+ field={{
374
+ name: "vAlign",
375
+ label: "Vertical",
376
+ type: "btn_select",
377
+ options: [
378
+ { value: "top", title: "All", label: <AlignTop /> },
379
+ { value: "middle", title: "All", label: <AlignMiddle /> },
380
+ { value: "bottom", title: "All", label: <AlignBottom /> },
381
+ ],
382
+ }}
383
+ node={node}
384
+ setProp={setProp}
385
+ />
386
+ <SettingsRow
387
+ field={{
388
+ name: "hAlign",
389
+ label: "Horizontal",
390
+ type: "btn_select",
391
+ options: [
392
+ { value: "left", title: "Left", label: <AlignStart /> },
393
+ { value: "center", title: "Center", label: <AlignCenter /> },
394
+ { value: "right", title: "Right", label: <AlignEnd /> },
395
+ ],
396
+ }}
397
+ node={node}
398
+ setProp={setProp}
399
+ />
400
+ <SettingsSectionHeaderRow title="Background" />
401
+ <SettingsRow
402
+ field={{
403
+ name: "bgType",
404
+ label: "Type",
405
+ type: "btn_select",
406
+ options: [
407
+ { value: "None", label: <SlashCircle /> },
408
+ { value: "Image", label: <Image /> },
409
+ { value: "Color", label: <Palette /> },
410
+ { value: "Gradient", label: <Rainbow /> },
411
+ ],
412
+ }}
413
+ node={node}
414
+ setProp={setProp}
415
+ onChange={(v) =>
416
+ setProp((prop) => {
417
+ prop.bgFileId =
418
+ prop.bgFileId ||
419
+ ((options.images || []).length + uploadedFiles.length > 0 &&
420
+ options.images?.[0]?.location);
421
+ })
422
+ }
423
+ />
424
+ {bgType === "Gradient" && (
425
+ <Fragment>
542
426
  <tr>
543
- <td>Color</td>
427
+ <td>Start</td>
544
428
  <td>
545
- <OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
429
+ <OrFormula
430
+ nodekey="gradStartColor"
431
+ {...{ setProp, isFormula, node }}
432
+ >
546
433
  <input
547
434
  type="color"
548
- value={bgColor}
435
+ value={gradStartColor}
549
436
  className="form-control-sm w-50"
550
- onChange={setAProp("bgColor")}
437
+ onChange={setAProp("gradStartColor")}
551
438
  />
552
439
  </OrFormula>
553
440
  </td>
554
441
  </tr>
555
- )}
556
- <SettingsSectionHeaderRow title="Typography" />
557
- <SettingsRow
558
- field={{
559
- name: "font-family",
560
- label: "Font family",
561
- type: "Font",
562
- }}
563
- node={node}
564
- setProp={setProp}
565
- isStyle={true}
566
- />
567
- <SettingsRow
568
- field={{
569
- name: "font-size",
570
- label: "Font size",
571
- type: "DimUnits",
572
- }}
573
- node={node}
574
- setProp={setProp}
575
- isStyle={true}
576
- />
577
- <SettingsRow
578
- field={{
579
- name: "font-weight",
580
- label: "Weight",
581
- type: "Integer",
582
- min: 100,
583
- max: 900,
584
- step: 100,
585
- }}
586
- node={node}
587
- setProp={setProp}
588
- isStyle={true}
589
- />
590
- <SettingsRow
591
- field={{
592
- name: "line-height",
593
- label: "Line height",
594
- type: "DimUnits",
595
- }}
596
- node={node}
597
- setProp={setProp}
598
- isStyle={true}
599
- />
600
- <tr>
601
- <td colSpan="2">
602
- <label>
603
- Set text color
604
- <input
605
- name="setTextColor"
606
- type="checkbox"
607
- checked={setTextColor}
608
- onChange={setAProp("setTextColor", { checked: true })}
609
- />
610
- </label>
611
- </td>
612
- </tr>
613
- {setTextColor && (
614
442
  <tr>
443
+ <td>End</td>
615
444
  <td>
616
- <label>Text</label>
445
+ <OrFormula
446
+ nodekey="gradEndColor"
447
+ {...{ setProp, isFormula, node }}
448
+ >
449
+ <input
450
+ type="color"
451
+ value={gradEndColor}
452
+ className="form-control-sm w-50"
453
+ onChange={setAProp("gradEndColor")}
454
+ />
455
+ </OrFormula>
617
456
  </td>
457
+ </tr>
458
+ <tr>
459
+ <td>Direction (&deg;)</td>
618
460
  <td>
619
- <input
620
- type="color"
621
- value={textColor}
622
- className="form-control-sm"
623
- onChange={setAProp("textColor")}
624
- />
461
+ <OrFormula
462
+ nodekey="gradDirection"
463
+ {...{ setProp, isFormula, node }}
464
+ >
465
+ <input
466
+ type="number"
467
+ min="0"
468
+ max="360"
469
+ value={gradDirection}
470
+ className="form-control-sm w-50"
471
+ onChange={setAProp("gradDirection")}
472
+ />
473
+ </OrFormula>
625
474
  </td>
626
475
  </tr>
627
- )}
628
- </tbody>
629
- </table>
630
- <table className="w-100" accordiontitle="Flex properties">
631
- <tbody>
632
- <SettingsSectionHeaderRow title="Flex item" />
633
- <SettingsRow
634
- field={{ name: "flex-grow", label: "Grow", type: "Float" }}
635
- node={node}
636
- setProp={setProp}
637
- isStyle={true}
638
- />
639
- <SettingsRow
640
- field={{ name: "flex-shrink", label: "Shrink", type: "Float" }}
641
- node={node}
642
- setProp={setProp}
643
- isStyle={true}
644
- />
645
- {display && display.includes("flex") && (
646
- <Fragment>
647
- <SettingsSectionHeaderRow title="Flex container" />
648
- <SettingsRow
649
- field={{
650
- name: "flex-direction",
651
- label: "Direction",
652
- type: "select",
653
- options: ["row", "row-reverse", "column", "column-reverse"],
654
- }}
655
- node={node}
656
- setProp={setProp}
657
- isStyle={true}
658
- />
659
- <SettingsRow
660
- field={{
661
- name: "flex-wrap",
662
- label: "Wrap",
663
- type: "select",
664
- options: ["nowrap", "wrap", "wrap-reverse"],
665
- }}
666
- node={node}
667
- setProp={setProp}
668
- isStyle={true}
669
- />
670
- <SettingsRow
671
- field={{
672
- name: "justify-content",
673
- label: "Justify content",
674
- type: "select",
675
- options: [
676
- "flex-start",
677
- "flex-end",
678
- "center",
679
- "space-between",
680
- "space-around",
681
- "space-evenly",
682
- "start",
683
- "end",
684
- "left",
685
- "right",
686
- ],
687
- }}
688
- node={node}
689
- setProp={setProp}
690
- isStyle={true}
691
- />
692
- <SettingsRow
693
- field={{
694
- name: "align-items",
695
- label: "Align items",
696
- type: "select",
697
- options: [
698
- "stretch",
699
- "flex-start",
700
- "flex-end",
701
- "center",
702
- "baseline",
703
- "first baseline",
704
- "last baseline",
705
- "start",
706
- "end",
707
- "self-start",
708
- "self-end",
709
- ],
710
- }}
711
- node={node}
712
- setProp={setProp}
713
- isStyle={true}
714
- />
715
- <SettingsRow
716
- field={{
717
- name: "align-content",
718
- label: "Align content",
719
- type: "select",
720
- options: [
721
- "flex-start",
722
- "flex-end",
723
- "center",
724
- "space-between",
725
- "space-around",
726
- "space-evenly",
727
- "stretch",
728
- "start",
729
- "end",
730
- "baseline",
731
- "first baseline",
732
- "last baseline",
733
- ],
734
- }}
735
- node={node}
736
- setProp={setProp}
737
- isStyle={true}
738
- />
739
- </Fragment>
740
- )}
741
- </tbody>
742
- </table>
743
- <table className="w-100" accordiontitle="Show if...">
744
- <tbody>
745
- {["show", "edit"].includes(options.mode) && (
746
- <SettingsSectionHeaderRow title="Formula - show if true" />
747
- )}
748
- {["show", "edit"].includes(options.mode) && (
476
+ </Fragment>
477
+ )}
478
+ {bgType === "Image" && (
479
+ <Fragment>
749
480
  <tr>
750
481
  <td>
751
- <input
752
- type="text"
753
- className="form-control text-to-display"
754
- value={showIfFormula}
755
- onChange={setAProp("showIfFormula")}
756
- />
757
- <div style={{ marginTop: "-5px" }}>
758
- <small className="text-muted font-monospace">FORMULA <FormulaTooltip /></small>
759
- </div>
482
+ <label>File</label>
760
483
  </td>
761
- </tr>
762
- )}
763
- <SettingsSectionHeaderRow title="Role" />
764
- {options.roles.map(({ role, id }) => (
765
- <tr key={id}>
766
- <td colSpan="2">
767
- <div className="form-check">
768
- <input
769
- className="form-check-input"
770
- name="block"
771
- type="checkbox"
772
- checked={
773
- typeof showForRole[id] === "undefined"
774
- ? true
775
- : showForRole[id]
776
- }
777
- onChange={(e) => {
778
- if (!e?.target) return;
779
- const checked = e.target.checked;
780
- setProp((prop) => {
781
- if (!prop.showForRole || prop.showForRole.length === 0)
782
- options.roles.forEach(
783
- (r) => (prop.showForRole[r.id] = true)
784
- );
785
- prop.showForRole[id] = checked;
786
- });
787
- }}
788
- />
789
- <label className="form-check-label">{role}</label>
790
- </div>
484
+ <td>
485
+ <select
486
+ value={bgFileId}
487
+ className="form-control-sm w-100 form-select"
488
+ onChange={setAProp("bgFileId")}
489
+ >
490
+ {options.images.map((f, ix) => (
491
+ <option key={ix} value={f.location}>
492
+ {f.filename}
493
+ </option>
494
+ ))}
495
+ {(uploadedFiles || []).map((uf, ix) => (
496
+ <option key={ix} value={uf.location}>
497
+ {uf.filename}
498
+ </option>
499
+ ))}{" "}
500
+ </select>
791
501
  </td>
792
502
  </tr>
793
- ))}
794
- {ownership ? (
795
503
  <tr>
796
- <td colSpan="2">
797
- <div className="form-check">
798
- <input
799
- className="form-check-input"
800
- name="block"
801
- type="checkbox"
802
- checked={show_for_owner}
803
- onChange={setAProp("show_for_owner", { checked: true })}
804
- />
805
- <label className="form-check-label">Owner</label>
806
- </div>
504
+ <td>
505
+ <label>Size</label>
506
+ </td>
507
+
508
+ <td>
509
+ <select
510
+ value={imageSize}
511
+ className="form-control-sm form-select"
512
+ onChange={setAProp("imageSize")}
513
+ >
514
+ <option>contain</option>
515
+ <option>cover</option>
516
+ <option>repeat</option>
517
+ </select>
807
518
  </td>
808
519
  </tr>
809
- ) : null}
520
+ {imageSize !== "repeat" && (
521
+ <tr>
522
+ <td>
523
+ <label>Responsive widths</label>
524
+ </td>
525
+
526
+ <td>
527
+ <input
528
+ type="text"
529
+ value={imgResponsiveWidths}
530
+ className="form-control"
531
+ onChange={setAProp("imgResponsiveWidths")}
532
+ />
533
+ <small>
534
+ <i>
535
+ List of widths to serve resized images, e.g. 300, 400,
536
+ 600
537
+ </i>
538
+ </small>
539
+ </td>
540
+ </tr>
541
+ )}
542
+ </Fragment>
543
+ )}
544
+ {bgType === "Color" && (
545
+ <tr>
546
+ <td>Color</td>
547
+ <td>
548
+ <OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
549
+ <input
550
+ type="color"
551
+ value={bgColor}
552
+ className="form-control-sm w-50"
553
+ onChange={setAProp("bgColor")}
554
+ />
555
+ </OrFormula>
556
+ </td>
557
+ </tr>
558
+ )}
559
+ <SettingsSectionHeaderRow title="Typography" />
560
+ <SettingsRow
561
+ field={{
562
+ name: "font-family",
563
+ label: "Font family",
564
+ type: "Font",
565
+ }}
566
+ node={node}
567
+ setProp={setProp}
568
+ isStyle={true}
569
+ />
570
+ <SettingsRow
571
+ field={{
572
+ name: "font-size",
573
+ label: "Font size",
574
+ type: "DimUnits",
575
+ }}
576
+ node={node}
577
+ setProp={setProp}
578
+ isStyle={true}
579
+ />
580
+ <SettingsRow
581
+ field={{
582
+ name: "font-weight",
583
+ label: "Weight",
584
+ type: "Integer",
585
+ min: 100,
586
+ max: 900,
587
+ step: 100,
588
+ }}
589
+ node={node}
590
+ setProp={setProp}
591
+ isStyle={true}
592
+ />
593
+ <SettingsRow
594
+ field={{
595
+ name: "line-height",
596
+ label: "Line height",
597
+ type: "DimUnits",
598
+ }}
599
+ node={node}
600
+ setProp={setProp}
601
+ isStyle={true}
602
+ />
603
+ <tr>
604
+ <td colSpan="2">
605
+ <label>
606
+ Set text color
607
+ <input
608
+ name="setTextColor"
609
+ type="checkbox"
610
+ checked={setTextColor}
611
+ onChange={setAProp("setTextColor", { checked: true })}
612
+ />
613
+ </label>
614
+ </td>
615
+ </tr>
616
+ {setTextColor && (
810
617
  <tr>
811
618
  <td>
812
- <label>Min screen width</label>
619
+ <label>Text</label>
813
620
  </td>
814
621
  <td>
815
- <select
816
- value={minScreenWidth}
817
- className="form-control form-select"
818
- onChange={setAProp("minScreenWidth")}
819
- >
820
- <option value="">all</option>
821
- <option value="sm">small</option>
822
- <option value="md">medium</option>
823
- <option value="lg">large</option>
824
- <option value="xl">x-large</option>
825
- </select>
622
+ <input
623
+ type="color"
624
+ value={textColor}
625
+ className="form-control-sm"
626
+ onChange={setAProp("textColor")}
627
+ />
826
628
  </td>
827
629
  </tr>
630
+ )}
631
+ </tbody>
632
+ </table>
633
+ <table className="w-100" accordiontitle="Flex properties">
634
+ <tbody>
635
+ <SettingsSectionHeaderRow title="Flex item" />
636
+ <SettingsRow
637
+ field={{ name: "flex-grow", label: "Grow", type: "Float" }}
638
+ node={node}
639
+ setProp={setProp}
640
+ isStyle={true}
641
+ />
642
+ <SettingsRow
643
+ field={{ name: "flex-shrink", label: "Shrink", type: "Float" }}
644
+ node={node}
645
+ setProp={setProp}
646
+ isStyle={true}
647
+ />
648
+ {display && display.includes("flex") && (
649
+ <Fragment>
650
+ <SettingsSectionHeaderRow title="Flex container" />
651
+ <SettingsRow
652
+ field={{
653
+ name: "flex-direction",
654
+ label: "Direction",
655
+ type: "select",
656
+ options: ["row", "row-reverse", "column", "column-reverse"],
657
+ }}
658
+ node={node}
659
+ setProp={setProp}
660
+ isStyle={true}
661
+ />
662
+ <SettingsRow
663
+ field={{
664
+ name: "flex-wrap",
665
+ label: "Wrap",
666
+ type: "select",
667
+ options: ["nowrap", "wrap", "wrap-reverse"],
668
+ }}
669
+ node={node}
670
+ setProp={setProp}
671
+ isStyle={true}
672
+ />
673
+ <SettingsRow
674
+ field={{
675
+ name: "justify-content",
676
+ label: "Justify content",
677
+ type: "select",
678
+ options: [
679
+ "flex-start",
680
+ "flex-end",
681
+ "center",
682
+ "space-between",
683
+ "space-around",
684
+ "space-evenly",
685
+ "start",
686
+ "end",
687
+ "left",
688
+ "right",
689
+ ],
690
+ }}
691
+ node={node}
692
+ setProp={setProp}
693
+ isStyle={true}
694
+ />
695
+ <SettingsRow
696
+ field={{
697
+ name: "align-items",
698
+ label: "Align items",
699
+ type: "select",
700
+ options: [
701
+ "stretch",
702
+ "flex-start",
703
+ "flex-end",
704
+ "center",
705
+ "baseline",
706
+ "first baseline",
707
+ "last baseline",
708
+ "start",
709
+ "end",
710
+ "self-start",
711
+ "self-end",
712
+ ],
713
+ }}
714
+ node={node}
715
+ setProp={setProp}
716
+ isStyle={true}
717
+ />
718
+ <SettingsRow
719
+ field={{
720
+ name: "align-content",
721
+ label: "Align content",
722
+ type: "select",
723
+ options: [
724
+ "flex-start",
725
+ "flex-end",
726
+ "center",
727
+ "space-between",
728
+ "space-around",
729
+ "space-evenly",
730
+ "stretch",
731
+ "start",
732
+ "end",
733
+ "baseline",
734
+ "first baseline",
735
+ "last baseline",
736
+ ],
737
+ }}
738
+ node={node}
739
+ setProp={setProp}
740
+ isStyle={true}
741
+ />
742
+ </Fragment>
743
+ )}
744
+ </tbody>
745
+ </table>
746
+ <table className="w-100" accordiontitle="Show if...">
747
+ <tbody>
748
+ {["show", "edit"].includes(options.mode) && (
749
+ <SettingsSectionHeaderRow title="Formula - show if true" />
750
+ )}
751
+ {["show", "edit"].includes(options.mode) && (
828
752
  <tr>
829
753
  <td>
830
- <label>Max screen width</label>
754
+ <input
755
+ type="text"
756
+ className="form-control text-to-display"
757
+ value={showIfFormula}
758
+ onChange={setAProp("showIfFormula")}
759
+ />
760
+ <div style={{ marginTop: "-5px" }}>
761
+ <small className="text-muted font-monospace">
762
+ FORMULA <FormulaTooltip />
763
+ </small>
764
+ </div>
831
765
  </td>
832
- <td>
833
- <select
834
- value={maxScreenWidth}
835
- className="form-control form-select"
836
- onChange={setAProp("maxScreenWidth")}
837
- >
838
- <option value="">all</option>
839
- <option value="md">small</option>
840
- <option value="lg">medium</option>
841
- <option value="xl">large</option>
842
- </select>
766
+ </tr>
767
+ )}
768
+ <SettingsSectionHeaderRow title="Role" />
769
+ {options.roles.map(({ role, id }) => (
770
+ <tr key={id}>
771
+ <td colSpan="2">
772
+ <div className="form-check">
773
+ <input
774
+ className="form-check-input"
775
+ name="block"
776
+ type="checkbox"
777
+ checked={
778
+ typeof showForRole[id] === "undefined"
779
+ ? true
780
+ : showForRole[id]
781
+ }
782
+ onChange={(e) => {
783
+ if (!e?.target) return;
784
+ const checked = e.target.checked;
785
+ setProp((prop) => {
786
+ if (!prop.showForRole || prop.showForRole.length === 0)
787
+ options.roles.forEach(
788
+ (r) => (prop.showForRole[r.id] = true)
789
+ );
790
+ prop.showForRole[id] = checked;
791
+ });
792
+ }}
793
+ />
794
+ <label className="form-check-label">{role}</label>
795
+ </div>
843
796
  </td>
844
797
  </tr>
845
- </tbody>
846
- </table>
847
- <div accordiontitle="Container link">
848
- <label>URL</label>
849
- <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
850
- <input
851
- type="text"
852
- className="form-control"
853
- value={url}
854
- onChange={setAProp("url")}
855
- />
856
- </OrFormula>
798
+ ))}
799
+ {ownership ? (
800
+ <tr>
801
+ <td colSpan="2">
802
+ <div className="form-check">
803
+ <input
804
+ className="form-check-input"
805
+ name="block"
806
+ type="checkbox"
807
+ checked={show_for_owner}
808
+ onChange={setAProp("show_for_owner", { checked: true })}
809
+ />
810
+ <label className="form-check-label">Owner</label>
811
+ </div>
812
+ </td>
813
+ </tr>
814
+ ) : null}
815
+ <tr>
816
+ <td>
817
+ <label>Min screen width</label>
818
+ </td>
819
+ <td>
820
+ <select
821
+ value={minScreenWidth}
822
+ className="form-control form-select"
823
+ onChange={setAProp("minScreenWidth")}
824
+ >
825
+ <option value="">all</option>
826
+ <option value="sm">small</option>
827
+ <option value="md">medium</option>
828
+ <option value="lg">large</option>
829
+ <option value="xl">x-large</option>
830
+ </select>
831
+ </td>
832
+ </tr>
833
+ <tr>
834
+ <td>
835
+ <label>Max screen width</label>
836
+ </td>
837
+ <td>
838
+ <select
839
+ value={maxScreenWidth}
840
+ className="form-control form-select"
841
+ onChange={setAProp("maxScreenWidth")}
842
+ >
843
+ <option value="">all</option>
844
+ <option value="md">small</option>
845
+ <option value="lg">medium</option>
846
+ <option value="xl">large</option>
847
+ </select>
848
+ </td>
849
+ </tr>
850
+ </tbody>
851
+ </table>
852
+ <div accordiontitle="Container link">
853
+ <label>URL</label>
854
+ <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
855
+ <input
856
+ type="text"
857
+ className="form-control"
858
+ value={url}
859
+ onChange={setAProp("url")}
860
+ />
861
+ </OrFormula>
857
862
 
858
- <label>Hover color</label>
859
- <select
860
- value={hoverColor}
861
- className="form-control form-select"
862
- onChange={setAProp("hoverColor")}
863
- >
864
- <option value="">None</option>
865
- <option value="gray">gray</option>
866
- <option value="gray-dark">gray-dark</option>
867
- <option value="light">light</option>
868
- <option value="dark">dark</option>
869
- </select>
870
- </div>
863
+ <label>Hover color</label>
864
+ <select
865
+ value={hoverColor}
866
+ className="form-control form-select"
867
+ onChange={setAProp("hoverColor")}
868
+ >
869
+ <option value="">None</option>
870
+ <option value="gray">gray</option>
871
+ <option value="gray-dark">gray-dark</option>
872
+ <option value="light">light</option>
873
+ <option value="dark">dark</option>
874
+ </select>
875
+ </div>
871
876
 
872
- <div accordiontitle="Custom class/CSS">
873
- <div>
874
- <label>Custom class</label>
875
- </div>
876
- <OrFormula nodekey="customClass" {...{ setProp, isFormula, node }}>
877
- <input
878
- type="text"
879
- className="form-control text-to-display"
880
- value={customClass}
881
- onChange={setAProp("customClass")}
882
- />
883
- </OrFormula>
884
- <div>
885
- <label>Custom CSS</label>
886
- </div>
887
- <textarea
888
- rows="4"
877
+ <div accordiontitle="Custom class/CSS">
878
+ <div>
879
+ <label>Custom class</label>
880
+ </div>
881
+ <OrFormula nodekey="customClass" {...{ setProp, isFormula, node }}>
882
+ <input
889
883
  type="text"
890
- className="text-to-display form-control"
891
- value={customCSS}
892
- onChange={setAProp("customCSS")}
893
- ></textarea>
884
+ className="form-control text-to-display"
885
+ value={customClass}
886
+ onChange={setAProp("customClass")}
887
+ />
888
+ </OrFormula>
889
+ <div>
890
+ <label>Custom CSS</label>
894
891
  </div>
895
- </Accordion>
896
- );
897
- };
892
+ <textarea
893
+ rows="4"
894
+ type="text"
895
+ className="text-to-display form-control"
896
+ value={customCSS}
897
+ onChange={setAProp("customCSS")}
898
+ ></textarea>
899
+ </div>
900
+ </Accordion>
901
+ );
902
+ };
898
903
 
899
904
  /**
900
905
  * @type {object}