@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raketa-cloud/admin",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "main": "src/index.js",
5
5
  "scripts": {
6
6
  "dev": "npx tailwindcss -i ./src/styles/application.css -o ../../apps/admin/static/application.css --watch",
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 { t, f, form_for, sort_button, pagination };
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);
@@ -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
- views,
190
- action,
191
- assigns: fullAssigns,
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);
@@ -1,6 +1,8 @@
1
1
  import FormBuilder from "./FormBuilder";
2
2
 
3
- export default function form_for(obj = {}, errors = {}, callback = (_) => {}) {
4
- const form = new FormBuilder(obj, errors);
5
- return callback(form);
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('resource.publish_at', { required: true, type: 'datetime-local' }) %>
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('resource.publish_at', { required: true, type: 'datetime-local' }) %>
6
- <%- f.field('resource.starts_at', { required: true, type: 'datetime-local' }) %>
7
- <%- f.field('resource.ends_at', { required: true, type: 'datetime-local' }) %>
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
 
@@ -23,4 +23,4 @@
23
23
  </div>
24
24
  </div>
25
25
 
26
- </div>
26
+ </div>
@@ -19,4 +19,4 @@
19
19
  </form>
20
20
  <% }) %>
21
21
  </div>
22
- </div>
22
+ </div>