@onetype/framework 2.0.53 → 2.0.55

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.
Files changed (150) hide show
  1. package/addons/float/popup/css/popup.css +2 -2
  2. package/addons/render/directives/front/functions/process.js +3 -1
  3. package/addons/render/directives/front/items/self/160-slot.js +9 -1
  4. package/addons/render/editor/addon.js +13 -0
  5. package/addons/render/editor/functions/block/add.js +57 -0
  6. package/addons/render/editor/functions/block/delete.js +32 -0
  7. package/addons/render/editor/functions/block/find.js +30 -0
  8. package/addons/render/editor/functions/render/block.js +114 -0
  9. package/addons/render/editor/functions/render/blocks.js +31 -0
  10. package/addons/render/editor/items/elements/editor.js +69 -0
  11. package/addons/render/editor/items/self/paragraph.js +21 -0
  12. package/addons/render/editor/styles/editor.css +252 -0
  13. package/addons/render/elements/front/functions/types/colors/badge.js +19 -0
  14. package/addons/render/elements/front/functions/types/colors/status.js +24 -0
  15. package/addons/render/elements/front/functions/types/escape.js +8 -0
  16. package/addons/render/elements/front/functions/types/format/currency.js +16 -0
  17. package/addons/render/elements/front/functions/types/format/date.js +16 -0
  18. package/addons/render/elements/front/functions/types/format/number.js +24 -0
  19. package/addons/render/elements/front/functions/types/format/timeago.js +43 -0
  20. package/addons/render/elements/front/functions/types/render/avatar.js +10 -0
  21. package/addons/render/elements/front/functions/types/render/badge.js +17 -0
  22. package/addons/render/elements/front/functions/types/render/boolean.js +8 -0
  23. package/addons/render/elements/front/functions/types/render/chip.js +6 -0
  24. package/addons/render/elements/front/functions/types/render/currency.js +7 -0
  25. package/addons/render/elements/front/functions/types/render/date.js +6 -0
  26. package/addons/render/elements/front/functions/types/render/description.js +12 -0
  27. package/addons/render/elements/front/functions/types/render/group.js +11 -0
  28. package/addons/render/elements/front/functions/types/render/icon.js +8 -0
  29. package/addons/render/elements/front/functions/types/render/image.js +9 -0
  30. package/addons/render/elements/front/functions/types/render/link.js +8 -0
  31. package/addons/render/elements/front/functions/types/render/media.js +16 -0
  32. package/addons/render/elements/front/functions/types/render/metric.js +13 -0
  33. package/addons/render/elements/front/functions/types/render/number.js +6 -0
  34. package/addons/render/elements/front/functions/types/render/progress.js +13 -0
  35. package/addons/render/elements/front/functions/types/render/status.js +12 -0
  36. package/addons/render/elements/front/functions/types/render/tag.js +6 -0
  37. package/addons/render/elements/front/functions/types/render/tags.js +11 -0
  38. package/addons/render/elements/front/functions/types/render/text.js +8 -0
  39. package/addons/render/elements/front/functions/types/render/timeago.js +6 -0
  40. package/addons/render/elements/front/functions/types/render.js +16 -0
  41. package/addons/render/elements/front/items/directives/element.js +8 -3
  42. package/addons/render/elements/front/items/self/cards/info/info.css +499 -0
  43. package/addons/render/elements/front/items/self/cards/info/info.js +224 -0
  44. package/addons/render/elements/front/items/self/cards/item/item.css +614 -0
  45. package/addons/render/elements/front/items/self/cards/item/item.js +200 -0
  46. package/addons/render/elements/front/items/self/cards/pricing/pricing.css +318 -46
  47. package/addons/render/elements/front/items/self/cards/pricing/pricing.js +81 -30
  48. package/addons/render/elements/front/items/self/cards/profile/profile.css +446 -0
  49. package/addons/render/elements/front/items/self/cards/profile/profile.js +186 -0
  50. package/addons/render/elements/front/items/self/cards/share/share.css +445 -0
  51. package/addons/render/elements/front/items/self/cards/share/share.js +316 -0
  52. package/addons/render/elements/front/items/self/cards/stat/stat.css +356 -0
  53. package/addons/render/elements/front/items/self/cards/stat/stat.js +146 -0
  54. package/addons/render/elements/front/items/self/charts/bar/bar.css +263 -0
  55. package/addons/render/elements/front/items/self/charts/bar/bar.js +156 -0
  56. package/addons/render/elements/front/items/self/charts/donut/donut.css +222 -0
  57. package/addons/render/elements/front/items/self/charts/donut/donut.js +164 -0
  58. package/addons/render/elements/front/items/self/charts/line/line.css +229 -0
  59. package/addons/render/elements/front/items/self/charts/line/line.js +249 -0
  60. package/addons/render/elements/front/items/self/charts/sparkline/sparkline.css +102 -0
  61. package/addons/render/elements/front/items/self/charts/sparkline/sparkline.js +164 -0
  62. package/addons/render/elements/front/items/self/core/builder/builder.css +71 -116
  63. package/addons/render/elements/front/items/self/core/builder/builder.js +212 -127
  64. package/addons/render/elements/front/items/self/core/repeater/repeater.css +338 -71
  65. package/addons/render/elements/front/items/self/core/repeater/repeater.js +191 -44
  66. package/addons/render/elements/front/items/self/data/filters/filters.css +541 -0
  67. package/addons/render/elements/front/items/self/data/filters/filters.js +504 -0
  68. package/addons/render/elements/front/items/self/data/table/table.css +588 -0
  69. package/addons/render/elements/front/items/self/data/table/table.js +589 -0
  70. package/addons/render/elements/front/items/self/form/button/button.css +430 -103
  71. package/addons/render/elements/front/items/self/form/button/button.js +109 -101
  72. package/addons/render/elements/front/items/self/form/checkbox/checkbox.css +356 -39
  73. package/addons/render/elements/front/items/self/form/checkbox/checkbox.js +109 -75
  74. package/addons/render/elements/front/items/self/form/color/color.css +255 -61
  75. package/addons/render/elements/front/items/self/form/color/color.js +135 -41
  76. package/addons/render/elements/front/items/self/form/date/date.css +289 -38
  77. package/addons/render/elements/front/items/self/form/date/date.js +108 -24
  78. package/addons/render/elements/front/items/self/form/editor/editor.css +447 -0
  79. package/addons/render/elements/front/items/self/form/editor/editor.js +794 -0
  80. package/addons/render/elements/front/items/self/form/field/field.css +160 -29
  81. package/addons/render/elements/front/items/self/form/field/field.js +36 -16
  82. package/addons/render/elements/front/items/self/form/input/input.css +272 -32
  83. package/addons/render/elements/front/items/self/form/input/input.js +324 -124
  84. package/addons/render/elements/front/items/self/form/radio/radio.css +310 -45
  85. package/addons/render/elements/front/items/self/form/radio/radio.js +99 -80
  86. package/addons/render/elements/front/items/self/form/rating/rating.css +234 -57
  87. package/addons/render/elements/front/items/self/form/rating/rating.js +216 -86
  88. package/addons/render/elements/front/items/self/form/section/section.css +247 -32
  89. package/addons/render/elements/front/items/self/form/section/section.js +53 -16
  90. package/addons/render/elements/front/items/self/form/select/select.css +362 -64
  91. package/addons/render/elements/front/items/self/form/select/select.js +156 -30
  92. package/addons/render/elements/front/items/self/form/slider/slider.css +331 -123
  93. package/addons/render/elements/front/items/self/form/slider/slider.js +124 -26
  94. package/addons/render/elements/front/items/self/form/tags/tags.css +328 -53
  95. package/addons/render/elements/front/items/self/form/tags/tags.js +155 -28
  96. package/addons/render/elements/front/items/self/form/textarea/textarea.css +128 -27
  97. package/addons/render/elements/front/items/self/form/textarea/textarea.js +172 -113
  98. package/addons/render/elements/front/items/self/form/toggle/toggle.css +239 -39
  99. package/addons/render/elements/front/items/self/form/toggle/toggle.js +32 -17
  100. package/addons/render/elements/front/items/self/form/transfer/transfer.css +377 -0
  101. package/addons/render/elements/front/items/self/form/transfer/transfer.js +453 -0
  102. package/addons/render/elements/front/items/self/form/upload/upload.css +408 -0
  103. package/addons/render/elements/front/items/self/form/upload/upload.js +469 -0
  104. package/addons/render/elements/front/items/self/global/accordion/accordion.css +377 -0
  105. package/addons/render/elements/front/items/self/global/accordion/accordion.js +135 -0
  106. package/addons/render/elements/front/items/self/global/code/code.css +207 -44
  107. package/addons/render/elements/front/items/self/global/code/code.js +327 -19
  108. package/addons/render/elements/front/items/self/global/gallery/gallery.css +521 -0
  109. package/addons/render/elements/front/items/self/global/gallery/gallery.js +291 -0
  110. package/addons/render/elements/front/items/self/global/heading/heading.css +151 -49
  111. package/addons/render/elements/front/items/self/global/heading/heading.js +30 -15
  112. package/addons/render/elements/front/items/self/global/markdown/markdown.css +284 -135
  113. package/addons/render/elements/front/items/self/global/markdown/markdown.js +35 -5
  114. package/addons/render/elements/front/items/self/global/menu/menu.css +311 -56
  115. package/addons/render/elements/front/items/self/global/menu/menu.js +95 -47
  116. package/addons/render/elements/front/items/self/global/notice/notice.css +263 -23
  117. package/addons/render/elements/front/items/self/global/notice/notice.js +51 -11
  118. package/addons/render/elements/front/items/self/global/parameters/parameters.css +276 -33
  119. package/addons/render/elements/front/items/self/global/parameters/parameters.js +86 -16
  120. package/addons/render/elements/front/items/self/global/tags/tags.css +215 -29
  121. package/addons/render/elements/front/items/self/global/tags/tags.js +91 -17
  122. package/addons/render/elements/front/items/self/navigation/dock/dock.css +221 -0
  123. package/addons/render/elements/front/items/self/navigation/dock/dock.js +134 -0
  124. package/addons/render/elements/front/items/self/navigation/footer/footer.css +356 -0
  125. package/addons/render/elements/front/items/self/navigation/footer/footer.js +219 -0
  126. package/addons/render/elements/front/items/self/navigation/navbar/navbar.css +736 -76
  127. package/addons/render/elements/front/items/self/navigation/navbar/navbar.js +437 -29
  128. package/addons/render/elements/front/items/self/navigation/sidebar/sidebar.css +327 -196
  129. package/addons/render/elements/front/items/self/navigation/sidebar/sidebar.js +115 -62
  130. package/addons/render/elements/front/items/self/navigation/steps/steps.css +345 -0
  131. package/addons/render/elements/front/items/self/navigation/steps/steps.js +113 -0
  132. package/addons/render/elements/front/items/self/navigation/tabs/tabs.css +362 -33
  133. package/addons/render/elements/front/items/self/navigation/tabs/tabs.js +62 -19
  134. package/addons/render/elements/front/items/self/status/code/code.css +83 -12
  135. package/addons/render/elements/front/items/self/status/code/code.js +15 -4
  136. package/addons/render/elements/front/items/self/status/empty/empty.css +95 -15
  137. package/addons/render/elements/front/items/self/status/empty/empty.js +17 -12
  138. package/addons/render/elements/front/items/self/status/error/error.css +99 -14
  139. package/addons/render/elements/front/items/self/status/error/error.js +21 -11
  140. package/addons/render/elements/front/items/self/status/loading/loading.css +85 -14
  141. package/addons/render/elements/front/items/self/status/loading/loading.js +5 -6
  142. package/addons/render/elements/front/styles/types.css +363 -0
  143. package/instructions.txt +28 -0
  144. package/lib/load.js +1 -0
  145. package/lib/styles/reset.css +89 -76
  146. package/package.json +1 -1
  147. package/addons/render/elements/front/items/self/form/editor-markdown/editor-markdown.css +0 -410
  148. package/addons/render/elements/front/items/self/form/editor-markdown/editor-markdown.js +0 -191
  149. package/addons/render/elements/front/items/self/global/faq/faq.css +0 -98
  150. package/addons/render/elements/front/items/self/global/faq/faq.js +0 -56
