@awes-io/ui 2.142.3 → 2.144.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.
Files changed (264) hide show
  1. package/assets/css/components/_index.css +7 -1
  2. package/assets/css/components/action-card.css +1 -0
  3. package/assets/css/components/action-icon.css +2 -2
  4. package/assets/css/components/alert.css +28 -22
  5. package/assets/css/components/animation.css +52 -32
  6. package/assets/css/components/badge.css +1 -0
  7. package/assets/css/components/banner-text.css +15 -4
  8. package/assets/css/components/card.css +0 -1
  9. package/assets/css/components/content-placeholder.css +104 -0
  10. package/assets/css/components/dropdown.css +20 -7
  11. package/assets/css/components/empty-container.css +69 -1
  12. package/assets/css/components/filter-chosen.css +6 -0
  13. package/assets/css/components/filter-date-range.css +17 -1
  14. package/assets/css/components/filter-month.css +23 -17
  15. package/assets/css/components/filter-select.css +11 -0
  16. package/assets/css/components/icon-menu-item.css +12 -7
  17. package/assets/css/components/layout.css +1 -32
  18. package/assets/css/components/mobile-menu-nav.css +8 -4
  19. package/assets/css/components/modal.css +1 -1
  20. package/assets/css/components/number.css +12 -0
  21. package/assets/css/components/page-aside.css +54 -0
  22. package/assets/css/components/text-field.css +4 -0
  23. package/assets/js/css.js +1 -1
  24. package/assets/js/icons/mono.js +59 -91
  25. package/assets/js/icons/multicolor.js +1 -31
  26. package/components/1_atoms/AwActionIcon.vue +11 -2
  27. package/components/1_atoms/AwContentPlaceholder.vue +60 -0
  28. package/components/1_atoms/AwFlow.vue +37 -49
  29. package/components/1_atoms/AwGrid.vue +11 -3
  30. package/components/1_atoms/AwIcon/AwIcon.vue +5 -3
  31. package/components/1_atoms/AwIcon/AwIconSystemMono.vue +3 -2
  32. package/components/1_atoms/AwInput.vue +2 -2
  33. package/components/1_atoms/AwLabel.vue +1 -1
  34. package/components/1_atoms/AwList.vue +3 -1
  35. package/components/1_atoms/AwRadio.vue +1 -1
  36. package/components/1_atoms/AwSlider.vue +15 -1
  37. package/components/1_atoms/AwTag.vue +6 -1
  38. package/components/2_molecules/AwAlert.vue +63 -42
  39. package/components/2_molecules/AwBadge.vue +1 -1
  40. package/components/2_molecules/AwBannerText.vue +8 -2
  41. package/components/2_molecules/AwButton.vue +1 -1
  42. package/components/2_molecules/AwDescriptionInput.vue +19 -1
  43. package/components/2_molecules/AwEmptyContainer.vue +74 -72
  44. package/components/2_molecules/AwNumber.vue +180 -0
  45. package/components/2_molecules/AwSelect.vue +11 -4
  46. package/components/3_organisms/AwBottomBar.vue +22 -4
  47. package/components/3_organisms/AwFilterChosen.vue +73 -0
  48. package/components/3_organisms/AwFilterDateRange.vue +177 -0
  49. package/components/3_organisms/AwFilterMonth.vue +37 -40
  50. package/components/3_organisms/AwFilterSelect.vue +368 -0
  51. package/components/3_organisms/AwMultiBlockBuilder.vue +1 -1
  52. package/components/3_organisms/AwSubnav.vue +11 -1
  53. package/components/3_organisms/AwTable/AwTableBuilder.vue +20 -60
  54. package/components/3_organisms/AwTable/_AwTableCellDropdown.vue +6 -1
  55. package/components/3_organisms/AwTable/_AwTableRow.vue +2 -1
  56. package/components/4_pages/AwPage.vue +1 -0
  57. package/components/4_pages/AwPageAside.vue +108 -0
  58. package/components/5_layouts/AwLayoutCenter.vue +3 -8
  59. package/components/5_layouts/_AwMenuItemIcon.vue +9 -2
  60. package/components/5_layouts/_AwMobileMenuItem.vue +5 -3
  61. package/components/5_layouts/_AwUserMenu.vue +1 -1
  62. package/components/_config.js +26 -1
  63. package/docs/_template.md +80 -0
  64. package/docs/components/atoms/aw-accordion-fold.md +129 -0
  65. package/docs/components/atoms/aw-action-card-body.md +99 -0
  66. package/docs/components/atoms/aw-action-card.md +130 -0
  67. package/docs/components/atoms/aw-action-icon.md +126 -0
  68. package/docs/components/atoms/aw-avatar.md +106 -0
  69. package/docs/components/atoms/aw-card.md +137 -0
  70. package/docs/components/atoms/aw-checkbox.md +288 -0
  71. package/docs/components/atoms/aw-content-placeholder.md +147 -0
  72. package/docs/components/atoms/aw-description.md +83 -0
  73. package/docs/components/atoms/aw-dock.md +90 -0
  74. package/docs/components/atoms/aw-dropdown-button.md +94 -0
  75. package/docs/components/atoms/aw-dropdown.md +178 -0
  76. package/docs/components/atoms/aw-file.md +73 -0
  77. package/docs/components/atoms/aw-flow.md +140 -0
  78. package/docs/components/atoms/aw-grid.md +109 -0
  79. package/docs/components/atoms/aw-headline.md +71 -0
  80. package/docs/components/atoms/aw-icon-system-color.md +122 -0
  81. package/docs/components/atoms/aw-icon-system-mono.md +206 -0
  82. package/docs/components/atoms/aw-icon.md +235 -0
  83. package/docs/components/atoms/aw-info.md +123 -0
  84. package/docs/components/atoms/aw-input.md +212 -0
  85. package/docs/components/atoms/aw-label.md +136 -0
  86. package/docs/components/atoms/aw-link.md +151 -0
  87. package/docs/components/atoms/aw-list.md +152 -0
  88. package/docs/components/atoms/aw-progress.md +119 -0
  89. package/docs/components/atoms/aw-radio.md +182 -0
  90. package/docs/components/atoms/aw-refresh-wrapper.md +81 -0
  91. package/docs/components/atoms/aw-select-native.md +234 -0
  92. package/docs/components/atoms/aw-slider.md +189 -0
  93. package/docs/components/atoms/aw-sub-headline.md +73 -0
  94. package/docs/components/atoms/aw-switcher.md +192 -0
  95. package/docs/components/atoms/aw-tag.md +144 -0
  96. package/docs/components/atoms/aw-title.md +70 -0
  97. package/docs/components/atoms/aw-toggler.md +90 -0
  98. package/docs/components/layouts/aw-layout-center.md +168 -0
  99. package/docs/components/layouts/aw-layout-error.md +153 -0
  100. package/docs/components/layouts/aw-layout-provider.md +238 -0
  101. package/docs/components/layouts/aw-layout.md +88 -0
  102. package/docs/components/molecules/aw-action-button.md +138 -0
  103. package/docs/components/molecules/aw-alert.md +191 -0
  104. package/docs/components/molecules/aw-badge.md +129 -0
  105. package/docs/components/molecules/aw-banner-text.md +156 -0
  106. package/docs/components/molecules/aw-button-nav.md +111 -0
  107. package/docs/components/molecules/aw-button.md +193 -0
  108. package/docs/components/molecules/aw-description-input.md +124 -0
  109. package/docs/components/molecules/aw-empty-container.md +235 -0
  110. package/docs/components/molecules/aw-island.md +506 -0
  111. package/docs/components/molecules/aw-number.md +138 -0
  112. package/docs/components/molecules/aw-select-object.md +401 -0
  113. package/docs/components/molecules/aw-select.md +215 -0
  114. package/docs/components/molecules/aw-tab-nav.md +108 -0
  115. package/docs/components/molecules/aw-tel.md +129 -0
  116. package/docs/components/molecules/aw-textarea.md +83 -0
  117. package/docs/components/molecules/aw-userpic.md +115 -0
  118. package/docs/components/organisms/aw-address-block.md +64 -0
  119. package/docs/components/organisms/aw-address.md +132 -0
  120. package/docs/components/organisms/aw-birthday-picker.md +73 -0
  121. package/docs/components/organisms/aw-bottom-bar.md +66 -0
  122. package/docs/components/organisms/aw-calendar-days.md +115 -0
  123. package/docs/components/organisms/aw-calendar-nav.md +98 -0
  124. package/docs/components/organisms/aw-calendar-view.md +98 -0
  125. package/docs/components/organisms/aw-calendar.md +166 -0
  126. package/docs/components/organisms/aw-chart.md +154 -0
  127. package/docs/components/organisms/aw-chip-select.md +164 -0
  128. package/docs/components/organisms/aw-chip.md +126 -0
  129. package/docs/components/organisms/aw-code-snippet.md +94 -0
  130. package/docs/components/organisms/aw-code.md +132 -0
  131. package/docs/components/organisms/aw-context-menu.md +117 -0
  132. package/docs/components/organisms/aw-cropper.md +151 -0
  133. package/docs/components/organisms/aw-date.md +161 -0
  134. package/docs/components/organisms/aw-display-date.md +33 -0
  135. package/docs/components/organisms/aw-download-link.md +46 -0
  136. package/docs/components/organisms/aw-fetch-data.md +161 -0
  137. package/docs/components/organisms/aw-filter-chosen.md +226 -0
  138. package/docs/components/organisms/aw-filter-date-range.md +205 -0
  139. package/docs/components/organisms/aw-filter-month.md +43 -0
  140. package/docs/components/organisms/aw-filter-select.md +239 -0
  141. package/docs/components/organisms/aw-form.md +174 -0
  142. package/docs/components/organisms/aw-gmap-marker.md +86 -0
  143. package/docs/components/organisms/aw-gmap.md +90 -0
  144. package/docs/components/organisms/aw-image-upload.md +56 -0
  145. package/docs/components/organisms/aw-island-avatar.md +87 -0
  146. package/docs/components/organisms/aw-markdown-editor.md +104 -0
  147. package/docs/components/organisms/aw-modal-buttons.md +57 -0
  148. package/docs/components/organisms/aw-modal.md +246 -0
  149. package/docs/components/organisms/aw-model-edit.md +74 -0
  150. package/docs/components/organisms/aw-money.md +53 -0
  151. package/docs/components/organisms/aw-multi-block-builder.md +165 -0
  152. package/docs/components/organisms/aw-pagination.md +121 -0
  153. package/docs/components/organisms/aw-password.md +103 -0
  154. package/docs/components/organisms/aw-preview-card.md +45 -0
  155. package/docs/components/organisms/aw-search.md +116 -0
  156. package/docs/components/organisms/aw-subnav.md +122 -0
  157. package/docs/components/organisms/aw-table-builder.md +165 -0
  158. package/docs/components/organisms/aw-table-col.md +123 -0
  159. package/docs/components/organisms/aw-table-head.md +92 -0
  160. package/docs/components/organisms/aw-table-row.md +91 -0
  161. package/docs/components/organisms/aw-table.md +172 -0
  162. package/docs/components/organisms/aw-tags.md +54 -0
  163. package/docs/components/organisms/aw-toggle-show-aside.md +43 -0
  164. package/docs/components/organisms/aw-uploader-files.md +125 -0
  165. package/docs/components/organisms/aw-uploader.md +163 -0
  166. package/docs/components/organisms/aw-user-menu.md +87 -0
  167. package/docs/components/pages/aw-page-aside.md +296 -0
  168. package/docs/components/pages/aw-page-menu-buttons.md +172 -0
  169. package/docs/components/pages/aw-page-modal.md +198 -0
  170. package/docs/components/pages/aw-page-single.md +300 -0
  171. package/docs/components/pages/aw-page.md +194 -0
  172. package/docs/configuration.md +493 -0
  173. package/docs/cookbook/advanced-patterns.md +1388 -0
  174. package/docs/cookbook/common-patterns.md +965 -0
  175. package/docs/cookbook/index.md +786 -0
  176. package/docs/getting-started.md +596 -0
  177. package/docs/guides/best-practices.md +1106 -0
  178. package/docs/guides/data-fetching.md +852 -0
  179. package/docs/guides/error-handling.md +1172 -0
  180. package/docs/guides/forms-guide.md +1329 -0
  181. package/docs/guides/mobile-subnavigation.md +359 -0
  182. package/docs/guides/page-patterns/aside-pages.md +1418 -0
  183. package/docs/guides/page-patterns/dashboard-pages.md +990 -0
  184. package/docs/guides/page-patterns/detail-pages.md +1556 -0
  185. package/docs/guides/page-patterns/list-pages.md +1242 -0
  186. package/docs/index.md +263 -1
  187. package/docs/integrations.md +870 -0
  188. package/docs/reference/colors.md +232 -0
  189. package/docs/reference/icons.md +163 -0
  190. package/docs/reference/menu.md +462 -0
  191. package/docs/reference/plugins.md +970 -0
  192. package/docs/reference/troubleshooting.md +964 -0
  193. package/nuxt/awes.config.js +9 -8
  194. package/nuxt/index.js +2 -2
  195. package/nuxt/pages/more.vue +1 -1
  196. package/package.json +5 -3
  197. package/readme.md +171 -1
  198. package/store/awesIo.js +11 -0
  199. package/CHANGELOG.md +0 -4520
  200. package/docs/aw-accordion-fold.md +0 -46
  201. package/docs/aw-address.md +0 -44
  202. package/docs/aw-avatar.md +0 -51
  203. package/docs/aw-badge.md +0 -32
  204. package/docs/aw-button-nav.md +0 -44
  205. package/docs/aw-button.md +0 -50
  206. package/docs/aw-calendar-days.md +0 -46
  207. package/docs/aw-calendar-nav.md +0 -25
  208. package/docs/aw-calendar-view.md +0 -12
  209. package/docs/aw-calendar.md +0 -59
  210. package/docs/aw-card.md +0 -48
  211. package/docs/aw-chart.md +0 -51
  212. package/docs/aw-checkbox.md +0 -56
  213. package/docs/aw-chip-select.md +0 -46
  214. package/docs/aw-chip.md +0 -53
  215. package/docs/aw-code-snippet.md +0 -18
  216. package/docs/aw-code.md +0 -56
  217. package/docs/aw-content-wrapper.md +0 -40
  218. package/docs/aw-context-menu.md +0 -31
  219. package/docs/aw-cropper.md +0 -60
  220. package/docs/aw-dashboard-card.md +0 -37
  221. package/docs/aw-dashboard-donut.md +0 -30
  222. package/docs/aw-dashboard-line.md +0 -20
  223. package/docs/aw-dashboard-progress.md +0 -33
  224. package/docs/aw-dashboard-section.md +0 -32
  225. package/docs/aw-dashboard-speed.md +0 -30
  226. package/docs/aw-date.md +0 -52
  227. package/docs/aw-dropdown-button.md +0 -31
  228. package/docs/aw-dropdown.md +0 -69
  229. package/docs/aw-fetch-data.md +0 -45
  230. package/docs/aw-form.md +0 -52
  231. package/docs/aw-grid.md +0 -48
  232. package/docs/aw-icon.md +0 -50
  233. package/docs/aw-info.md +0 -53
  234. package/docs/aw-input.md +0 -55
  235. package/docs/aw-layout-default.md +0 -30
  236. package/docs/aw-layout-frame-center.md +0 -29
  237. package/docs/aw-layout-simple.md +0 -49
  238. package/docs/aw-link.md +0 -54
  239. package/docs/aw-markdown-editor.md +0 -51
  240. package/docs/aw-modal.md +0 -63
  241. package/docs/aw-multi-block-builder.md +0 -66
  242. package/docs/aw-page.md +0 -36
  243. package/docs/aw-pagination.md +0 -54
  244. package/docs/aw-password.md +0 -48
  245. package/docs/aw-radio.md +0 -54
  246. package/docs/aw-search.md +0 -49
  247. package/docs/aw-select.md +0 -93
  248. package/docs/aw-slider.md +0 -40
  249. package/docs/aw-svg-image.md +0 -19
  250. package/docs/aw-switcher.md +0 -51
  251. package/docs/aw-tab-nav.md +0 -55
  252. package/docs/aw-table-builder.md +0 -58
  253. package/docs/aw-table-col.md +0 -33
  254. package/docs/aw-table-head.md +0 -28
  255. package/docs/aw-table-row.md +0 -33
  256. package/docs/aw-table.md +0 -59
  257. package/docs/aw-tel.md +0 -47
  258. package/docs/aw-textarea.md +0 -47
  259. package/docs/aw-toggler.md +0 -41
  260. package/docs/aw-uploader-files.md +0 -20
  261. package/docs/aw-uploader.md +0 -60
  262. package/docs/aw-user-menu.md +0 -34
  263. package/docs/aw-userpic.md +0 -34
  264. /package/components/{3_organisms → 2_molecules}/AwTel.vue +0 -0
