@saltcorn/builder 0.5.6-beta.3 → 0.6.0-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.
@@ -28,11 +28,13 @@ export const DropDownFilterSettings = () => {
28
28
  block,
29
29
  neutral_label,
30
30
  full_width,
31
+ where,
31
32
  } = useNode((node) => ({
32
33
  name: node.data.props.name,
33
34
  block: node.data.props.block,
34
35
  neutral_label: node.data.props.neutral_label,
35
36
  full_width: node.data.props.full_width,
37
+ where: node.data.props.where,
36
38
  }));
37
39
  const options = useContext(optionsCtx);
38
40
  return (
@@ -70,12 +72,24 @@ export const DropDownFilterSettings = () => {
70
72
  />
71
73
  </td>
72
74
  </tr>
75
+ <tr>
76
+ <td>
77
+ <label>Where</label>
78
+ </td>
79
+ <td>
80
+ <input
81
+ value={where}
82
+ className="form-control"
83
+ onChange={(e) => setProp((prop) => (prop.where = e.target.value))}
84
+ />
85
+ </td>
86
+ </tr>
73
87
  <tr>
74
88
  <td></td>
75
89
  <td>
76
90
  <BlockSetting block={block} setProp={setProp} />
77
91
  </td>
78
- </tr>{" "}
92
+ </tr>
79
93
  <tr>
80
94
  <td></td>
81
95
  <td>
@@ -108,6 +122,7 @@ DropDownFilter.craft = {
108
122
  { name: "name", segment_name: "field_name", column_name: "field_name" },
109
123
  "full_width",
110
124
  "neutral_label",
125
+ "where",
111
126
  "block",
112
127
  ],
113
128
  },
@@ -160,7 +160,7 @@ export const FieldSettings = () => {
160
160
  <TextStyleRow textStyle={textStyle} setProp={setProp} />
161
161
  )}
162
162
  </tbody>
163
- </table>{" "}
163
+ </table>
164
164
  {cfgFields ? (
165
165
  <ConfigForm
166
166
  fields={cfgFields}
@@ -29,8 +29,10 @@ export const ImageSettings = () => {
29
29
  fileid: node.data.props.fileid,
30
30
  field: node.data.props.field,
31
31
  url: node.data.props.url,
32
+ filepath: node.data.props.filepath,
32
33
  srctype: node.data.props.srctype,
33
- alt: node.data.props.fieldview,
34
+ alt: node.data.props.alt,
35
+ uploadedFiles: node.data.props.uploadedFiles,
34
36
  block: node.data.props.block,
35
37
  isFormula: node.data.props.isFormula,
36
38
  }));
@@ -43,8 +45,47 @@ export const ImageSettings = () => {
43
45
  alt,
44
46
  block,
45
47
  isFormula,
48
+ filepath,
49
+ uploadedFiles,
46
50
  } = node;
47
51
  const options = useContext(optionsCtx);
