alchemy-chimera 1.0.0 → 1.0.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 1.0.3 (2022-03-16)
2
+
3
+ * Make table filtering case insensitive
4
+
5
+ ## 1.0.2 (2022-02-20)
6
+
7
+ * Improve editor styling
8
+ * Put editor errors in the Widget context
9
+ * Add TOC to editor
10
+ * Make sidebar sticky
11
+
12
+ ## 1.0.1 (2022-01-28)
13
+
14
+ * Allow setting a simple menu sidebar in the config
15
+ * Add simple notification after adding/saving
16
+ * Add page & window titles
17
+ * Improve edit buttons
18
+
1
19
  ## 1.0.0 (2021-09-12)
2
20
 
3
21
  * Use widgets to create the interface
@@ -0,0 +1,19 @@
1
+ hawkejs.scene.after({
2
+ type : 'set',
3
+ name : 'page-notification',
4
+ }, function onNotification(element, variables, block) {
5
+
6
+ let notification = element.querySelector('.notification');
7
+
8
+ if (!notification) {
9
+ return;
10
+ }
11
+
12
+ setTimeout(() => {
13
+ notification.classList.add('removing');
14
+
15
+ setTimeout(() => {
16
+ notification.remove();
17
+ }, 2500);
18
+ }, 4 * 1000);
19
+ });
@@ -10,10 +10,15 @@ body {
10
10
  --text-color: #475466;
11
11
  --main-bg-color: #ebedf0;
12
12
  --main-border-color: #dadee0;
13
+
13
14
  --button-bg-color: #F4F5F9;
14
15
  --button-bg-hover-color: #e7e9f2;
15
16
  --button-text-color: #3699FF;
16
17
 
18
+ --notification-bg-color: #4a4e58;
19
+ --notification-text-color: #f4f5f9;
20
+ --notification-border-color: #dadee0;
21
+
17
22
  --color-title: #475466;
18
23
  --color-box-border: #DADEE0;
19
24
  --color-active: #3699FF;
@@ -27,25 +32,97 @@ body {
27
32
  }
28
33
 
29
34
  .btn {
35
+ //--button-bg-color: var(--context-background-color, --button-bg-color);
36
+ --local-text-color: var(--context-color, var(--button-text-color));
37
+ --local-border-color: var(--context-border-color, var(--button-border-color));
38
+
30
39
  background-color: var(--button-bg-color);
40
+ color: var(--local-text-color);
41
+ border: 1px solid;
42
+ border-color: var(--local-border-color);
43
+
31
44
  text-decoration: none;
32
- color: var(--button-text-color);
33
45
  line-height: 2rem;
34
46
  min-width: 10rem;
35
47
  text-align: center;
36
48
  border-radius: 2px;
37
49
  font-weight: 500;
50
+ cursor: pointer;
38
51
 
39
52
  &:hover {
40
53
  background-color: var(--button-bg-hover-color);
54
+ //filter: brightness(1.05);
41
55
  }
42
56
  }
43
57
 
58
+ .primary {
59
+ --context-color: #084298;
60
+ --context-background-color: #cfe2ff;
61
+ --context-border-color: #b6d4fe;
62
+ }
63
+
64
+ .secondary {
65
+ --context-color: #41464b;
66
+ --context-background-color: #e2e3e5;
67
+ --context-border-color: #d3d6d8;
68
+ }
69
+
70
+ .success {
71
+ --context-color: #0f5132;
72
+ --context-background-color: #d1e7dd;
73
+ --context-border-color: #badbcc;
74
+ }
75
+
76
+ .danger,
77
+ .error {
78
+ --context-color: #842029;
79
+ --context-background-color: #f8d7da;
80
+ --context-border-color: #f5c2c7;
81
+ }
82
+
83
+ .warning {
84
+ --context-color: #664d03;
85
+ --context-background-color: #fff3cd;
86
+ --context-border-color: #ffecb5;
87
+ }
88
+
89
+ .info {
90
+ --context-color: #055160;
91
+ --context-background-color: #cff4fc;
92
+ --context-border-color: #b6effb;
93
+ }
94
+
95
+ .light {
96
+ --context-color: #636464;
97
+ --context-background-color: #fefefe;
98
+ --context-border-color: #fdfdfe;
99
+ }
100
+
101
+ .dark {
102
+ --context-color: #141619;
103
+ --context-background-color: #d3d3d4;
104
+ --context-border-color: #bcbebf;
105
+ }
106
+
107
+ .alert-box {
108
+ color: var(--context-color);
109
+ background-color: var(--context-background-color);
110
+ border: 1px solid;
111
+ border-color: var(--context-border-color);
112
+ padding: 1rem;
113
+ margin: 1rem 0 1rem;
114
+ }
115
+
44
116
  .chimera-sidebar {
45
117
  background-color: var(--sidebar-bg-color);
46
118
  flex: 0 0 14rem;
47
119
  display: flex;
48
120
  flex-flow: column;
121
+
122
+ .sidebar-widgets {
123
+ position: sticky;
124
+ top: 1rem;
125
+ }
49
126
  }
50
127
 
51
128
  .chimera-content {
@@ -86,6 +163,12 @@ body {
86
163
  .chimera-main {
87
164
  flex: 1;
88
165
  padding: 0.5rem;
166
+
167
+ &[data-he-template="chimera/widgets"] {
168
+ h1 {
169
+ padding-top: 0;
170
+ }
171
+ }
89
172
  }
90
173
 
91
174
  .main-widgets {
@@ -156,16 +239,41 @@ alchemy-widgets-navigation {
156
239
  height: 2rem;
157
240
  }
158
241
 
242
+ .page-notification {
243
+ .notification {
244
+ border: 1px solid var(--notification-border-color);
245
+ background: var(--notification-bg-color);
246
+ color: var(--notification-text-color);
247
+ border-radius: 5px;
248
+ padding: 0.5rem 0.8rem;
249
+ }
250
+ }
251
+
252
+ .removing {
253
+ transition: opacity 2s;
254
+ opacity: 0;
255
+ }
256
+
159
257
  alchemy-table .aft-column-filters input {
160
258
  @extend .chimera-input-field;
161
259
  width: 100%;
162
260
  }
163
261
 
262
+ alchemy-form {
263
+ .error-area:not(:empty) {
264
+ @extend .error, .alert-box;
265
+ margin-top: 0;
266
+ }
267
+ }
268
+
164
269
  alchemy-field {
165
270
  border: 1px solid var(--color-box-border);
166
271
  background-color: white;
167
272
  border-radius: 4px;
168
273
 
274
+ // In case something goes wrong:
275
+ min-height: 1rem;
276
+
169
277
  alchemy-label {
170
278
  padding-left: 1rem;
171
279
  line-height: 3rem;
@@ -211,6 +319,7 @@ alchemy-field {
211
319
  .field {
212
320
  display: flex;
213
321
  padding: 1rem;
322
+ flex: 1;
214
323
 
215
324
  > * {
216
325
  flex: 1;
@@ -222,16 +331,121 @@ alchemy-field {
222
331
  }
223
332
  }
224
333
 
225
- .field input[type="text"],
226
- .field input[type="number"],
227
- .field input[type="color"] {
228
- @extend .chimera-input-field;
229
- height: 3rem;
334
+ .field {
335
+ input[type="text"],
336
+ input[type="number"],
337
+ input[type="color"],
338
+ input[type="datetime-local"],
339
+ input[type="password"] {
340
+ @extend .chimera-input-field;
341
+ height: 3rem;
342
+ }
343
+
344
+ textarea {
345
+ @extend .chimera-input-field;
346
+ min-height: 5rem;
347
+ padding: 1rem;
348
+ }
349
+
350
+ input[type="color"] {
351
+ background-color: transparent;
352
+ border: none;
353
+ padding: 0;
354
+ }
230
355
  }
356
+ }
357
+
358
+ alchemy-field-array {
359
+ .add-entry {
360
+ @extend .btn;
361
+ margin: 1rem 0 0 1rem;
362
+ }
363
+
364
+ button.remove {
365
+ @extend .btn;
366
+ @extend .danger;
367
+ min-width: 6rem;
368
+ margin: 0 1rem 1rem 0;
369
+ }
370
+
371
+ .entries {
372
+ margin-top: 0.5rem;
373
+ }
374
+
375
+ alchemy-field-array-entry:not(:last-of-type) {
376
+ //border-bottom: 1px solid gray;
377
+ position: relative;
378
+
379
+ &::after {
380
+ display: block;
381
+ content: " ";
382
+ background-color: lightgray;
383
+ position: absolute;
384
+ bottom: 0;
385
+ height: 1px;
386
+ left: 50%;
387
+ transform: translateX(-50%);
388
+ width: 80%;
389
+ }
390
+ }
391
+
392
+ alchemy-field-array-entry:not(:first-of-type) {
393
+ margin-top: 1rem;
394
+ }
395
+ }
231
396
 
232
- .field input[type="color"] {
233
- background-color: transparent;
397
+ .chimera-editor-widgets {
398
+
399
+ alchemy-widgets-column.toc-col {
400
+ flex: 1 1;
401
+ }
402
+
403
+ table-of-contents[elements-selector="alchemy-field"] {
404
+ align-self: start;
405
+ top: 2rem;
406
+ position: sticky;
407
+
408
+ ol {
409
+ list-style: none;
410
+ margin: 0 0 0 2rem;
411
+ padding: 0;
412
+
413
+ li {
414
+ a {
415
+ display: block;
416
+ line-height: 2rem;
417
+ border-bottom: 1px solid #aaa;
418
+ text-decoration: none;
419
+ opacity: 0.5;
420
+ color: #0070e4;
421
+ }
422
+ }
423
+
424
+ li a.visible {
425
+ opacity: 1;
426
+ }
427
+ }
428
+ }
429
+ }
430
+
431
+ alchemy-field-schema {
432
+ alchemy-field {
234
433
  border: none;
235
- padding: 0;
434
+ margin-bottom: 1rem;
435
+ }
436
+ }
437
+
438
+ .aft-actions {
439
+ a {
440
+ color: var(--button-text-color);
441
+ background-color: var(--button-bg-color);
442
+ padding: 0.5rem;
443
+ border-radius: 6px;
444
+ margin: 0.2rem;
445
+ display: inline-block;
446
+
447
+ &:hover {
448
+ background-color: var(--button-bg-hover-color);
449
+ }
236
450
  }
237
451
  }
File without changes
@@ -7,12 +7,44 @@
7
7
  */
8
8
  const Editor = Function.inherits('Alchemy.Controller.Chimera', 'Editor');
9
9
 
10
+ /**
11
+ * Set the title
12
+ *
13
+ * @author Jelle De Loecker <jelle@elevenways.be>
14
+ * @since 1.0.1
15
+ * @version 1.0.1
16
+ *
17
+ * @param {String} title
18
+ */
19
+ Editor.setMethod(function setTitle(title) {
20
+
21
+ let window_title,
22
+ page_title;
23
+
24
+ if (alchemy.plugins.chimera.title) {
25
+ window_title = alchemy.plugins.chimera.title || '';
26
+
27
+ if (title && window_title) {
28
+ window_title += ' | ';
29
+ }
30
+ }
31
+
32
+ if (title) {
33
+ window_title += title;
34
+ }
35
+
36
+ page_title = title;
37
+
38
+ this.set('page_title', page_title);
39
+ this.set('window_title', window_title || page_title);
40
+ });
41
+
10
42
  /**
11
43
  * The index action
12
44
  *
13
45
  * @author Jelle De Loecker <jelle@elevenways.be>
14
46
  * @since 0.1.0
15
- * @version 1.0.0
47
+ * @version 1.0.1
16
48
  *
17
49
  * @param {Conduit} conduit
18
50
  * @param {String} model_name
@@ -23,7 +55,8 @@ Editor.setAction(function index(conduit, model_name) {
23
55
 
24
56
  let widget_config = model.chimera.getWidgetConfig('index', conduit);
25
57
 
26
- this.set('page_title', model_name.titleize());
58
+ this.setTitle(model_name.titleize());
59
+
27
60
  this.set('model_name', model_name);
28
61
 
29
62
  this.set('widget_config', widget_config);
@@ -36,7 +69,7 @@ Editor.setAction(function index(conduit, model_name) {
36
69
  *
37
70
  * @author Jelle De Loecker <jelle@elevenways.be>
38
71
  * @since 0.1.0
39
- * @version 1.0.0
72
+ * @version 1.0.2
40
73
  *
41
74
  * @param {Conduit} conduit
42
75
  * @param {String} model_name
@@ -56,14 +89,16 @@ Editor.setAction(async function add(conduit, model_name) {
56
89
  try {
57
90
  await record.save();
58
91
 
59
- let url = alchemy.routeUrl('Chimera.Editor#edit', {model: model_name, pk: record.$pk});
92
+ let url = alchemy.routeUrl('Chimera.Editor#edit', {
93
+ model: model_name,
94
+ pk: record.$pk,
95
+ message: 'added'
96
+ });
60
97
 
61
98
  return conduit.redirect(url);
62
99
  } catch (err) {
63
- // @TODO: set this in the context somehow?
64
- this.set('record_violations', err);
65
-
66
100
  this.set('context_variables', {
101
+ form_violations : err,
67
102
  record : record
68
103
  });
69
104
  }
@@ -78,6 +113,7 @@ Editor.setAction(async function add(conduit, model_name) {
78
113
  widget_config.class_names.push('chimera-editor-widgets');
79
114
 
80
115
  this.set('widget_config', widget_config);
116
+ this.setTitle(model.constructor.title + ' Add');
81
117
 
82
118
  this.render('chimera/widgets');
83
119
  });
@@ -87,7 +123,7 @@ Editor.setAction(async function add(conduit, model_name) {
87
123
  *
88
124
  * @author Jelle De Loecker <jelle@elevenways.be>
89
125
  * @since 0.1.0
90
- * @version 1.0.0
126
+ * @version 1.0.2
91
127
  *
92
128
  * @param {Conduit} conduit
93
129
  * @param {String} model_name
@@ -100,34 +136,44 @@ Editor.setAction(async function edit(conduit, model_name, pk_val) {
100
136
  model.translateItems = false;
101
137
 
102
138
  let record = await model.findByPk(pk_val);
139
+ let message_type = conduit.param('message');
103
140
 
104
- this.set('context_variables', {
105
- record : record
106
- });
141
+ let context_variables = {
142
+ record,
143
+ };
107
144
 
108
145
  if (conduit.method == 'post') {
109
146
 
110
147
  Object.assign(record, conduit.body[model_name]);
111
148
 
112
- console.log('Set data record of', record, conduit.body);
113
-
114
149
  try {
115
150
  await record.save();
151
+ message_type = 'saved';
116
152
  } catch (err) {
117
- // @TODO: set this in the context somehow?
118
- this.set('record_violations', err);
153
+ context_variables.form_violations = err;
119
154
  }
120
155
  }
121
156
 
157
+ this.set('context_variables', context_variables);
158
+
122
159
  let widget_config = model.chimera.getWidgetConfig('edit', conduit);
123
160
 
124
161
  if (!widget_config.class_names) {
125
162
  widget_config.class_names = [];
126
163
  }
127
164
 
165
+ if (message_type) {
166
+ if (message_type == 'added') {
167
+ this.set('message', 'Record has been added');
168
+ } else if (message_type == 'saved') {
169
+ this.set('message', 'Record has been saved');
170
+ }
171
+ }
172
+
128
173
  widget_config.class_names.push('chimera-editor-widgets');
129
174
 
130
175
  this.set('widget_config', widget_config);
176
+ this.setTitle(model.constructor.title + ' Edit');
131
177
 
132
178
  this.render('chimera/widgets');
133
179
  });
@@ -137,7 +183,7 @@ Editor.setAction(async function edit(conduit, model_name, pk_val) {
137
183
  *
138
184
  * @author Jelle De Loecker <jelle@elevenways.be>
139
185
  * @since 1.0.0
140
- * @version 1.0.0
186
+ * @version 1.0.3
141
187
  *
142
188
  * @param {Conduit} conduit
143
189
  * @param {String} model_name
@@ -183,7 +229,7 @@ Editor.setAction(async function records(conduit, model_name) {
183
229
  continue;
184
230
  }
185
231
 
186
- val = RegExp.interpretWildcard('*' + val + '*');
232
+ val = RegExp.interpretWildcard('*' + val + '*', 'i');
187
233
  crit.where(key).equals(val);
188
234
  }
189
235
  }
@@ -26,7 +26,7 @@ ChimeraStatic.setAction(function dashboard(conduit) {
26
26
  *
27
27
  * @author Jelle De Loecker <jelle@elevenways.be>
28
28
  * @since 1.0.0
29
- * @version 1.0.0
29
+ * @version 1.0.1
30
30
  *
31
31
  * @param {Conduit} conduit
32
32
  */
@@ -35,20 +35,71 @@ ChimeraStatic.setAction(function sidebar(conduit) {
35
35
  let widgets = [],
36
36
  config;
37
37
 
38
- let models = Model.getAllChildren();
39
- models.sortByPath(1, 'model_name');
40
-
41
- for (let model of models) {
42
- widgets.push({
43
- type : 'link',
44
- config : {
45
- route : 'Chimera.Editor#index',
46
- parameters: [
47
- {name: 'model', value: model.type_name},
48
- ],
49
- content: model.title
38
+ if (Array.isArray(alchemy.plugins.chimera.sidebar_menu)) {
39
+
40
+ for (let entry of alchemy.plugins.chimera.sidebar_menu) {
41
+
42
+ if (!entry.model && !entry.href) {
43
+ continue;
44
+ }
45
+
46
+ let model,
47
+ title = entry.title;
48
+
49
+ if (entry.model) {
50
+ model = Model.get(entry.model);
51
+ }
52
+
53
+ if (!title) {
54
+ if (model) {
55
+ title = model.constructor.title;
56
+ }
57
+
58
+ if (!title && entry.href) {
59
+ title = entry.href;
60
+ }
50
61
  }
51
- });
62
+
63
+ if (entry.href) {
64
+ widgets.push({
65
+ type : 'link',
66
+ config : {
67
+ href : entry.href,
68
+ content: title
69
+ }
70
+ });
71
+ } else {
72
+
73
+ widgets.push({
74
+ type : 'link',
75
+ config : {
76
+ route : 'Chimera.Editor#index',
77
+ parameters: [
78
+ {name: 'model', value: model.constructor.type_name},
79
+ ],
80
+ content: title
81
+ }
82
+ });
83
+ }
84
+ }
85
+
86
+ } else {
87
+
88
+ let models = Model.getAllChildren();
89
+ models.sortByPath(1, 'model_name');
90
+
91
+ for (let model of models) {
92
+ widgets.push({
93
+ type : 'link',
94
+ config : {
95
+ route : 'Chimera.Editor#index',
96
+ parameters: [
97
+ {name: 'model', value: model.type_name},
98
+ ],
99
+ content: model.title
100
+ }
101
+ });
102
+ }
52
103
  }
53
104
 
54
105
  config = [
@@ -65,7 +65,7 @@ Config.setMethod(function getFieldSet(name) {
65
65
  *
66
66
  * @author Jelle De Loecker <jelle@elevenways.be>
67
67
  * @since 1.0.0
68
- * @version 1.0.0
68
+ * @version 1.0.2
69
69
  *
70
70
  * @param {String} action
71
71
  * @param {Conduit} conduit
@@ -89,10 +89,13 @@ Config.setMethod(function getWidgetConfig(action, conduit) {
89
89
  let field;
90
90
 
91
91
  for (field of fieldset) {
92
+
92
93
  field_widgets.push({
93
94
  type : 'alchemy_field',
94
95
  config : {
95
- field : field.name,
96
+ field : field.name,
97
+ view : field.options.view,
98
+ widget_settings : field.options.widget_settings || {},
96
99
  }
97
100
  });
98
101
  }
@@ -100,7 +103,7 @@ Config.setMethod(function getWidgetConfig(action, conduit) {
100
103
  field_widgets.push({
101
104
  type : 'html',
102
105
  config : {
103
- html : '<button type="submit">Submit</button>'
106
+ html : '<button class="btn btn-submit" type="submit">Save</button>'
104
107
  }
105
108
  });
106
109
 
@@ -115,12 +118,43 @@ Config.setMethod(function getWidgetConfig(action, conduit) {
115
118
  "level": 1,
116
119
  "content": this.ModelClass.title + ' edit',
117
120
  }
118
- }, {
119
- "type": "alchemy_form",
120
- "config": {
121
- model : this.ModelClass.type_name,
122
- view_type : 'edit',
123
- widgets : field_widgets
121
+ },
122
+ {
123
+ type: "row",
124
+ config: {
125
+ widgets: [
126
+ {
127
+ type: "column",
128
+ config: {
129
+ widgets: [
130
+ {
131
+ "type": "alchemy_form",
132
+ "config": {
133
+ model : this.ModelClass.type_name,
134
+ view_type : 'edit',
135
+ widgets : field_widgets
136
+ }
137
+ }
138
+ ]
139
+ }
140
+ },
141
+ {
142
+ type: 'column',
143
+ config: {
144
+ wrapper_class_names: 'toc-col',
145
+ widgets: [
146
+ {
147
+ type: "table_of_contents",
148
+ config: {
149
+ parent_selector: 'alchemy-widgets-row',
150
+ elements_selector: 'alchemy-field',
151
+ title_selector: 'alchemy-label'
152
+ }
153
+ }
154
+ ]
155
+ }
156
+ }
157
+ ]
124
158
  }
125
159
  }
126
160
  ]
@@ -159,7 +193,5 @@ Config.setMethod(function getWidgetConfig(action, conduit) {
159
193
 
160
194
  result.widgets = widgets;
161
195
 
162
- console.log('Widget config', result, 'for', this);
163
-
164
196
  return result;
165
197
  });
package/model/model.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-chimera",
3
3
  "description": "Chimera plugin for Alchemy MVC",
4
- "version": "1.0.0",
4
+ "version": "1.0.3",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -11,13 +11,12 @@
11
11
  ],
12
12
  "repository": "11ways/alchemy-chimera",
13
13
  "peerDependencies": {
14
- "alchemy-acl" : "~0.6.0",
15
- "alchemy-menu" : "~0.6.0",
16
- "alchemymvc" : "~1.1.0",
17
- "alchemy-widget": "~0.1.0"
14
+ "alchemy-acl" : "~0.7.0",
15
+ "alchemymvc" : "~1.2.1",
16
+ "alchemy-widget": "~0.1.2"
18
17
  },
19
18
  "license": "MIT",
20
19
  "engines": {
21
- "node" : ">=10.21.0"
20
+ "node" : ">=12.0.0"
22
21
  }
23
22
  }
File without changes
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- {% extend "layouts/chimera_body" %}
1
+ {% include "layouts/chimera_basics" %}
2
2
 
3
3
  {% block "main" %}
4
4
  <alchemy-widgets
@@ -3,6 +3,7 @@
3
3
  <head>
4
4
  <!-- This puts in all the required styles, scripts, ... -->
5
5
  <% this.foundation({protoblast: true}) %>
6
+ <% script('chimera/chimera') %>
6
7
  </head>
7
8
  <body>
8
9
  <!-- This is a block you can assign content to -->
@@ -1,4 +1,15 @@
1
1
  {% extend "layouts/chimera_body" %}
2
2
 
3
- <% console.log('Pagetitle:', page_title) %>
4
- {% block "page-title" %}{{ page_title }}{% /block %}
3
+ {% if page_title %}
4
+ {% block "page-title" %}{{ page_title }}{% /block %}
5
+ {% /if %}
6
+
7
+ {% if window_title %}
8
+ <% set_title(window_title) %>
9
+ {% elseif page_title %}
10
+ <% set_title(page_title) %>
11
+ {% /if %}
12
+
13
+ {% if message %}
14
+ {% block "page-notification" %}<span class="notification">{{ message }}</span>{% /block %}
15
+ {% /if %}
@@ -6,13 +6,14 @@
6
6
  <div class="chimera-wrapper">
7
7
  <div class="chimera-sidebar">
8
8
  <div class="chimera-page-header">
9
- Test
9
+
10
10
  </div>
11
11
  <%= Alchemy.segment('Chimera.Static#sidebar') %>
12
12
  </div>
13
13
  <div class="chimera-content">
14
14
  <div class="chimera-page-header">
15
15
  <div class="page-title" data-he-name="page-title"></div>
16
+ <div class="page-notification" data-he-name="page-notification"></div>
16
17
  <div class="page-actions" data-he-name="page-actions"></div>
17
18
  </div>
18
19
  <div data-he-name="main" class="chimera-main">