@@ -4,13 +4,20 @@ onetype.AddonReady('elements', (elements) =>
4
4
  id: 'navigation-navbar',
5
5
  icon: 'menu',
6
6
  name: 'Navbar',
7
- description: 'Top navigation bar with logo and links.',
7
+ description: 'Premium top navigation bar with slots, dropdowns, user menu, breadcrumbs, sticky/shrink/scroll-hide behaviors and mobile drawer.',
8
8
  category: 'Navigation',
9
9
  author: 'OneType',
10
10
  config: {
11
11
  logo: {
12
+ type: 'string'
13
+ },
14
+ logoAlt: {
15
+ type: 'string',
16
+ value: 'Logo'
17
+ },
18
+ brandHref: {
12
19
  type: 'string',
13
- value: 'https://cdn.onetype.ai/brand/logo/full-orange.svg'
20
+ value: '/'
14
21
  },
15
22
  items: {
16
23
  type: 'array',
@@ -18,71 +25,472 @@ onetype.AddonReady('elements', (elements) =>
18
25
  each: {
19
26
  type: 'object',
20
27
  config: {
21
- icon: { type: 'string', value: '' },
22
- label: { type: 'string', value: '' },
23
- href: { type: 'string', value: '' },
24
- target: { type: 'string', value: '' },
28
+ id: { type: 'string' },
29
+ icon: { type: 'string' },
30
+ label: { type: 'string' },
31
+ description: { type: 'string' },
32
+ href: { type: 'string' },
33
+ target: { type: 'string' },
25
34
  position: { type: 'string', value: 'left', options: ['left', 'right'] },
26
- match: { type: 'string|array', value: '' }
35
+ match: { type: 'string|array' },
36
+ badge: { type: 'string|number' },
37
+ disabled: { type: 'boolean' },
38
+ children: { type: 'array', value: [] }
39
+ }
40
+ }
41
+ },
42
+ crumbs: {
43
+ type: 'array',
44
+ value: [],
45
+ each: {
46
+ type: 'object',
47
+ config: {
48
+ icon: { type: 'string' },
49
+ label: { type: 'string' },
50
+ href: { type: 'string' }
51
+ }
52
+ }
53
+ },
54
+ user: {
55
+ type: 'object',
56
+ value: null,
57
+ config: {
58
+ name: { type: 'string' },
59
+ email: { type: 'string' },
60
+ avatar: { type: 'string' },
61
+ role: { type: 'string' }
62
+ }
63
+ },
64
+ userMenu: {
65
+ type: 'array',
66
+ value: [],
67
+ each: {
68
+ type: 'object',
69
+ config: {
70
+ icon: { type: 'string' },
71
+ label: { type: 'string' },
72
+ href: { type: 'string' },
73
+ separator: { type: 'boolean' }
27
74
  }
28
75
  }
29
76
  },
77
+ notifications: {
78
+ type: 'number',
79
+ value: 0
80
+ },
81
+ notificationsHref: {
82
+ type: 'string'
83
+ },
84
+ sticky: {
85
+ type: 'boolean',
86
+ value: true
87
+ },
88
+ scrollHide: {
89
+ type: 'boolean'
90
+ },
91
+ shrinkOnScroll: {
92
+ type: 'boolean',
93
+ value: true
94
+ },
95
+ blur: {
96
+ type: 'boolean'
97
+ },
30
98
  variant: {
31
99
  type: 'array',
32
- value: ['bg-1'],
33
- options: ['bg-1', 'bg-2', 'bg-3', 'bg-4']
100
+ value: ['bg-1', 'border-bottom'],
101
+ options: ['bg-1', 'bg-2', 'bg-3', 'bg-4', 'border-bottom', 'border', 'clean']
102
+ },
103
+ _search: {
104
+ type: 'function'
34
105
  }
35
106
  },
36
107
  render: function()
37
108
  {
38
109
  const path = onetype.RouteCurrent();
39
110
 
111
+ // Active detection
112
+
40
113
  const isActive = (item) =>
41
114
  {
115
+ if(!item.href && !item.match)
116
+ {
117
+ return false;
118
+ }
119
+
42
120
  if(item.match)
43
121
  {
44
122
  const patterns = Array.isArray(item.match) ? item.match : [item.match];
45
123
  return patterns.some(pattern => onetype.RouteMatch(pattern, path).match);
46
124
  }
47
125
 
48
- return item.href === '/' ? path === '/' : path.startsWith(item.href);
126
+ if(item.href === '/')
127
+ {
128
+ return path === '/';
129
+ }
130
+
131
+ return path.startsWith(item.href);
49
132
  };
50
133
 
51
- this.left = this.items.filter(item => item.position === 'left').map(item => ({
134
+ // Split items by position + annotate active state
135
+
136
+ this.left = this.items.filter(item => (item.position || 'left') === 'left').map(item => ({
52
137
  ...item,
53
- active: isActive(item)
138
+ active: isActive(item),
139
+ hasChildren: item.children && item.children.length > 0
54
140
  }));
55
141
 
56
142
  this.right = this.items.filter(item => item.position === 'right').map(item => ({
57
143
  ...item,
58
- active: isActive(item)
144
+ active: isActive(item),
145
+ hasChildren: item.children && item.children.length > 0
59
146
  }));
60
147
 
61
148
  this.all = [...this.left, ...this.right];
149
+
150
+ // Slots — additive only, default content always renders
151
+
152
+ this.hasBanner = !!this.Slots.banner;
153
+ this.hasActions = !!this.Slots.actions;
154
+ this.hasLogo = !!this.logo;
155
+ this.hasCrumbs = this.crumbs && this.crumbs.length > 0;
156
+ this.hasUser = !!this.user;
157
+ this.hasNotifications = !!this.notificationsHref || this.notifications > 0;
158
+ this.hasUserMenu = this.hasUser && this.userMenu && this.userMenu.length > 0;
159
+
160
+ // State
161
+
62
162
  this.open = false;
163
+ this.hidden = false;
164
+ this.shrunk = false;
63
165
 
64
- this.toggle = () =>
166
+ this.toggleMobile = () =>
65
167
  {
66
168
  this.open = !this.open;
67
169
  };
68
170
 
69
- return `
70
- <nav :class="'holder ' + variant.join(' ')">
71
- <a class="logo" href="/">
72
- <img class="logo-icon" :src="logo" alt="OneType" />
73
- <i class="logo-arrow">keyboard_arrow_down</i>
74
- </a>
75
- <div class="tabs">
76
- <a ot-for="item in left" :class="'tab' + (item.active ? ' active' : '')" :href="item.href" :target="item.target || null"><i>{{ item.icon }}</i> {{ item.label }}</a>
171
+ this.closeMobile = () =>
172
+ {
173
+ this.open = false;
174
+ };
175
+
176
+ // Dropdown open handler — uses $ot.popup
177
+
178
+ this.openDropdown = (event, item) =>
179
+ {
180
+ if(!item.hasChildren)
181
+ {
182
+ return;
183
+ }
184
+
185
+ const target = event.currentTarget;
186
+ const children = item.children;
187
+
188
+ $ot.popup(target, function()
189
+ {
190
+ this.children = children;
191
+
192
+ this.go = (href) =>
193
+ {
194
+ if(href)
195
+ {
196
+ $ot.page(href);
197
+ $ot.close();
198
+ }
199
+ };
200
+
201
+ return /* html */ `
202
+ <div class="navbar-dropdown">
203
+ <a
204
+ ot-for="child in children"
205
+ :href="child.href || 'javascript:void(0)'"
206
+ :target="child.target || null"
207
+ class="dropdown-item"
208
+ ot-click="() => go(child.href)"
209
+ >
210
+ <div ot-if="child.icon" class="dropdown-icon">
211
+ <i>{{ child.icon }}</i>
212
+ </div>
213
+ <div class="dropdown-text">
214
+ <span class="dropdown-label">{{ child.label }}</span>
215
+ <span ot-if="child.description" class="dropdown-description">{{ child.description }}</span>
216
+ </div>
217
+ </a>
218
+ </div>
219
+ `;
220
+ }, {
221
+ id: 'navbar-dropdown-' + (item.id || item.label),
222
+ position: { x: 'center', y: 'bottom' },
223
+ offset: { x: 0, y: 8 }
224
+ });
225
+ };
226
+
227
+ // User menu dropdown
228
+
229
+ this.openUserMenu = (event) =>
230
+ {
231
+ if(!this.hasUserMenu)
232
+ {
233
+ return;
234
+ }
235
+
236
+ const target = event.currentTarget;
237
+ const user = this.user;
238
+ const menu = this.userMenu;
239
+
240
+ $ot.popup(target, function()
241
+ {
242
+ this.user = user;
243
+ this.menu = menu;
244
+
245
+ this.go = (href) =>
246
+ {
247
+ if(href)
248
+ {
249
+ $ot.page(href);
250
+ $ot.close();
251
+ }
252
+ };
253
+
254
+ return /* html */ `
255
+ <div class="navbar-user-menu">
256
+ <div class="user-head">
257
+ <div ot-if="user.avatar" class="user-avatar">
258
+ <img :src="user.avatar" :alt="user.name || ''" />
259
+ </div>
260
+ <div ot-if="!user.avatar" class="user-avatar user-avatar-fallback">
261
+ <i>person</i>
262
+ </div>
263
+ <div class="user-text">
264
+ <span ot-if="user.name" class="user-name">{{ user.name }}</span>
265
+ <span ot-if="user.email" class="user-email">{{ user.email }}</span>
266
+ </div>
267
+ </div>
268
+ <div class="user-menu-list">
269
+ <div ot-for="entry in menu">
270
+ <div ot-if="entry.separator" class="user-menu-separator"></div>
271
+ <a
272
+ ot-if="!entry.separator"
273
+ :href="entry.href || 'javascript:void(0)'"
274
+ class="user-menu-item"
275
+ ot-click="() => go(entry.href)"
276
+ >
277
+ <i ot-if="entry.icon">{{ entry.icon }}</i>
278
+ <span>{{ entry.label }}</span>
279
+ </a>
280
+ </div>
281
+ </div>
282
+ </div>
283
+ `;
284
+ }, {
285
+ id: 'navbar-user-menu',
286
+ position: { x: 'right-in', y: 'bottom' },
287
+ offset: { x: 0, y: 8 }
288
+ });
289
+ };
290
+
291
+ // Scroll behavior
292
+
293
+ this.OnReady(() =>
294
+ {
295
+ if(!this.scrollHide && !this.shrinkOnScroll)
296
+ {
297
+ return;
298
+ }
299
+
300
+ let lastY = window.scrollY;
301
+ const threshold = 8;
302
+ const shrinkAt = 20;
303
+
304
+ this.onScroll = () =>
305
+ {
306
+ const y = window.scrollY;
307
+
308
+ if(this.shrinkOnScroll)
309
+ {
310
+ this.shrunk = y > shrinkAt;
311
+ }
312
+
313
+ if(this.scrollHide)
314
+ {
315
+ if(y < 60)
316
+ {
317
+ this.hidden = false;
318
+ }
319
+ else if(Math.abs(y - lastY) > threshold)
320
+ {
321
+ this.hidden = y > lastY;
322
+ }
323
+ }
324
+
325
+ lastY = y;
326
+ };
327
+
328
+ window.addEventListener('scroll', this.onScroll, { passive: true });
329
+ });
330
+
331
+ this.OnDestroy(() =>
332
+ {
333
+ if(this.onScroll)
334
+ {
335
+ window.removeEventListener('scroll', this.onScroll);
336
+ }
337
+ });
338
+
339
+ return /* html */ `
340
+ <header :class="'holder ' + variant.join(' ') + (sticky ? ' sticky' : '') + (blur ? ' blur' : '') + (hidden ? ' hidden' : '') + (shrunk ? ' shrunk' : '') + (open ? ' open' : '')">
341
+ <div ot-if="hasBanner" class="banner">
342
+ <slot name="banner"></slot>
343
+ </div>
344
+
345
+ <div class="bar">
346
+ <div class="section left">
347
+ <a ot-if="hasLogo && !hasCrumbs" class="brand" :href="brandHref">
348
+ <img class="brand-logo" :src="logo" :alt="logoAlt" />
349
+ </a>
350
+
351
+ <nav ot-if="hasCrumbs" class="crumbs" aria-label="Breadcrumb">
352
+ <a
353
+ ot-for="crumb, index in crumbs"
354
+ :href="crumb.href || 'javascript:void(0)'"
355
+ class="crumb"
356
+ >
357
+ <i ot-if="crumb.icon">{{ crumb.icon }}</i>
358
+ <span ot-if="crumb.label">{{ crumb.label }}</span>
359
+ </a>
360
+ </nav>
361
+
362
+ <nav ot-if="left.length" class="nav left-nav">
363
+ <div ot-for="item in left">
364
+ <a
365
+ :class="'nav-item' + (item.active ? ' active' : '') + (item.disabled ? ' disabled' : '') + (item.hasChildren ? ' has-children' : '')"
366
+ :href="item.href || 'javascript:void(0)'"
367
+ :target="item.target || null"
368
+ ot-click="({ event }) => item.hasChildren && openDropdown(event, item)"
369
+ >
370
+ <i ot-if="item.icon">{{ item.icon }}</i>
371
+ <span ot-if="item.label">{{ item.label }}</span>
372
+ <span ot-if="item.badge != null" class="nav-badge">{{ item.badge }}</span>
373
+ <i ot-if="item.hasChildren" class="nav-chevron">expand_more</i>
374
+ </a>
375
+ </div>
376
+ </nav>
377
+ </div>
378
+
379
+ <div class="section right">
380
+ <nav ot-if="right.length" class="nav right-nav">
381
+ <div ot-for="item in right">
382
+ <a
383
+ :class="'nav-item' + (item.active ? ' active' : '') + (item.disabled ? ' disabled' : '') + (item.hasChildren ? ' has-children' : '')"
384
+ :href="item.href || 'javascript:void(0)'"
385
+ :target="item.target || null"
386
+ ot-click="({ event }) => item.hasChildren && openDropdown(event, item)"
387
+ >
388
+ <i ot-if="item.icon">{{ item.icon }}</i>
389
+ <span ot-if="item.label">{{ item.label }}</span>
390
+ <span ot-if="item.badge != null" class="nav-badge">{{ item.badge }}</span>
391
+ <i ot-if="item.hasChildren" class="nav-chevron">expand_more</i>
392
+ </a>
393
+ </div>
394
+ </nav>
395
+
396
+ <div ot-if="hasActions" class="actions">
397
+ <slot name="actions"></slot>
398
+ </div>
399
+
400
+ <a
401
+ ot-if="hasNotifications"
402
+ class="bell"
403
+ :href="notificationsHref || 'javascript:void(0)'"
404
+ >
405
+ <i>notifications</i>
406
+ <span ot-if="notifications > 0" class="bell-badge">{{ notifications > 99 ? '99+' : notifications }}</span>
407
+ </a>
408
+
409
+ <button
410
+ ot-if="hasUser"
411
+ type="button"
412
+ class="user-trigger"
413
+ ot-click="openUserMenu"
414
+ >
415
+ <div ot-if="user.avatar" class="user-avatar-small">
416
+ <img :src="user.avatar" :alt="user.name || ''" />
417
+ </div>
418
+ <div ot-if="!user.avatar" class="user-avatar-small user-avatar-fallback">
419
+ <i>person</i>
420
+ </div>
421
+ <div ot-if="hasUserMenu" class="user-chevron">
422
+ <i>expand_more</i>
423
+ </div>
424
+ </button>
425
+ </div>
426
+
427
+ <button class="burger" type="button" ot-click="toggleMobile" :aria-expanded="open">
428
+ <i>{{ open ? 'close' : 'menu' }}</i>
429
+ </button>
77
430
  </div>
78
- <div class="right">
79
- <a ot-for="item in right" :class="'tab' + (item.active ? ' active' : '')" :href="item.href" :target="item.target || null"><i>{{ item.icon }}</i> {{ item.label }}</a>
431
+
432
+ <div ot-if="open" class="drawer">
433
+ <div ot-if="hasUser" class="drawer-user">
434
+ <div ot-if="user.avatar" class="drawer-user-avatar">
435
+ <img :src="user.avatar" :alt="user.name || ''" />
436
+ </div>
437
+ <div ot-if="!user.avatar" class="drawer-user-avatar drawer-user-avatar-fallback">
438
+ <i>person</i>
439
+ </div>
440
+ <div class="drawer-user-text">
441
+ <span ot-if="user.name" class="drawer-user-name">{{ user.name }}</span>
442
+ <span ot-if="user.email" class="drawer-user-email">{{ user.email }}</span>
443
+ </div>
444
+ </div>
445
+
446
+ <nav class="drawer-nav">
447
+ <div ot-for="item in all">
448
+ <a
449
+ ot-if="!item.hasChildren"
450
+ :class="'drawer-item' + (item.active ? ' active' : '') + (item.disabled ? ' disabled' : '')"
451
+ :href="item.href || 'javascript:void(0)'"
452
+ :target="item.target || null"
453
+ ot-click="closeMobile"
454
+ >
455
+ <i ot-if="item.icon">{{ item.icon }}</i>
456
+ <span>{{ item.label }}</span>
457
+ <span ot-if="item.badge != null" class="drawer-badge">{{ item.badge }}</span>
458
+ </a>
459
+
460
+ <div ot-if="item.hasChildren" class="drawer-group">
461
+ <div class="drawer-group-head">
462
+ <i ot-if="item.icon">{{ item.icon }}</i>
463
+ <span>{{ item.label }}</span>
464
+ </div>
465
+ <a
466
+ ot-for="child in item.children"
467
+ :href="child.href || 'javascript:void(0)'"
468
+ class="drawer-child"
469
+ ot-click="closeMobile"
470
+ >
471
+ <i ot-if="child.icon">{{ child.icon }}</i>
472
+ <span>{{ child.label }}</span>
473
+ </a>
474
+ </div>
475
+ </div>
476
+ </nav>
477
+
478
+ <div ot-if="hasUserMenu" class="drawer-user-menu">
479
+ <div ot-for="entry in userMenu">
480
+ <div ot-if="entry.separator" class="drawer-separator"></div>
481
+ <a
482
+ ot-if="!entry.separator"
483
+ :href="entry.href || 'javascript:void(0)'"
484
+ class="drawer-item"
485
+ ot-click="closeMobile"
486
+ >
487
+ <i ot-if="entry.icon">{{ entry.icon }}</i>
488
+ <span>{{ entry.label }}</span>
489
+ </a>
490
+ </div>
491
+ </div>
80
492
  </div>
81
- <button class="burger" ot-click="toggle"><i>{{ open ? 'close' : 'menu' }}</i></button>
82
- </nav>
83
- <div ot-if="open" class="menu">
84
- <a ot-for="item in all" :class="'link' + (item.active ? ' active' : '')" :href="item.href" :target="item.target || null"><i>{{ item.icon }}</i> {{ item.label }}</a>
85
- </div>
493
+ </header>
86
494
  `;
87
495
  }
88
496
  });