52
+ const handleUpload = (e) => {
53
+ if (e.target.files && e.target.files.length > 0) {
54
+ const formData = new FormData();
55
+
56
+ formData.append("file", e.target.files[0]);
57
+ formData.append("min_role_read", options.min_role || 1);
58
+
59
+ fetch("/files/upload", {
60
+ method: "POST",
61
+ body: formData,
62
+ headers: {
63
+ "X-Requested-With": "XMLHttpRequest",
64
+ "CSRF-Token": options.csrfToken,
65
+ },
66
+ })
67
+ .then((response) => response.json())
68
+ .then((result) => {
69
+ setProp((prop) => {
70
+ prop.fileid = result.success.id;
71
+ prop.srctype = "File";
72
+ prop.uploadedFiles = [
73
+ ...prop.uploadedFiles,
74
+ { id: result.success.id, filename: result.success.filename },
75
+ ];
76
+ });
77
+ })
78
+ .catch((error) => {
79
+ console.error("Error:", error);
80
+ });
81
+ }
82
+ };
83
+ const setAProp = (key) => (e) => {
84
+ if (e.target) {
85
+ const target_value = e.target.value;
86
+ setProp((prop) => (prop[key] = target_value));
87
+ }
88
+ };
48
89
  return (
49
90
  <table>
50
91
  <tbody>
@@ -63,12 +104,11 @@ export const ImageSettings = () => {
63
104
  <select
64
105
  value={srctype}
65
106
  className="form-control"
66
- onChange={(e) =>
67
- setProp((prop) => (prop.srctype = e.target.value))
68
- }
107
+ onChange={setAProp("srctype")}
69
108
  >
70
109
  <option>File</option>
71
110
  <option>URL</option>
111
+ <option>Upload</option>
72
112
  {options.mode === "show" && <option>Field</option>}
73
113
  </select>
74
114
  </td>
@@ -82,15 +122,18 @@ export const ImageSettings = () => {
82
122
  <select
83
123
  value={fileid}
84
124
  className="form-control"
85
- onChange={(e) =>
86
- setProp((prop) => (prop.fileid = e.target.value))
87
- }
125
+ onChange={setAProp("fileid")}
88
126
  >
89
127
  {options.images.map((f, ix) => (
90
128
  <option key={ix} value={f.id}>
91
129
  {f.filename}
92
130
  </option>
93
131
  ))}
132
+ {(uploadedFiles || []).map((uf, ix) => (
133
+ <option key={ix} value={uf.id}>
134
+ {uf.filename}
135
+ </option>
136
+ ))}
94
137
  </select>
95
138
  </td>
96
139
  </tr>
@@ -106,14 +149,27 @@ export const ImageSettings = () => {
106
149
  type="text"
107
150
  className="form-control"
108
151
  value={url}
109
- onChange={(e) =>
110
- setProp((prop) => (prop.url = e.target.value))
111
- }
152
+ onChange={setAProp("url")}
112
153
  />
113
154
  </OrFormula>
114
155
  </td>
115
156
  </tr>
116
157
  )}
158
+ {srctype === "Upload" && (
159
+ <tr>
160
+ <td>
161
+ <label>File</label>
162
+ </td>
163
+ <td>
164
+ <input
165
+ type="file"
166
+ className="form-control"
167
+ value={filepath}
168
+ onChange={handleUpload}
169
+ />
170
+ </td>
171
+ </tr>
172
+ )}
117
173
  {srctype === "Field" && (
118
174
  <tr>
119
175
  <td>
@@ -123,9 +179,7 @@ export const ImageSettings = () => {
123
179
  <select
124
180
  value={field}
125
181
  className="form-control"
126
- onChange={(e) =>
127
- setProp((prop) => (prop.field = e.target.value))
128
- }
182
+ onChange={setAProp("field")}
129
183
  >
130
184
  {options.fields
131
185
  .filter(
@@ -142,26 +196,30 @@ export const ImageSettings = () => {
142
196
  </td>
143
197
  </tr>
144
198
  )}
145
- <tr>
146
- <td>
147
- <label>Alt text</label>
148
- </td>
149
- <td>
150
- <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
151
- <input
152
- type="text"
153
- className="form-control"
154
- value={alt}
155
- onChange={(e) => setProp((prop) => (prop.alt = e.target.value))}
156
- />
157
- </OrFormula>
158
- </td>
159
- </tr>
160
- <tr>
161
- <td colSpan="2">
162
- <BlockSetting block={block} setProp={setProp} />
163
- </td>
164
- </tr>
199
+ {srctype !== "Upload" && (
200
+ <tr>
201
+ <td>
202
+ <label>Alt text</label>
203
+ </td>
204
+ <td>
205
+ <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
206
+ <input
207
+ type="text"
208
+ className="form-control"
209
+ value={alt}
210
+ onChange={setAProp("alt")}
211
+ />
212
+ </OrFormula>
213
+ </td>
214
+ </tr>
215
+ )}
216
+ {srctype !== "Upload" && (
217
+ <tr>
218
+ <td colSpan="2">
219
+ <BlockSetting block={block} setProp={setProp} />
220
+ </td>
221
+ </tr>
222
+ )}
165
223
  </tbody>
166
224
  </table>
167
225
  );
@@ -173,6 +231,7 @@ Image.craft = {
173
231
  alt: "",
174
232
  block: false,
175
233
  isFormula: {},
234
+ uploadedFiles: [],
176
235
  srctype: "File",
177
236
  },
178
237
  related: {
@@ -1,9 +1,13 @@
1
1
  import React, { Fragment, useContext } from "react";
2
2
  import { useNode } from "@craftjs/core";
3
- import { blockProps, BlockSetting, TextStyleSetting, OrFormula } from "./utils";
3
+ import {
4
+ blockProps,
5
+ BlockSetting,
6
+ TextStyleSetting,
7
+ OrFormula,
8
+ ButtonOrLinkSettingsRows,
9
+ } from "./utils";
4
10
  import optionsCtx from "../context";
5
- import FontIconPicker from "@fonticonpicker/react-fonticonpicker";
6
- import faIcons from "./faicons";
7
11
 
8
12
  export const Link = ({
9
13
  text,
@@ -13,6 +17,9 @@ export const Link = ({
13
17
  link_style,
14
18
  link_size,
15
19
  link_icon,
20
+ link_bgcol,
21
+ link_bordercol,
22
+ link_textcol,
16
23
  }) => {
17
24
  const {
18
25
  selected,
@@ -25,6 +32,15 @@ export const Link = ({
25
32
  } ${isFormula.text ? "text-monospace" : ""} ${link_style} ${link_size}`}
26
33
  {...blockProps(block)}
27
34
  ref={(dom) => connect(drag(dom))}
35
+ style={
36
+ link_style === "btn btn-custom-color"
37
+ ? {
38
+ backgroundColor: link_bgcol || "#000000",
39
+ borderColor: link_bordercol || "#000000",
40
+ color: link_textcol || "#000000",
41
+ }
42
+ : {}
43
+ }
28
44
  >
29
45
  {link_icon ? <i className={`${link_icon} mr-1`}></i> : ""}
30
46
  {isFormula.text ? `=${text}` : text}
@@ -45,6 +61,9 @@ export const LinkSettings = () => {
45
61
  link_style: node.data.props.link_style,
46
62
  link_size: node.data.props.link_size,
47
63
  link_icon: node.data.props.link_icon,
64
+ link_bgcol: node.data.props.link_bgcol,
65
+ link_bordercol: node.data.props.link_bordercol,
66
+ link_textcol: node.data.props.link_textcol,
48
67
  }));
49
68
  const {
50
69
  actions: { setProp },
@@ -56,140 +75,124 @@ export const LinkSettings = () => {
56
75
  nofollow,
57
76
  target_blank,
58
77
  link_src,
59
- link_style,
60
- link_size,
61
- link_icon,
62
78
  } = node;
63
79
  const options = useContext(optionsCtx);
80
+ const setAProp = (key) => (e) => {
81
+ if (e.target) {
82
+ const target_value = e.target.value;
83
+ setProp((prop) => (prop[key] = target_value));
84
+ }
85
+ };
64
86
  return (
65
87
  <div>
66
- <label>Text to display</label>
67
- <OrFormula nodekey="text" {...{ setProp, isFormula, node }}>
68
- <input
69
- type="text"
70
- className="form-control text-to-display"
71
- value={text}
72
- onChange={(e) => setProp((prop) => (prop.text = e.target.value))}
73
- />
74
- </OrFormula>
75
- <label>Link source</label>
76
- <select
77
- value={link_src}
78
- className="form-control"
79
- onChange={(e) =>
80
- setProp((prop) => {
81
- prop.link_src = e.target.value;
82
- if (e.target.value !== "URL") {
83
- prop.isFormula.url = false;
84
- }
85
- })
86
- }
87
- >
88
- <option>URL</option>
89
- {(options.pages || []).length > 0 && <option>Page</option>}
90
- {(options.views || []).length > 0 && options.mode === "page" && (
91
- <option>View</option>
92
- )}
93
- </select>
94
- {link_src === "URL" && (
95
- <Fragment>
96
- {" "}
97
- <label>URL</label>
98
- <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
99
- <input
100
- type="text"
101
- className="form-control "
102
- value={url}
103
- onChange={(e) => setProp((prop) => (prop.url = e.target.value))}
104
- />
105
- </OrFormula>
106
- </Fragment>
107
- )}
108
- {link_src === "Page" && (
109
- <Fragment>
110
- {" "}
111
- <label>Page</label>
112
- <select
113
- value={url}
114
- className="form-control"
115
- onChange={(e) =>
116
- setProp((prop) => {
117
- prop.url = e.target.value;
118
- })
119
- }
120
- >
121
- <option></option>
122
- {(options.pages || []).map((p) => (
123
- <option value={`/page/${p.name}`}>{p.name}</option>
124
- ))}
125
- </select>
126
- </Fragment>
127
- )}
128
- {link_src === "View" && (
129
- <Fragment>
130
- {" "}
131
- <label>View</label>
132
- <select
133
- value={url}
134
- className="form-control"
135
- onChange={(e) =>
136
- setProp((prop) => {
137
- prop.url = e.target.value;
138
- })
139
- }
140
- >
141
- <option></option>
142
- {(options.views || []).map((p) => (
143
- <option value={`/view/${p.name}`}>
144
- {p.name} [{p.viewtemplate}]
145
- </option>
146
- ))}
147
- </select>
148
- </Fragment>
149
- )}
150
- <div>
151
- <label>Link style</label>
152
- <select
153
- className="form-control"
154
- value={link_style}
155
- onChange={(e) =>
156
- setProp((prop) => (prop.link_style = e.target.value))
157
- }
158
- >
159
- <option value="">Link</option>
160
- <option value="btn btn-primary">Primary button</option>
161
- <option value="btn btn-secondary">Secondary button</option>
162
- <option value="btn btn-success">Success button</option>
163
- <option value="btn btn-danger">Danger button</option>
164
- <option value="btn btn-outline-primary">
165
- Primary outline button
166
- </option>
167
- <option value="btn btn-outline-secondary">
168
- Secondary outline button
169
- </option>
170
- </select>
171
- </div>
172
- <div>
173
- <label>Link size</label>
174
- <select
175
- className="form-control"
176
- value={link_size}
177
- onChange={(e) => setProp((prop) => (prop.link_size = e.target.value))}
178
- >
179
- <option value="">Standard</option>
180
- <option value="btn-lg">Large</option>
181
- <option value="btn-sm">Small</option>
182
- <option value="btn-block">Block</option>
183
- <option value="btn-block btn-lg">Large block</option>
184
- </select>
185
- </div>
186
- <label className="mr-2">Icon</label>
187
- <FontIconPicker
188
- value={link_icon}
189
- icons={faIcons}
190
- onChange={(value) => setProp((prop) => (prop.link_icon = value))}
191
- isMulti={false}
192
- />
88
+ <table className="w-100">
89
+ <tbody>
90
+ <tr>
91
+ <td>
92
+ <label>Text to display</label>
93
+ </td>
94
+ <td>
95
+ <OrFormula nodekey="text" {...{ setProp, isFormula, node }}>
96
+ <input
97
+ type="text"
98
+ className="form-control text-to-display"
99
+ value={text}
100
+ onChange={setAProp("text")}
101
+ />
102
+ </OrFormula>
103
+ </td>
104
+ </tr>
105
+ <tr>
106
+ <td>
107
+ <label>Link source</label>
108
+ </td>
109
+ <td>
110
+ <select
111
+ value={link_src}
112
+ className="form-control"
113
+ onChange={(e) =>
114
+ setProp((prop) => {
115
+ prop.link_src = e.target.value;
116
+ if (e.target.value !== "URL") {
117
+ prop.isFormula.url = false;
118
+ }
119
+ })
120
+ }
121
+ >
122
+ <option>URL</option>
123
+ {(options.pages || []).length > 0 && <option>Page</option>}
124
+ {(options.views || []).length > 0 &&
125
+ options.mode === "page" && <option>View</option>}
126
+ </select>
127
+ </td>
128
+ </tr>
129
+ {link_src === "URL" && (
130
+ <tr>
131
+ <td>
132
+ <label>URL</label>
133
+ </td>
134
+ <td>
135
+ <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
136
+ <input
137
+ type="text"
138
+ className="form-control "
139
+ value={url}
140
+ onChange={setAProp("url")}
141
+ />
142
+ </OrFormula>
143
+ </td>
144
+ </tr>
145
+ )}
146
+ {link_src === "Page" && (
147
+ <tr>
148
+ <td>
149
+ <label>Page</label>
150
+ </td>
151
+ <td>
152
+ <select
153
+ value={url}
154
+ className="form-control"
155
+ onChange={setAProp("url")}
156
+ >
157
+ <option></option>
158
+ {(options.pages || []).map((p) => (
159
+ <option value={`/page/${p.name}`}>{p.name}</option>
160
+ ))}
161
+ </select>
162
+ </td>
163
+ </tr>
164
+ )}
165
+ {link_src === "View" && (
166
+ <tr>
167
+ <td>
168
+ <label>View</label>
169
+ </td>
170
+ <td>
171
+ <select
172
+ value={url}
173
+ className="form-control"
174
+ onChange={setAProp("url")}
175
+ >
176
+ <option></option>
177
+ {(options.views || []).map((p) => (
178
+ <option value={`/view/${p.name}`}>
179
+ {p.name} [{p.viewtemplate}]
180
+ </option>
181
+ ))}
182
+ </select>
183
+ </td>
184
+ </tr>
185
+ )}
186
+ <ButtonOrLinkSettingsRows
187
+ setProp={setProp}
188
+ keyPrefix="link_"
189
+ btnClass="btn"
190
+ values={node}
191
+ linkFirst={true}
192
+ />
193
+ </tbody>
194
+ </table>
195
+
193
196
  <div className="form-check">
194
197
  <input
195
198
  className="form-check-input"
@@ -246,6 +249,9 @@ Link.craft = {
246
249
  "link_size",
247
250
  "link_icon",
248
251
  "link_style",
252
+ "link_bgcol",
253
+ "link_bordercol",
254
+ "link_textcol",
249
255
  ],
250
256
  },
251
257
  };
@@ -25,7 +25,7 @@ export const SearchBar = ({ has_dropdown, contents, show_badges }) => {
25
25
  >
26
26
  <div className="input-group-prepend">
27
27
  <button className="btn btn-outline-secondary" disabled>
28
- <i class="fas fa-search"></i>
28
+ <i className="fas fa-search"></i>
29
29
  </button>
30
30
  </div>
31
31
  <input