@@ -0,0 +1,1106 @@
1
+ # Best Practices Guide
2
+
3
+ Comprehensive best practices for building AwesCode UI applications with UI components, vue-mc models, and Laravel backend integration.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Component Communication](#component-communication)
8
+ 2. [Loading States & Progress](#loading-states--progress)
9
+ 3. [Data Management](#data-management)
10
+ 4. [Error Handling](#error-handling)
11
+ 5. [User Feedback](#user-feedback)
12
+ 6. [Date Formatting](#date-formatting)
13
+ 7. [Component Imports](#component-imports)
14
+ 8. [Accessibility](#accessibility)
15
+ 9. [Performance](#performance)
16
+ 10. [Styling](#styling)
17
+ 11. [Table Patterns](#table-patterns)
18
+ 12. [Navigation](#navigation)
19
+
20
+ ---
21
+
22
+ ## Component Communication
23
+
24
+ ### Event-Driven Architecture
25
+
26
+ Use events for parent-child communication with specific, descriptive event names.
27
+
28
+ #### ✅ Good: Specific Events with Clear Data
29
+
30
+ ```markup
31
+ <!-- Child Component -->
32
+ <script>
33
+ export default {
34
+ methods: {
35
+ selectDescription(description) {
36
+ this.$emit('description-selected', description)
37
+ },
38
+
39
+ updateTranslations(translations) {
40
+ this.$emit('translations-generated', translations)
41
+ },
42
+
43
+ updateStatus(generating, text) {
44
+ this.$emit('ai-status-changed', {
45
+ generating,
46
+ statusText: text
47
+ })
48
+ }
49
+ }
50
+ }
51
+ </script>
52
+
53
+ <!-- Parent Component -->
54
+ <template>
55
+ <AIAssistant
56
+ @description-selected="handleDescription"
57
+ @translations-generated="handleTranslations"
58
+ @ai-status-changed="handleStatus"
59
+ />
60
+ </template>
61
+ ```
62
+
63
+ #### ❌ Bad: Generic Events with Unclear Data
64
+
65
+ ```javascript
66
+ // ❌ WRONG - Generic event name
67
+ this.$emit('change', someData)
68
+
69
+ // ❌ WRONG - Type discrimination in payload
70
+ this.$emit('update', { type: 'description', value: description })
71
+
72
+ // ❌ WRONG - No data context
73
+ this.$emit('done')
74
+ ```
75
+
76
+ ### Props vs Events
77
+
78
+ **Props down, events up:**
79
+ - Use props to pass data to child components
80
+ - Use events to notify parent of changes
81
+ - Never mutate props directly in child
82
+
83
+ ```markup
84
+ <!-- ✅ GOOD -->
85
+ <script>
86
+ export default {
87
+ props: {
88
+ value: String
89
+ },
90
+
91
+ methods: {
92
+ updateValue(newValue) {
93
+ this.$emit('input', newValue) // Emit event
94
+ }
95
+ }
96
+ }
97
+ </script>
98
+
99
+ <!-- ❌ BAD -->
100
+ <script>
101
+ export default {
102
+ props: {
103
+ value: String
104
+ },
105
+
106
+ methods: {
107
+ updateValue(newValue) {
108
+ this.value = newValue // ❌ Never mutate props
109
+ }
110
+ }
111
+ }
112
+ </script>
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Loading States & Progress
118
+
119
+ ### Button Loading States
120
+
121
+ Always use the `:loading` prop for AwButton.
122
+
123
+ #### ✅ Good: Simple Loading State
124
+
125
+ ```markup
126
+ <AwButton
127
+ :loading="isLoading"
128
+ @click="handleAction"
129
+ text="Save"
130
+ />
131
+
132
+ <script>
133
+ export default {
134
+ data() {
135
+ return {
136
+ isLoading: false
137
+ }
138
+ },
139
+
140
+ methods: {
141
+ async handleAction() {
142
+ this.isLoading = true
143
+ try {
144
+ await this.performAction()
145
+ } finally {
146
+ this.isLoading = false
147
+ }
148
+ }
149
+ }
150
+ }
151
+ </script>
152
+ ```
153
+
154
+ #### ❌ Bad: Conditional Text Inside Button
155
+
156
+ ```markup
157
+ <!-- ❌ WRONG - Button handles loading text automatically -->
158
+ <AwButton :loading="isLoading">
159
+ <span v-if="isLoading">Loading...</span>
160
+ <span v-else>Save</span>
161
+ </AwButton>
162
+ ```
163
+
164
+ ### Custom Button Styles with Loading
165
+
166
+ When styling buttons, exclude loading state from custom CSS:
167
+
168
+ ```scss
169
+ /* ✅ GOOD - Excludes loading state */
170
+ .custom-btn:not([disabled]):not(.loading) {
171
+ background-color: var(--c-accent) !important;
172
+ border-color: var(--c-accent) !important;
173
+ }
174
+
175
+ .custom-btn:hover:not([disabled]):not(.loading) {
176
+ filter: brightness(1.1) !important;
177
+ }
178
+
179
+ /* ❌ BAD - Overrides loading styles */
180
+ .custom-btn {
181
+ background: red !important;
182
+ }
183
+ ```
184
+
185
+ ### Model Loading States
186
+
187
+ Vue-mc models provide automatic loading states:
188
+
189
+ ```markup
190
+ <template>
191
+ <AwPageSingle
192
+ :title="pageTitle"
193
+ :action="saveButton"
194
+ @action="save"
195
+ >
196
+ <!-- Form content -->
197
+ </AwPageSingle>
198
+ </template>
199
+
200
+ <script>
201
+ export default {
202
+ computed: {
203
+ saveButton() {
204
+ return {
205
+ text: 'Save',
206
+ loading: this.model.saving // ✅ Automatic from vue-mc
207
+ }
208
+ }
209
+ }
210
+ }
211
+ </script>
212
+ ```
213
+
214
+ ### Page Progress Indicator
215
+
216
+ Use the built-in `progress` prop for long operations:
217
+
218
+ ```markup
219
+ <template>
220
+ <AwPageSingle
221
+ :title="pageTitle"
222
+ :action="saveButton"
223
+ :progress="isProcessing ? uploadProgress : null"
224
+ @action="save"
225
+ >
226
+ <!-- Page content -->
227
+ </AwPageSingle>
228
+ </template>
229
+
230
+ <script>
231
+ export default {
232
+ data() {
233
+ return {
234
+ uploadProgress: 0,
235
+ isProcessing: false
236
+ }
237
+ },
238
+
239
+ computed: {
240
+ saveButton() {
241
+ return {
242
+ key: 'save',
243
+ label: 'Save',
244
+ loading: this.model.saving,
245
+ color: 'accent'
246
+ }
247
+ }
248
+ },
249
+
250
+ methods: {
251
+ async handleAction(action) {
252
+ if (action.key === 'save') {
253
+ await this.save()
254
+ }
255
+ }
256
+ }
257
+ }
258
+ </script>
259
+ ```
260
+
261
+ **Note:** For custom status indicators (AI generating, etc.), you can still use the `#buttons` slot alongside the action prop for non-action UI elements.
262
+
263
+ ---
264
+
265
+ ## Data Management
266
+
267
+ ### Collection Initialization
268
+
269
+ Collections always take 2 arguments: `(models, options)`
270
+
271
+ #### ✅ Good: Proper Collection Initialization
272
+
273
+ ```javascript
274
+ import Customers from '~/collections/Customers'
275
+
276
+ export default {
277
+ data() {
278
+ return {
279
+ customers: new Customers([], {
280
+ shop_uuid: this.$route.params.shop_uuid
281
+ })
282
+ }
283
+ }
284
+ }
285
+ ```
286
+
287
+ #### ❌ Bad: Missing Options
288
+
289
+ ```javascript
290
+ // ❌ WRONG - Missing shop_uuid
291
+ customers: new Customers([])
292
+
293
+ // ❌ WRONG - Only one argument
294
+ customers: new Customers()
295
+ ```
296
+
297
+ ### Model Initialization
298
+
299
+ Models take 3 arguments: `(attributes, collection, options)`
300
+
301
+ #### ✅ Good: Proper Model Initialization
302
+
303
+ ```javascript
304
+ import Customer from '~/models/Customer'
305
+
306
+ export default {
307
+ data() {
308
+ return {
309
+ // New model
310
+ customer: new Customer(
311
+ {}, // Empty attributes
312
+ null, // No parent collection
313
+ { shop_uuid: this.$route.params.shop_uuid }
314
+ ),
315
+
316
+ // Existing model
317
+ customer: new Customer(
318
+ { id: this.$route.params.id }, // ID from route
319
+ null,
320
+ { shop_uuid: this.$route.params.shop_uuid }
321
+ )
322
+ }
323
+ }
324
+ }
325
+ ```
326
+
327
+ #### ❌ Bad: Wrong Number of Arguments
328
+
329
+ ```javascript
330
+ // ❌ WRONG - Only one argument
331
+ customer: new Customer({ id: 1 })
332
+
333
+ // ❌ WRONG - Missing options
334
+ customer: new Customer({ id: 1 }, null)
335
+ ```
336
+
337
+ ### Always Include shop_uuid
338
+
339
+ ```javascript
340
+ // ✅ GOOD - Shop UUID in options
341
+ customers: new Customers([], {
342
+ shop_uuid: this.$route.params.shop_uuid
343
+ })
344
+
345
+ // ❌ BAD - No shop UUID
346
+ customers: new Customers([])
347
+ ```
348
+
349
+ ### Use Standard vue-mc Methods
350
+
351
+ Don't create custom methods that duplicate vue-mc functionality:
352
+
353
+ ```javascript
354
+ // ✅ GOOD - Use standard vue-mc methods
355
+ if (this.customers.isEmpty()) {
356
+ // Collection is empty
357
+ }
358
+
359
+ if (Object.keys(this.model.errors).length > 0) {
360
+ // Model has validation errors
361
+ }
362
+
363
+ // ❌ BAD - Custom methods
364
+ if (this.customers.hasItems()) { // ❌ Use isEmpty() instead
365
+ }
366
+
367
+ if (this.model.hasErrors()) { // ❌ Use Object.keys(errors).length > 0 instead
368
+ }
369
+ ```
370
+
371
+ ### AwTableBuilder Automatically Fetches
372
+
373
+ Don't manually fetch when using AwTableBuilder:
374
+
375
+ ```markup
376
+ <!-- ✅ GOOD - Let AwTableBuilder handle fetching -->
377
+ <template>
378
+ <AwTableBuilder :collection="customers">
379
+ <AwTableCol field="name" title="Name" />
380
+ </AwTableBuilder>
381
+ </template>
382
+
383
+ <script>
384
+ export default {
385
+ data() {
386
+ return {
387
+ customers: new Customers([], {
388
+ shop_uuid: this.$route.params.shop_uuid
389
+ })
390
+ }
391
+ }
392
+ // No fetch() or mounted() needed!
393
+ }
394
+ </script>
395
+
396
+ <!-- ❌ BAD - Manual fetch not needed -->
397
+ <script>
398
+ export default {
399
+ async mounted() {
400
+ await this.customers.fetch() // ❌ Unnecessary!
401
+ }
402
+ }
403
+ </script>
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Error Handling
409
+
410
+ ### Field-Level Validation
411
+
412
+ Always bind `:error` prop to model errors:
413
+
414
+ ```markup
415
+ <AwInput
416
+ v-model="model.name"
417
+ label="Name"
418
+ :error="model.errors.name"
419
+ required
420
+ />
421
+
422
+ <AwInput
423
+ v-model="model.email"
424
+ label="Email"
425
+ :error="model.errors.email"
426
+ required
427
+ />
428
+ ```
429
+
430
+ ### Check Errors After Save
431
+
432
+ Always check for validation errors after saving:
433
+
434
+ ```javascript
435
+ async save() {
436
+ try {
437
+ await this.model.save()
438
+
439
+ // ✅ GOOD - Check for errors
440
+ if (Object.keys(this.model.errors).length > 0) {
441
+ this.$notify({
442
+ message: 'Please fix validation errors',
443
+ type: 'error'
444
+ })
445
+ return
446
+ }
447
+
448
+ // Success path
449
+ this.$notify({
450
+ message: 'Saved successfully',
451
+ type: 'success'
452
+ })
453
+ this.$router.push('/list')
454
+ } catch (error) {
455
+ this.$notify({
456
+ message: 'Failed to save',
457
+ type: 'error'
458
+ })
459
+ }
460
+ }
461
+ ```
462
+
463
+ ### Handle Fetch Errors
464
+
465
+ Redirect or show error when fetch fails:
466
+
467
+ ```javascript
468
+ async mounted() {
469
+ if (!this.model.isNew()) {
470
+ try {
471
+ await this.model.fetch()
472
+ } catch (error) {
473
+ // 404 - Record not found
474
+ if (error.response?.status === 404) {
475
+ this.$notify({
476
+ message: 'Record not found',
477
+ type: 'error'
478
+ })
479
+ this.$router.push('/list')
480
+ return
481
+ }
482
+
483
+ // Other errors
484
+ this.$notify({
485
+ message: 'Failed to load data',
486
+ type: 'error'
487
+ })
488
+ }
489
+ }
490
+ }
491
+ ```
492
+
493
+ ### Try-Catch for API Calls
494
+
495
+ Always wrap API calls in try-catch:
496
+
497
+ ```javascript
498
+ async performAction() {
499
+ try {
500
+ const { data } = await this.$axios.post('/api/action', this.payload)
501
+ this.handleSuccess(data)
502
+ } catch (error) {
503
+ console.error('Action failed:', error)
504
+
505
+ // User-friendly error message
506
+ this.$notify({
507
+ message: error.response?.data?.message || 'Action failed. Please try again.',
508
+ type: 'error'
509
+ })
510
+ }
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ## User Feedback
517
+
518
+ ### Notifications
519
+
520
+ Use `$notify` for user feedback:
521
+
522
+ ```javascript
523
+ // Success
524
+ this.$notify({
525
+ message: 'Customer created successfully',
526
+ type: 'success'
527
+ })
528
+
529
+ // Error
530
+ this.$notify({
531
+ message: 'Failed to delete item',
532
+ type: 'error'
533
+ })
534
+
535
+ // Warning
536
+ this.$notify({
537
+ message: 'Changes not saved',
538
+ type: 'warning'
539
+ })
540
+
541
+ // Info
542
+ this.$notify({
543
+ message: 'Email sent',
544
+ type: 'info'
545
+ })
546
+ ```
547
+
548
+ ### Confirmations
549
+
550
+ Use `$confirm` for destructive actions:
551
+
552
+ ```javascript
553
+ async deleteItem(item) {
554
+ const confirmed = await this.$confirm({
555
+ title: 'Delete Customer',
556
+ message: `Are you sure you want to delete "${item.name}"?`
557
+ })
558
+
559
+ if (!confirmed) return
560
+
561
+ try {
562
+ await this.$axios.delete(`/api/customers/${item.id}`)
563
+ this.$notify({
564
+ message: 'Customer deleted successfully',
565
+ type: 'success'
566
+ })
567
+ this.customers.fetch()
568
+ } catch (error) {
569
+ this.$notify({
570
+ message: 'Failed to delete customer',
571
+ type: 'error'
572
+ })
573
+ }
574
+ }
575
+ ```
576
+
577
+ ### Success Feedback After Actions
578
+
579
+ Always provide feedback after user actions:
580
+
581
+ ```javascript
582
+ // ✅ GOOD - Clear feedback
583
+ async save() {
584
+ await this.model.save()
585
+
586
+ if (Object.keys(this.model.errors).length > 0) {
587
+ this.$notify({
588
+ message: 'Please fix validation errors',
589
+ type: 'error'
590
+ })
591
+ return
592
+ }
593
+
594
+ this.$notify({
595
+ message: `Customer ${this.model.isNew() ? 'created' : 'updated'} successfully`,
596
+ type: 'success'
597
+ })
598
+
599
+ this.$router.push('/customers')
600
+ }
601
+
602
+ // ❌ BAD - No feedback
603
+ async save() {
604
+ await this.model.save()
605
+ this.$router.push('/customers') // User doesn't know if it succeeded
606
+ }
607
+ ```
608
+
609
+ ---
610
+
611
+ ## Date Formatting
612
+
613
+ ### Always Use $dayjs
614
+
615
+ Use `$dayjs` in templates (without `this`):
616
+
617
+ ```markup
618
+ <!-- ✅ GOOD - Using $dayjs in templates -->
619
+ <template>
620
+ <div>
621
+ <!-- Short date -->
622
+ {{ $dayjs(cell.created_at).format('ll') }}
623
+
624
+ <!-- Date with time -->
625
+ {{ $dayjs(cell.updated_at).format('lll') }}
626
+
627
+ <!-- Month and year -->
628
+ {{ $dayjs(date).format('MMMM YYYY') }}
629
+
630
+ <!-- Relative time -->
631
+ {{ $dayjs(cell.created_at).fromNow() }}
632
+ </div>
633
+ </template>
634
+ ```
635
+
636
+ Use `this.$dayjs` in methods (with `this`):
637
+
638
+ ```javascript
639
+ export default {
640
+ methods: {
641
+ // ✅ GOOD - Using this.$dayjs in methods
642
+ formatMonth(monthString) {
643
+ return this.$dayjs(monthString).format('MMMM YYYY')
644
+ },
645
+
646
+ isRecent(date) {
647
+ return this.$dayjs(date).isAfter(
648
+ this.$dayjs().subtract(7, 'days')
649
+ )
650
+ }
651
+ }
652
+ }
653
+ ```
654
+
655
+ ### ❌ Bad: Native Date Methods
656
+
657
+ ```markup
658
+ <!-- ❌ WRONG - Using native Date -->
659
+ {{ new Date(cell.created_at).toLocaleDateString() }}
660
+
661
+ <!-- ❌ WRONG - Using toLocaleDateString -->
662
+ {{ date.toLocaleDateString('en-US', { year: 'numeric', month: 'short' }) }}
663
+ ```
664
+
665
+ ### Common Date Formats
666
+
667
+ | Format | Code | Example |
668
+ |--------|------|---------|
669
+ | Short date | `$dayjs(date).format('ll')` | Jan 15, 2024 |
670
+ | Date with time | `$dayjs(date).format('lll')` | Jan 15, 2024 10:30 AM |
671
+ | Long date | `$dayjs(date).format('LL')` | January 15, 2024 |
672
+ | Month and year | `$dayjs(date).format('MMMM YYYY')` | January 2024 |
673
+ | Short month/year | `$dayjs(date).format('MMM YYYY')` | Jan 2024 |
674
+ | Relative time | `$dayjs(date).fromNow()` | 2 hours ago |
675
+
676
+ ---
677
+
678
+ ## Component Imports
679
+
680
+ ### Auto-Imported Components
681
+
682
+ Atoms and molecules are globally registered:
683
+
684
+ ```markup
685
+ <!-- ✅ GOOD - No import needed for global components -->
686
+ <template>
687
+ <div>
688
+ <AwButton text="Click me" />
689
+ <AwInput v-model="value" />
690
+ <AwCard title="Card Title">
691
+ Content
692
+ </AwCard>
693
+ </div>
694
+ </template>
695
+
696
+ <!-- No imports needed! -->
697
+ ```
698
+
699
+ ### Manual Imports
700
+
701
+ Collections, models, and utilities must be imported:
702
+
703
+ ```markup
704
+ <script>
705
+ // ✅ GOOD - Import collections and models
706
+ import Customers from '~/collections/Customers'
707
+ import Customer from '~/models/Customer'
708
+
709
+ export default {
710
+ data() {
711
+ return {
712
+ customers: new Customers([], {
713
+ shop_uuid: this.$route.params.shop_uuid
714
+ }),
715
+ customer: new Customer()
716
+ }
717
+ }
718
+ }
719
+ </script>
720
+ ```
721
+
722
+ ### Components from /components/
723
+
724
+ Components in your project's `/components/` folder are auto-imported by Nuxt:
725
+
726
+ ```markup
727
+ <!-- ✅ GOOD - Auto-imported from /components/ -->
728
+ <template>
729
+ <div>
730
+ <CustomerCard :customer="customer" />
731
+ <OrderSummary :order="order" />
732
+ </div>
733
+ </template>
734
+
735
+ <!-- No imports needed for project components -->
736
+ ```
737
+
738
+ ---
739
+
740
+ ## Accessibility
741
+
742
+ ### Semantic HTML
743
+
744
+ Use semantic HTML elements:
745
+
746
+ ```markup
747
+ <!-- ✅ GOOD - Semantic HTML -->
748
+ <nav>
749
+ <ul>
750
+ <li><a href="/home">Home</a></li>
751
+ <li><a href="/about">About</a></li>
752
+ </ul>
753
+ </nav>
754
+
755
+ <!-- ❌ BAD - Non-semantic -->
756
+ <div class="nav">
757
+ <div class="nav-item">Home</div>
758
+ <div class="nav-item">About</div>
759
+ </div>
760
+ ```
761
+
762
+ ### ARIA Labels
763
+
764
+ Provide ARIA labels for interactive elements:
765
+
766
+ ```markup
767
+ <!-- ✅ GOOD - ARIA labels -->
768
+ <AwButton
769
+ @click="deleteItem"
770
+ icon="awesio/delete"
771
+ aria-label="Delete customer"
772
+ />
773
+
774
+ <AwInput
775
+ v-model="search"
776
+ placeholder="Search..."
777
+ aria-label="Search customers"
778
+ />
779
+ ```
780
+
781
+ ### Keyboard Navigation
782
+
783
+ Ensure keyboard navigation works:
784
+
785
+ ```markup
786
+ <AwButton
787
+ @click="handleAction"
788
+ @keydown.enter="handleAction"
789
+ @keydown.space.prevent="handleAction"
790
+ >
791
+ Action
792
+ </AwButton>
793
+ ```
794
+
795
+ ---
796
+
797
+ ## Performance
798
+
799
+ ### Computed Properties Over Watchers
800
+
801
+ Use computed properties for derived state:
802
+
803
+ ```javascript
804
+ // ✅ GOOD - Computed property
805
+ export default {
806
+ computed: {
807
+ fullName() {
808
+ return `${this.firstName} ${this.lastName}`
809
+ },
810
+
811
+ hasErrors() {
812
+ return Object.keys(this.model.errors).length > 0
813
+ }
814
+ }
815
+ }
816
+
817
+ // ❌ BAD - Watcher for derived state
818
+ export default {
819
+ data() {
820
+ return {
821
+ fullName: ''
822
+ }
823
+ },
824
+
825
+ watch: {
826
+ firstName() {
827
+ this.fullName = `${this.firstName} ${this.lastName}`
828
+ },
829
+ lastName() {
830
+ this.fullName = `${this.firstName} ${this.lastName}`
831
+ }
832
+ }
833
+ }
834
+ ```
835
+
836
+ ### Proper Key Attributes
837
+
838
+ Always use unique keys in v-for:
839
+
840
+ ```markup
841
+ <!-- ✅ GOOD - Unique key -->
842
+ <div v-for="customer in customers" :key="customer.id">
843
+ {{ customer.name }}
844
+ </div>
845
+
846
+ <!-- ❌ BAD - Index as key -->
847
+ <div v-for="(customer, index) in customers" :key="index">
848
+ {{ customer.name }}
849
+ </div>
850
+
851
+ <!-- ❌ BAD - No key -->
852
+ <div v-for="customer in customers">
853
+ {{ customer.name }}
854
+ </div>
855
+ ```
856
+
857
+ ### Efficient Re-rendering
858
+
859
+ Avoid unnecessary re-renders:
860
+
861
+ ```javascript
862
+ // ✅ GOOD - Computed property caches result
863
+ computed: {
864
+ expensiveComputation() {
865
+ return this.items.filter(item => {
866
+ // Complex filtering logic
867
+ })
868
+ }
869
+ }
870
+
871
+ // ❌ BAD - Method recalculates every render
872
+ methods: {
873
+ expensiveComputation() {
874
+ return this.items.filter(item => {
875
+ // Complex filtering logic
876
+ })
877
+ }
878
+ }
879
+ ```
880
+
881
+ ---
882
+
883
+ ## Styling
884
+
885
+ ### CSS Custom Properties
886
+
887
+ Use CSS custom properties for theming:
888
+
889
+ ```scss
890
+ /* ✅ GOOD - CSS custom properties */
891
+ .button-accent {
892
+ background-color: var(--c-accent);
893
+ border-color: var(--c-accent);
894
+ color: var(--c-on-accent);
895
+ }
896
+
897
+ .button-accent:hover {
898
+ filter: brightness(1.1);
899
+ }
900
+
901
+ /* ❌ BAD - Hardcoded colors */
902
+ .button-accent {
903
+ background-color: #6366f1;
904
+ border-color: #6366f1;
905
+ color: white;
906
+ }
907
+ ```
908
+
909
+ ### Responsive Design
910
+
911
+ Use AwGrid component for responsive layouts:
912
+
913
+ ```markup
914
+ <!-- ✅ GOOD - Mobile-first responsive with AwGrid -->
915
+ <AwGrid :col="{ md: 2, lg: 4 }">
916
+ <AwCard>Card 1</AwCard>
917
+ <AwCard>Card 2</AwCard>
918
+ <AwCard>Card 3</AwCard>
919
+ <AwCard>Card 4</AwCard>
920
+ </AwGrid>
921
+ ```
922
+
923
+ ### Hover Effects
924
+
925
+ Add appropriate hover states:
926
+
927
+ ```scss
928
+ /* ✅ GOOD - Hover effects */
929
+ .card:hover {
930
+ transform: translateY(-2px);
931
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
932
+ transition: all 0.2s ease;
933
+ }
934
+
935
+ .link:hover {
936
+ color: var(--c-accent);
937
+ text-decoration: underline;
938
+ }
939
+ ```
940
+
941
+ ---
942
+
943
+ ## Table Patterns
944
+
945
+ ### Understanding field Prop
946
+
947
+ **With field:** `cell` = field value only
948
+ **Without field:** `cell` = entire row object
949
+
950
+ ```markup
951
+ <!-- WITH field: cell is just the value -->
952
+ <AwTableCol title="Name" field="name">
953
+ <template #default="{ cell }">
954
+ {{ cell }} <!-- cell is the string value of 'name' -->
955
+ </template>
956
+ </AwTableCol>
957
+
958
+ <!-- WITHOUT field: cell is full object -->
959
+ <AwTableCol title="Name">
960
+ <template #default="{ cell }">
961
+ {{ cell.name }} <!-- cell is the full row object -->
962
+ {{ cell.email }} <!-- can access other fields -->
963
+ </template>
964
+ </AwTableCol>
965
+ ```
966
+
967
+ ### Can't Use @click:row and #dropdown Together
968
+
969
+ ```markup
970
+ <!-- ❌ BAD - Conflict! -->
971
+ <AwTableBuilder
972
+ :collection="items"
973
+ @click:row="viewItem"
974
+ >
975
+ <template #dropdown="{ cell }">
976
+ <AwDropdownButton text="Edit" />
977
+ </template>
978
+ </AwTableBuilder>
979
+
980
+ <!-- ✅ GOOD - Choose one approach -->
981
+ <AwTableBuilder :collection="items">
982
+ <template #dropdown="{ cell }">
983
+ <AwDropdownButton text="View" @click="viewItem(cell)" />
984
+ <AwDropdownButton text="Edit" @click="editItem(cell)" />
985
+ </template>
986
+ </AwTableBuilder>
987
+ ```
988
+
989
+ ### AwDropdownButton Usage
990
+
991
+ ```markup
992
+ <template #dropdown="{ cell }">
993
+ <AwDropdownButton
994
+ text="View"
995
+ @click="viewItem(cell)"
996
+ />
997
+ <AwDropdownButton
998
+ text="Edit"
999
+ @click="editItem(cell)"
1000
+ />
1001
+ <AwDropdownButton
1002
+ text="Delete"
1003
+ color="error"
1004
+ @click="deleteItem(cell)"
1005
+ />
1006
+ </template>
1007
+ ```
1008
+
1009
+ ---
1010
+
1011
+ ## Navigation
1012
+
1013
+ ### Always Include shop_uuid in Routes
1014
+
1015
+ ```javascript
1016
+ // ✅ GOOD - Include shop_uuid
1017
+ this.$router.push({
1018
+ name: 'customers-edit',
1019
+ params: {
1020
+ shop_uuid: this.$route.params.shop_uuid,
1021
+ id: customer.id
1022
+ }
1023
+ })
1024
+
1025
+ // ❌ BAD - Missing shop_uuid
1026
+ this.$router.push(`/customers/${customer.id}/edit`)
1027
+ ```
1028
+
1029
+ ### AwButton href vs @click
1030
+
1031
+ Use `href` for navigation, `@click` for actions:
1032
+
1033
+ ```markup
1034
+ <!-- ✅ GOOD - href for navigation -->
1035
+ <AwButton
1036
+ :href="`/${shopUuid}/customers/${customer.id}`"
1037
+ text="View Customer"
1038
+ />
1039
+
1040
+ <!-- ✅ GOOD - @click for actions -->
1041
+ <AwButton
1042
+ @click="deleteCustomer(customer)"
1043
+ text="Delete"
1044
+ color="error"
1045
+ />
1046
+ ```
1047
+
1048
+ ### Mobile Breadcrumbs
1049
+
1050
+ Add breadcrumbs for mobile navigation:
1051
+
1052
+ ```markup
1053
+ <template>
1054
+ <AwPage title="Email Templates">
1055
+ <template #mobile-breadcrumbs>
1056
+ <AwButton
1057
+ :href="`/${$route.params.shop_uuid}/notifications`"
1058
+ theme="text"
1059
+ icon="arrow-left"
1060
+ text="Back to Notifications"
1061
+ />
1062
+ </template>
1063
+
1064
+ <!-- Page content -->
1065
+ </AwPage>
1066
+ </template>
1067
+ ```
1068
+
1069
+ ---
1070
+
1071
+ ## Summary Checklist
1072
+
1073
+ ### Data Management
1074
+ - ✅ Collections: 2 arguments `(models, options)`
1075
+ - ✅ Models: 3 arguments `(attributes, collection, options)`
1076
+ - ✅ Always include `shop_uuid` in options
1077
+ - ✅ Use standard vue-mc methods (`.isEmpty()`, `.isNew()`)
1078
+ - ✅ Let AwTableBuilder handle fetching (no manual `fetch()`)
1079
+
1080
+ ### Error Handling
1081
+ - ✅ Bind `:error` to `model.errors.field`
1082
+ - ✅ Check `Object.keys(model.errors).length > 0` after save
1083
+ - ✅ Wrap API calls in try-catch
1084
+ - ✅ Redirect on fetch errors (404)
1085
+
1086
+ ### User Feedback
1087
+ - ✅ Use `$notify` for success/error messages
1088
+ - ✅ Use `$confirm` for destructive actions
1089
+ - ✅ Show loading states (`:loading` prop)
1090
+
1091
+ ### Date Formatting
1092
+ - ✅ Always use `$dayjs` in templates
1093
+ - ✅ Always use `this.$dayjs` in methods
1094
+ - ✅ Never use native Date methods
1095
+
1096
+ ### Navigation
1097
+ - ✅ Always include `shop_uuid` in routes
1098
+ - ✅ Use `href` for navigation, `@click` for actions
1099
+ - ✅ Add mobile breadcrumbs for subpages
1100
+
1101
+ ## See Also
1102
+
1103
+ - [Page Patterns](./page-patterns/) - List, detail, and dashboard patterns
1104
+ - [Forms Guide](./forms-guide.md) - Form validation and submission
1105
+ - [Data Fetching Guide](./data-fetching.md) - Working with collections
1106
+ - [Error Handling Guide](./error-handling.md) - Error patterns