@raketa-cloud/admin 0.0.21 → 0.0.23
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/package.json +1 -1
- package/src/Adapter.js +10 -4
- package/src/HonoAdapter.js +8 -5
- package/src/helpers/FormBuilder.js +124 -1
- package/src/helpers/form_for.js +5 -3
- package/src/styles/application.css +24 -0
- package/src/views/articles/_form.ejs +2 -5
- package/src/views/events/_form.ejs +4 -7
- package/src/views/settings/general/edit_form.ejs +1 -1
- package/src/views/settings/layout/edit_form.ejs +1 -1
package/package.json
CHANGED
package/src/Adapter.js
CHANGED
|
@@ -116,11 +116,17 @@ export default class Adapter {
|
|
|
116
116
|
return existsSync(appPath) ? appPath : packagePath;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
getHelpers() {
|
|
119
|
+
getHelpers(viewHelpersConfig) {
|
|
120
120
|
const t = new HTMLBuilder();
|
|
121
121
|
const f = new FormBuilder();
|
|
122
122
|
|
|
123
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
t,
|
|
125
|
+
f,
|
|
126
|
+
form_for: form_for(viewHelpersConfig),
|
|
127
|
+
sort_button,
|
|
128
|
+
pagination,
|
|
129
|
+
};
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
async renderLayout(assigns, body) {
|
|
@@ -132,9 +138,9 @@ export default class Adapter {
|
|
|
132
138
|
});
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
async renderAction({ views, action, assigns }) {
|
|
141
|
+
async renderAction({ views, action, assigns }, viewHelpersConfig = {}) {
|
|
136
142
|
const fullTemplatePath = this.getActionPath(views, action);
|
|
137
|
-
const renderAssigns = { ...this.getHelpers(), ...assigns };
|
|
143
|
+
const renderAssigns = { ...this.getHelpers(viewHelpersConfig), ...assigns };
|
|
138
144
|
|
|
139
145
|
try {
|
|
140
146
|
const rendered = await ejs.renderFile(fullTemplatePath, renderAssigns);
|
package/src/HonoAdapter.js
CHANGED
|
@@ -185,11 +185,14 @@ export default class HonoAdapter extends Adapter {
|
|
|
185
185
|
return routerCtx.json(json);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
const rendered = this.renderAction(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
const rendered = this.renderAction(
|
|
189
|
+
{
|
|
190
|
+
views,
|
|
191
|
+
action,
|
|
192
|
+
assigns: fullAssigns,
|
|
193
|
+
},
|
|
194
|
+
this.globalConfig?.helpers || {}
|
|
195
|
+
);
|
|
193
196
|
|
|
194
197
|
return routerCtx.html(rendered);
|
|
195
198
|
});
|
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
import HTMLBuilder from "./HTMLBuilder";
|
|
2
2
|
|
|
3
|
+
const BUTTON_FIELDS_MAP = {
|
|
4
|
+
label: { label: "Label" },
|
|
5
|
+
link: { label: "Link" },
|
|
6
|
+
id: { label: "ID" },
|
|
7
|
+
type: {
|
|
8
|
+
label: "Type",
|
|
9
|
+
as: "select",
|
|
10
|
+
options: [
|
|
11
|
+
["primary", "Primary"],
|
|
12
|
+
["secondary", "Secondary"],
|
|
13
|
+
["text", "Text"],
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
target: {
|
|
17
|
+
label: "Target",
|
|
18
|
+
as: "select",
|
|
19
|
+
options: [
|
|
20
|
+
["_self", "Self"],
|
|
21
|
+
["_blank", "New Tab"],
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
rel: {
|
|
25
|
+
label: "Follow Link",
|
|
26
|
+
as: "select",
|
|
27
|
+
options: [
|
|
28
|
+
["follow", "Follow"],
|
|
29
|
+
["nofollow", "No Follow"],
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const LINK_FIELDS_MAP = {
|
|
35
|
+
label: { label: "Label" },
|
|
36
|
+
link: { label: "Link" },
|
|
37
|
+
id: { label: "ID" },
|
|
38
|
+
className: {
|
|
39
|
+
label: "CSS Class",
|
|
40
|
+
},
|
|
41
|
+
target: {
|
|
42
|
+
label: "Target",
|
|
43
|
+
as: "select",
|
|
44
|
+
options: [
|
|
45
|
+
["_self", "Self"],
|
|
46
|
+
["_blank", "New Tab"],
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
rel: {
|
|
50
|
+
label: "Follow Link",
|
|
51
|
+
as: "select",
|
|
52
|
+
options: [
|
|
53
|
+
["follow", "Follow"],
|
|
54
|
+
["nofollow", "No Follow"],
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
3
59
|
function dig(obj, path) {
|
|
4
60
|
return path.split(".").reduce((acc, key) => {
|
|
5
61
|
if (acc && Object.hasOwn(acc, key)) {
|
|
@@ -33,10 +89,11 @@ function toFormName(dotNotation) {
|
|
|
33
89
|
}
|
|
34
90
|
|
|
35
91
|
export default class FormBuilder extends HTMLBuilder {
|
|
36
|
-
constructor(obj = {}, errors = {}) {
|
|
92
|
+
constructor(obj = {}, errors = {}, config = {}) {
|
|
37
93
|
super();
|
|
38
94
|
this.obj = obj;
|
|
39
95
|
this.errors = errors;
|
|
96
|
+
this.config = config;
|
|
40
97
|
}
|
|
41
98
|
|
|
42
99
|
__getValue(name) {
|
|
@@ -85,6 +142,7 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
85
142
|
const selected = value || this.__getValue(name);
|
|
86
143
|
|
|
87
144
|
const renderedOpts = [];
|
|
145
|
+
|
|
88
146
|
if (prompt) {
|
|
89
147
|
renderedOpts.push(this.tag("option", prompt, { value: "" }));
|
|
90
148
|
}
|
|
@@ -191,8 +249,73 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
191
249
|
return this.tag("button", label, { type: "submit", ...opts });
|
|
192
250
|
}
|
|
193
251
|
|
|
252
|
+
button(name, opts) {
|
|
253
|
+
const { label, ...rest } = opts;
|
|
254
|
+
const defaultLabel = opts?.label || this.__getDefaultLabel(name);
|
|
255
|
+
const fields = Object.keys(BUTTON_FIELDS_MAP).map((key) => {
|
|
256
|
+
const innerOpts = BUTTON_FIELDS_MAP[key];
|
|
257
|
+
|
|
258
|
+
if (innerOpts.as) {
|
|
259
|
+
return this.field(`${name}.${key}`, {
|
|
260
|
+
as: innerOpts.as,
|
|
261
|
+
options: this.config.buttons?.[`${key}Options`] || innerOpts.options,
|
|
262
|
+
label: innerOpts.label,
|
|
263
|
+
class: "no-margin",
|
|
264
|
+
});
|
|
265
|
+
} else {
|
|
266
|
+
return this.field(`${name}.${key}`, {
|
|
267
|
+
label: innerOpts.label,
|
|
268
|
+
class: "no-margin",
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
return this.tag(
|
|
274
|
+
"fieldset",
|
|
275
|
+
[this.tag("legend", defaultLabel, {}), ...fields].join(""),
|
|
276
|
+
{
|
|
277
|
+
class: "button-group",
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
link(name, opts) {
|
|
283
|
+
const { label, ...rest } = opts;
|
|
284
|
+
const defaultLabel = opts?.label || this.__getDefaultLabel(name);
|
|
285
|
+
const fields = Object.keys(LINK_FIELDS_MAP).map((key) => {
|
|
286
|
+
const innerOpts = LINK_FIELDS_MAP[key];
|
|
287
|
+
|
|
288
|
+
if (innerOpts.as) {
|
|
289
|
+
return this.field(`${name}.${key}`, {
|
|
290
|
+
as: innerOpts.as,
|
|
291
|
+
options: innerOpts.options,
|
|
292
|
+
label: innerOpts.label,
|
|
293
|
+
class: "no-margin",
|
|
294
|
+
});
|
|
295
|
+
} else {
|
|
296
|
+
return this.field(`${name}.${key}`, {
|
|
297
|
+
label: innerOpts.label,
|
|
298
|
+
class: "no-margin",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return this.tag(
|
|
304
|
+
"fieldset",
|
|
305
|
+
[this.tag("legend", defaultLabel, {}), ...fields].join(""),
|
|
306
|
+
{
|
|
307
|
+
class: "link-group",
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
194
312
|
field(name, opts = {}) {
|
|
195
313
|
const { as = "input", label, ...rest } = opts;
|
|
314
|
+
|
|
315
|
+
if (as === "button" || as === "link") {
|
|
316
|
+
return this[as](name, { ...rest, label });
|
|
317
|
+
}
|
|
318
|
+
|
|
196
319
|
const defaultLabel = opts?.label || this.__getDefaultLabel(name);
|
|
197
320
|
const htmlID = this.__getID(name);
|
|
198
321
|
const error = this.__getError(name);
|
package/src/helpers/form_for.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import FormBuilder from "./FormBuilder";
|
|
2
2
|
|
|
3
|
-
export default function form_for(
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export default function form_for(viewHelpersConfig = {}) {
|
|
4
|
+
return function form_for(obj = {}, errors = {}, callback = (_) => {}) {
|
|
5
|
+
const form = new FormBuilder(obj, errors, viewHelpersConfig);
|
|
6
|
+
return callback(form);
|
|
7
|
+
};
|
|
6
8
|
}
|
|
@@ -170,6 +170,30 @@ body {
|
|
|
170
170
|
.hint {
|
|
171
171
|
@apply text-sm opacity-50;
|
|
172
172
|
}
|
|
173
|
+
|
|
174
|
+
.button-group,
|
|
175
|
+
.link-group {
|
|
176
|
+
@apply grid grid-cols-6 gap-4 mb-4;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.button-group label,
|
|
180
|
+
.link-group label {
|
|
181
|
+
@apply font-normal;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.button-group legend,
|
|
185
|
+
.link-group legend {
|
|
186
|
+
@apply col-span-6 text-nowrap text-sm font-semibold w-fit pb-2;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.button-group div,
|
|
190
|
+
.link-group div {
|
|
191
|
+
@apply col-span-2 mb-0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.no-margin {
|
|
195
|
+
@apply m-0;
|
|
196
|
+
}
|
|
173
197
|
}
|
|
174
198
|
|
|
175
199
|
.inline-form {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<form action="<%= resource?.id ? `/${_context.locale}/articles/${resource.id}` : `/${_context.locale}/articles` %>" method="post" class="form">
|
|
3
3
|
<%- f.field('resource.title', { required: true }) %>
|
|
4
4
|
<%- f.field('resource.slug', { label: "URL", required: true }) %>
|
|
5
|
-
<%- f.field('
|
|
5
|
+
<%- f.field('general_settings.publish_at', { required: true, type: 'datetime-local', label: 'Publish at (UTC)' }) %>
|
|
6
6
|
|
|
7
7
|
<%- f.field('resource.visibility', { as: 'select', required: true, options: visibilityOptions }) %>
|
|
8
8
|
|
|
@@ -18,10 +18,7 @@
|
|
|
18
18
|
<%- f.field('resource.meta_title', { required: true }) %>
|
|
19
19
|
<%- f.field('resource.meta_description', { as: "textarea", required: true }) %>
|
|
20
20
|
|
|
21
|
-
<raketa-image-picker
|
|
22
|
-
name="resource[meta_image]"
|
|
23
|
-
value="<%= JSON.stringify(resource.meta_image) %>"
|
|
24
|
-
></raketa-image-picker>
|
|
21
|
+
<raketa-image-picker name="resource[meta_image]" value="<%= JSON.stringify(resource.meta_image) %>"></raketa-image-picker>
|
|
25
22
|
|
|
26
23
|
<%- f.field('resource.tags', { as: 'checkbox_group', required: true, options: tags.map(tag => [tag.id, tag.name]) }) %>
|
|
27
24
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<form action="<%= resource?.id ? `/${_context.locale}/events/${resource.id}` : `/${_context.locale}/events` %>" method="post" class="form">
|
|
3
3
|
<%- f.field('resource.title', { required: true }) %>
|
|
4
4
|
<%- f.field('resource.slug', { label: "URL", required: true }) %>
|
|
5
|
-
<%- f.field('
|
|
6
|
-
<%- f.field('
|
|
7
|
-
<%- f.field('
|
|
5
|
+
<%- f.field('general_settings.publish_at', { required: true, type: 'datetime-local', label: 'Publish at (UTC)' }) %>
|
|
6
|
+
<%- f.field('general_settings.starts_at', { required: true, type: 'datetime-local', label: 'Starts at (UTC)' }) %>
|
|
7
|
+
<%- f.field('general_settings.ends_at', { required: true, type: 'datetime-local', label: 'Ends at (UTC)' }) %>
|
|
8
8
|
|
|
9
9
|
<%- f.field('resource.visibility', { as: 'select', required: true, options: visibilityOptions }) %>
|
|
10
10
|
|
|
@@ -20,10 +20,7 @@
|
|
|
20
20
|
<%- f.field('resource.meta_title', { required: true }) %>
|
|
21
21
|
<%- f.field('resource.meta_description', { as: "textarea", required: true }) %>
|
|
22
22
|
|
|
23
|
-
<raketa-image-picker
|
|
24
|
-
name="resource[meta_image]"
|
|
25
|
-
value="<%= JSON.stringify(resource.meta_image) %>"
|
|
26
|
-
></raketa-image-picker>
|
|
23
|
+
<raketa-image-picker name="resource[meta_image]" value="<%= JSON.stringify(resource.meta_image) %>"></raketa-image-picker>
|
|
27
24
|
|
|
28
25
|
<%- f.field('resource.tags', { as: 'checkbox_group', required: true, options: tags.map(tag => [tag.id, tag.name]) }) %>
|
|
29
26
|
|