@fui-org/fui-cli 0.2.0 → 0.4.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 (212) hide show
  1. package/README.md +20 -2
  2. package/dist/fui.js +347 -44
  3. package/package.json +15 -3
  4. package/skills/fui/SKILL.md +149 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,532 @@
1
+ ---
2
+ version: 1
3
+ name: FUI-design-system
4
+ description: "FUI design system dựa trên Vuetify 2 + Material Design 2, rút ra từ codebase thực tế. Light mode, enterprise admin. Primary blue (#1976D2) dành cho action chính. Input fields dùng outlined+dense+hide-details theo defaultControlAttr (FUI runtime tự apply — không cần viết lại trong module.json). Icon giữ kích thước mặc định, không tự thêm small/:small. Các control khác loại/khác chiều cao trong cùng một hàng phải được kiểm tra và canh giữa theo chiều dọc bằng align-center; không bù bằng margin thủ công. Dialog: dựng v-dialog thủ công theo anatomy chuẩn mô phỏng phong cách f-dialog (toolbar dense+flat không color, close icon; hàng cuối là v-card-actions căn phải, button rộng tự nhiên; tối đa một action chính có nền, action phụ là text). Form dùng floating label — KHÔNG dùng label div rời. Card trong dialog không dùng elevation hay outlined — dùng class pa-0. f-button mặc định elevation:0, color:primary, checkvalid:false."
5
+
6
+ colors:
7
+ primary: "#1976D2"
8
+ primary-text: "primary--text"
9
+ warning: "#FB8C00"
10
+ success: "#4CAF50"
11
+ error: "#FF5252"
12
+ action-main: "primary"
13
+ action-delete: "warning"
14
+ action-positive: "success"
15
+ action-register: "green"
16
+ conditional: "(condition ? 'red' : 'primary')"
17
+
18
+ icons:
19
+ save: "mdi-content-save"
20
+ delete: "mdi-delete"
21
+ search: "mdi-magnify"
22
+ close: "mdi-close"
23
+ add-user: "mdi-account-multiple-plus"
24
+ remove-user: "mdi-account-multiple-minus"
25
+ edit: "mdi-pencil"
26
+ filter: "mdi-filter"
27
+ refresh: "mdi-refresh"
28
+ upload: "mdi-cloud-upload-outline"
29
+ download: "mdi-download"
30
+ print: "mdi-printer"
31
+ settings: "mdi-cog"
32
+ eye: "mdi-eye"
33
+ lock: "mdi-lock"
34
+ check: "mdi-check-bold"
35
+
36
+ layout:
37
+ main-container: "grid-list-md fluid"
38
+ dialog-container: "hidden-container"
39
+ centered-narrow: "grid-list-md mw-1000"
40
+ page-with-nav: "page-container grid-list-md fluid"
41
+ dialog-inner: "grid-list-md px-4"
42
+ ---
43
+
44
+ # FUI Design System
45
+
46
+ Tài liệu này mô tả cách viết UI chuẩn cho FUI modules. Tất cả patterns rút từ codebase thực tế, không phải lý thuyết.
47
+
48
+ ---
49
+
50
+ ## 1. Defaults do FUI Runtime tự apply (không cần viết trong module.json)
51
+
52
+ `defaultControlAttr` trong FUI runtime tự inject các attr sau khi render. **Không cần** viết lại trong module.json:
53
+
54
+ | Component | Defaults tự inject |
55
+ |---|---|
56
+ | `v-text-field` | `outlined, dense, hide-details, required:true` |
57
+ | `v-textarea` | `outlined, dense` |
58
+ | `v-select` | `outlined, dense, hide-details, required:true, menu-props:{offsetY:true}` |
59
+ | `v-combobox` | `outlined, dense, hide-details, required:true, menu-props:{offsetY:true}` |
60
+ | `v-autocomplete` | `outlined, dense, hide-details, auto-select-first:true` |
61
+ | `v-checkbox` | `class:mt-1, hide-details` |
62
+ | `v-switch` | `dense, hide-details, class:my-1 mx-0` |
63
+ | `v-card` | `outlined:true` |
64
+ | `v-btn` | `elevation:0` |
65
+ | `f-button` | `elevation:0, color:primary` |
66
+ | `f-table` | `dense, fixed-header, hide-default-footer, show-search, items-per-page:50` |
67
+ | `f-dialog` | `outlined, dense` |
68
+ | `f-date` | `outlined, dense, hide-details, picker.locale:vi` |
69
+ | `f-time` | `outlined, dense, hide-details` |
70
+ | `f-search` | `outlined, dense, hide-details, auto-select-first:true` |
71
+
72
+ **Hệ quả thực tế:** Khi viết module.json, một input field chỉ cần:
73
+ ```json
74
+ { "el": "v-text-field", "attr": { "v-model": "vueData.form.Name", "label": "Họ và tên" }, "w": 12 }
75
+ ```
76
+ Không cần thêm `outlined`, `dense`, `hide-details` — runtime tự thêm.
77
+
78
+ ---
79
+
80
+ ## 2. Colors — Quy tắc dùng màu
81
+
82
+ | Màu | Khi nào dùng |
83
+ |---|---|
84
+ | `primary` | Mọi action chính: Save, Add, Search, View, mở dialog |
85
+ | `warning` | Delete, Permission denied, Remove — destructive nhưng không nguy hiểm cao |
86
+ | `success` | Action positive không xóa dữ liệu: Update permission, Scan |
87
+ | `green` | Đăng ký, Register — dùng với `:outlined:true` |
88
+ | conditional | `"(vueData.item.Active == 0 ? 'red' : 'primary')"` — trạng thái toggle |
89
+
90
+ **Rule cốt lõi:** Chỉ một màu accent trên một màn hình. Không mix nhiều màu cùng cấp.
91
+
92
+ ---
93
+
94
+ ## 3. Toolbar — Chỉ dùng trong dialog
95
+
96
+ Toolbar trong FUI module **không bao giờ có** `color` hay `dark`. Pattern chuẩn bên trong `v-card`:
97
+
98
+ ```json
99
+ {
100
+ "el": "v-toolbar",
101
+ "attr": { "dense": "", "flat": "" },
102
+ "innerHTML": [
103
+ { "el": "v-toolbar-title", "innerHTML": "Tên Dialog" },
104
+ { "el": "v-spacer" },
105
+ {
106
+ "el": "v-btn",
107
+ "attr": { "icon": "", "v-on:click": "vueData.dlTen = false" },
108
+ "innerHTML": [{ "el": "v-icon", "innerHTML": "mdi-close" }]
109
+ }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ **Không dùng:** `color="primary"`, `dark`, `elevation`, `tile` trên toolbar trong dialog.
115
+
116
+ ---
117
+
118
+ ## 4. Dialog — Cấu trúc chuẩn (v-dialog thủ công, phong cách f-dialog)
119
+
120
+ **Quy tắc gốc:** Dialog dựng bằng `v-dialog` thủ công (AI dễ đọc/chỉnh sửa từng phần), nhưng **diện mạo phải mô phỏng đúng `f-dialog`** của runtime: toolbar `dense flat` không màu + close icon, thân form floating label, hàng cuối là `v-card-actions` căn phải. Button giữ chiều ngang tự nhiên; tối đa một action chính được tô nền, các action phụ dùng **text style**. Component `f-dialog` vẫn hợp lệ cho form rất nhỏ, nhưng chuẩn mặc định là anatomy dưới đây.
121
+
122
+ Dialog luôn nằm trong `hidden-container`. Cấu trúc đầy đủ:
123
+
124
+ ```json
125
+ {
126
+ "prop": "hidden-container",
127
+ "rows": [
128
+ {
129
+ "prop": "",
130
+ "cols": [
131
+ {
132
+ "el": "v-dialog",
133
+ "col": {},
134
+ "attr": { "v-model": "vueData.dlTen", "width": 650 },
135
+ "innerHTML": [
136
+ {
137
+ "el": "v-card",
138
+ "attr": { "class": "pa-0" },
139
+ "innerHTML": [
140
+ {
141
+ "el": "v-toolbar",
142
+ "attr": { "dense": "", "flat": "" },
143
+ "innerHTML": [
144
+ { "el": "v-toolbar-title", "innerHTML": "Tiêu đề" },
145
+ { "el": "v-spacer" },
146
+ { "el": "v-btn", "attr": { "icon": "", "v-on:click": "vueData.dlTen = false" },
147
+ "innerHTML": [{ "el": "v-icon", "innerHTML": "mdi-close" }] }
148
+ ]
149
+ },
150
+ {
151
+ "el": "v-container",
152
+ "attr": { "class": "grid-list-md px-4" },
153
+ "innerHTML": [
154
+ {
155
+ "el": "v-layout",
156
+ "w": 12,
157
+ "attr": { "row": "", "wrap": "" },
158
+ "innerHTML": [
159
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.FullName", "label": "Họ và tên" }, "w": 12 },
160
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.Phone", "label": "Điện thoại" }, "w": 6 },
161
+ { "el": "v-select", "col": {}, "attr": { "v-model": "vueData.form.DeptID", "label": "Phòng ban",
162
+ ":items": "vueData.deptList", "item-text": "DeptName", "item-value": "DeptID" }, "w": 6 }
163
+ ]
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ "el": "v-card-actions",
169
+ "attr": { "class": "mr-1 mb-1" },
170
+ "innerHTML": [
171
+ { "el": "v-spacer" },
172
+ { "el": "f-button", "attr": { "text": "", "label": "Đặt lại", ":action": { "CALL": "resetForm" } } },
173
+ { "el": "f-button", "attr": { "color": "primary", "label": "Lưu", "icon-text": "mdi-content-save",
174
+ ":checkvalid": false, "action": { "API": "...", "IN": {}, "CALLBACK": {} } } }
175
+ ]
176
+ }
177
+ ]
178
+ }
179
+ ]
180
+ }
181
+ ]
182
+ }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ **Anatomy bắt buộc (đúng phong cách f-dialog):**
188
+ | Phần | Quy tắc |
189
+ |---|---|
190
+ | `v-card` | `class="pa-0"` — triệt đệm để toolbar tiêu đề tràn sát mép dialog (spacing của form đã do `v-container px-4` lo); không elevation/outlined vì v-dialog đã tự có bóng đổ. Ưu tiên class Vuetify thay vì `style="padding: 0px;"` |
191
+ | `v-toolbar` | `dense flat` — **không** color/dark; title + `v-spacer` + `v-btn[icon]` mdi-close |
192
+ | Thân | `v-container.grid-list-md.px-4` > `v-layout[row wrap]` > field floating label (xem §5) |
193
+ | `v-card-actions` | Là **hàng cuối** của dialog; `class="mr-1 mb-1"`; `v-spacer` trước nhóm nút → các nút dồn phải |
194
+ | Chiều ngang nút | Theo nội dung tự nhiên; không đặt `w`, `width`, `block`, `flex-grow`, không bọc nút trong cột giãn |
195
+ | Nút hành động chính | Tối đa một nút (ví dụ **Lưu**) dùng `color="primary"`; có thể có icon trái nhưng không tự thu nhỏ icon |
196
+ | Nút hành động phụ | `f-button` kèm `"text": ""`; không tô nền cho action ít quan trọng, giữ nhãn ngắn và số lượng tối thiểu |
197
+ | Nút đóng phụ | Chỉ dùng close icon trên toolbar; không thêm nút "Đóng" ở actions trừ khi user yêu cầu |
198
+
199
+ **Width conventions:**
200
+ | Width | Dùng cho |
201
+ |---|---|
202
+ | 400 | Dialog nhỏ: confirm, function right, module select |
203
+ | 550 | Dialog trung bình: department update |
204
+ | 600 | Add right, department |
205
+ | 650 | Form user info chuẩn |
206
+ | 800 | Dialog lớn có table bên trong |
207
+
208
+ **Không dùng:** `persistent`, `fullscreen`, `scrollable`, `transition` trừ khi có lý do cụ thể.
209
+
210
+ ---
211
+
212
+ ## 5. Form Layout bên trong Dialog — floating label
213
+
214
+ **Chuẩn duy nhất: floating label của Vuetify** — mỗi field tự mang `label` trong `attr`. **KHÔNG dùng** pattern label `div` rời bên trái (kiểu w:3 + w:9) — pattern đó đã bị loại bỏ.
215
+
216
+ ```json
217
+ { "el": "v-layout", "w": 12, "attr": { "row": "", "wrap": "" }, "innerHTML": [
218
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.FullName", "label": "Họ và tên" }, "w": 12 },
219
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.Phone", "label": "Điện thoại" }, "w": 6 },
220
+ { "el": "v-select", "col": {}, "attr": { "v-model": "vueData.form.DeptID", "label": "Phòng ban",
221
+ ":items": "vueData.deptList", "item-text": "DeptName", "item-value": "DeptID" }, "w": 6 },
222
+ { "el": "v-textarea", "col": {}, "attr": { "v-model": "vueData.form.Note", "label": "Ghi chú" }, "w": 12 }
223
+ ]}
224
+ ```
225
+
226
+ **Quy tắc chia cột form:**
227
+ - Field dài (họ tên, địa chỉ, ghi chú, textarea) → `w: 12`
228
+ - Field ngắn đi theo cặp → `w: 6` + `w: 6` (hoặc `4+4+4` khi 3 field ngắn)
229
+ - Field optional → thêm `":required": false` (runtime mặc định inject `required: true`)
230
+ - **KHÔNG** thêm class căn chỉnh (`mt-2`, `ml-2`, `flex-md-grow-0`) — floating label tự thẳng hàng trong grid
231
+
232
+ ---
233
+
234
+ ## 6. Toolbar chính của màn hình (row filter + buttons)
235
+
236
+ Row đầu tiên của màn hình thường chứa filter + action buttons. Vì các control này thường khác chiều
237
+ cao, row phải dùng `align-center` để cùng trục giữa theo chiều dọc:
238
+
239
+ ```json
240
+ {
241
+ "prop": "row wrap align-center",
242
+ "cols": [
243
+ {
244
+ "el": "v-autocomplete",
245
+ "col": { "class": "shrink" },
246
+ "attr": { "class": "flex-md-grow-0 my-2", "v-model": "vueData.sFilter",
247
+ "label": "Lọc theo...", ":items": "vueData.dsList",
248
+ "item-text": "Name", "item-value": "ID", ":required": false },
249
+ "w": "350"
250
+ },
251
+ {
252
+ "el": "f-button",
253
+ "col": { "class": "shrink" },
254
+ "attr": { "class": "my-2", "label": "Tìm", "icon-text": "mdi-magnify",
255
+ ":checkvalid": false, "action": { "CALL": "vueData.search" } }
256
+ },
257
+ {
258
+ "el": "f-button",
259
+ "col": { "class": "shrink" },
260
+ "attr": { "class": "my-2", "label": "Thêm", "icon-text": "mdi-account-multiple-plus",
261
+ ":checkvalid": false, "action": { "EXE": "vueData.dlThem = true" } }
262
+ }
263
+ ]
264
+ }
265
+ ```
266
+
267
+ **Width cho filter inputs trên toolbar:** Dùng pixel (`"w": "350"`, `"w": "200"`) thay vì grid columns.
268
+
269
+ ---
270
+
271
+ ## 7. f-button — Quy tắc
272
+
273
+ ```json
274
+ {
275
+ "el": "f-button",
276
+ "attr": {
277
+ "label": "Lưu",
278
+ "icon-text": "mdi-content-save",
279
+ ":checkvalid": false,
280
+ "action": { "API": "/me/Save", "IN": { "Name": "vueData.form.Name" }, "CALLBACK": { "MESS": "Đã lưu" } }
281
+ },
282
+ "w": 2
283
+ }
284
+ ```
285
+
286
+ **`:checkvalid`:**
287
+ - `false` (default): **Hầu hết buttons** — không cần validate form trước
288
+ - `true`: Chỉ khi button là Save của form có validation (user registration, connection string)
289
+
290
+ **Color mapping:**
291
+ | color | label | icon-text | Khi nào |
292
+ |---|---|---|---|
293
+ | `primary` (default) | Lưu | mdi-content-save | Lưu dữ liệu |
294
+ | `primary` | Tìm | mdi-magnify | Search/filter |
295
+ | `primary` | Thêm | mdi-account-multiple-plus | Mở dialog thêm |
296
+ | `warning` | Xóa | mdi-delete | Xóa dữ liệu |
297
+ | `warning` | Từ chối | mdi-cancel | Permission denied |
298
+ | `success` | Cập nhật | mdi-shield-edit | Update quyền |
299
+
300
+ ---
301
+
302
+ ## 8. f-table — Cấu trúc chuẩn
303
+
304
+ ```json
305
+ {
306
+ "el": "f-table",
307
+ "col": { "v-if": "vueData.user.SystemRight > 1" },
308
+ "attr": {
309
+ "label": "Danh sách",
310
+ ":items": "vueData.dataList",
311
+ "item-key": "ID",
312
+ ":items-per-page": -1,
313
+ ":hide-default-footer": true,
314
+ ":height": -16
315
+ },
316
+ "w": 12
317
+ }
318
+ ```
319
+
320
+ **`:items-per-page`:**
321
+ - `-1` (default): Hiển thị tất cả, không phân trang — dùng khi có `hide-default-footer: true`
322
+ - `50`: Khi cần phân trang, bỏ `hide-default-footer`
323
+
324
+ **Permission guard:** Luôn đặt `v-if` trên `col` wrapper, không phải trên element:
325
+ ```json
326
+ "col": { "v-if": "vueData.user.SystemRight > 1" }
327
+ ```
328
+
329
+ **Chiều cao (`:height`)** — cùng quy ước cho `f-table` và `f-sheet`:
330
+
331
+ | Giá trị | Hành vi |
332
+ |---|---|
333
+ | *(bỏ trống)* | Tự giãn theo số dòng — chỉ hợp bảng ngắn/lookup; bảng chính sẽ làm cả trang cuộn |
334
+ | `<= 0` | **Fill tới đáy màn hình, chừa `abs(n)` px** — chuẩn cho bảng chính, dùng `-16` |
335
+ | `> 0` | px cố định — bảng trong dialog (vd `360`) |
336
+
337
+ Chế độ `<=0` tự đo `getBoundingClientRect().top` thật của bảng sau layout, theo dõi `resize`, và tự bật `fixed-header` — **không phải tính tay** theo chiều cao header. Pattern cũ `"$( window ).height()-285"` không dùng nữa (lint D9 cảnh báo).
338
+
339
+ **Inline column types (trong `headers` array):**
340
+ | el | Dùng cho |
341
+ |---|---|
342
+ | `t-button` | Action button trong row |
343
+ | `t-select` | Dropdown inline edit |
344
+ | `t-check` | Toggle on/off |
345
+ | `t-menu` | Context menu cho row |
346
+ | `v-icon` | Icon indicator (conditional color) |
347
+ | `v-chip-group` | Nhóm chip tags |
348
+
349
+ ---
350
+
351
+ ## 9. Layout — Container Patterns
352
+
353
+ **Main page container:**
354
+ ```json
355
+ { "prop": "grid-list-md fluid", "rows": [...] }
356
+ ```
357
+
358
+ **Centered narrow (form/login page):**
359
+ ```json
360
+ { "prop": "grid-list-md mw-1000", "rows": [...] }
361
+ ```
362
+
363
+ **Page với side navigation:**
364
+ ```json
365
+ { "prop": "page-container grid-list-md fluid", "rows": [
366
+ { "prop": "page-navigation", "cols": [...] },
367
+ { "prop": "row", "cols": [...] }
368
+ ]}
369
+ ```
370
+
371
+ **Container chứa dialogs (bắt buộc):**
372
+ ```json
373
+ { "prop": "hidden-container", "rows": [
374
+ { "prop": "", "cols": [ { "el": "v-dialog", ... } ] }
375
+ ]}
376
+ ```
377
+
378
+ ---
379
+
380
+ ## 10. Context Menu — t-menu pattern
381
+
382
+ Khi một row có nhiều actions, dùng `t-menu` thay vì nhiều `t-button`:
383
+
384
+ ```json
385
+ // Trong headers array:
386
+ { "el": "t-menu", "width": "120px", "align": "center", "text": "Tác vụ", "value": "Actions",
387
+ "attr": { ":items": "vueData.menuActions" } }
388
+
389
+ // Trong data section:
390
+ "menuActions": [
391
+ { "color": "primary", "icon-text": "mdi-pencil", "text": "Chỉnh sửa",
392
+ "action": { "EXE": "vueData.openEdit(item)" } },
393
+ { "color": "warning", "icon-text": "mdi-delete", "text": "Xóa",
394
+ "action": { "CONFIRM": "Bạn có chắc muốn xóa?", "API": "...", "IN": { "ID": "item.ID" } } }
395
+ ]
396
+ ```
397
+
398
+ ---
399
+
400
+ ## 11. Phản hồi & xác nhận — CHỈ dùng hệ thống có sẵn của FUI
401
+
402
+ Mọi phản hồi cho user (xác nhận, báo thành công, báo lỗi) đi qua hệ thống có sẵn của platform — **KHÔNG tự dựng** `v-snackbar`, `v-alert`, hay toast/notification tự chế trong controls:
403
+
404
+ | Nhu cầu | Dùng | Cơ chế |
405
+ |---|---|---|
406
+ | Xác nhận trước hành động | `CONFIRM` trong action | jquery-confirm dialog |
407
+ | Báo thành công (thoáng qua) | `MESS` trong CALLBACK | vue-toast góc màn hình |
408
+ | Thông báo cần user đọc kỹ | `MESSBOX` trong action | `showMessage()` hộp thoại |
409
+ | Báo lỗi API | `ERRORCALLBACK` + `MESS`/`MESSBOX` | như trên |
410
+ | Trong script.js / EXE | `Vue.$toast.success/error(...)`, `showMessage({...})` | hàm global sẵn có |
411
+
412
+ ### Destructive actions — luôn có CONFIRM
413
+
414
+ Mọi action xóa dữ liệu phải có `CONFIRM`:
415
+
416
+ ```json
417
+ {
418
+ "CONFIRM": "Bạn có chắc muốn xóa?",
419
+ "API": "/me/Delete",
420
+ "IN": { "ID": "vueData.selectedID" },
421
+ "CALLBACK": { "CALL": "vueData.loadData" }
422
+ }
423
+ ```
424
+
425
+ Update có tác động lớn (system right, connection string) cũng cần `CONFIRM`.
426
+
427
+ ### Action ghi — luôn có phản hồi
428
+
429
+ Mọi action ghi dữ liệu (Insert/Update/Delete) phải có `CALLBACK` vừa reload data vừa `MESS` báo kết quả:
430
+
431
+ ```json
432
+ { "API": "/me/Save", "IN": { ... }, "CALLBACK": [ { "MESS": "Đã lưu" }, { "CALL": "vueData.loadData" } ] }
433
+ ```
434
+
435
+ ---
436
+
437
+ ## 12. Icons — Bảng chuẩn
438
+
439
+ | Icon | Dùng cho |
440
+ |---|---|
441
+ | `mdi-content-save` | Save / Lưu |
442
+ | `mdi-delete` | Xóa |
443
+ | `mdi-magnify` | Tìm kiếm |
444
+ | `mdi-close` | Đóng dialog |
445
+ | `mdi-refresh` | Tải lại |
446
+ | `mdi-plus` | Thêm mới (generic) |
447
+ | `mdi-pencil` | Sửa |
448
+ | `mdi-account-multiple-plus` | Thêm user |
449
+ | `mdi-account-multiple-minus` | Xóa user |
450
+ | `mdi-account-details` | Chi tiết user |
451
+ | `mdi-shield-edit` | Cập nhật quyền |
452
+ | `mdi-shield-account-outline` | User permission |
453
+ | `mdi-lock-open-plus` | Cấp quyền |
454
+ | `mdi-lock-open-remove` | Thu hồi quyền |
455
+ | `mdi-check-bold` | Trạng thái active |
456
+ | `mdi-lock` | Trạng thái locked |
457
+ | `mdi-cancel` | Từ chối / Denied |
458
+ | `mdi-cloud-upload-outline` | Upload file |
459
+ | `mdi-download` | Tải xuống |
460
+ | `mdi-filter` | Lọc |
461
+ | `mdi-folder-edit-outline` | Xem/sửa chi tiết |
462
+
463
+ ---
464
+
465
+ ## 13. Do's and Don'ts
466
+
467
+ ### Do
468
+ - Dùng `hidden-container` để wrap tất cả dialogs.
469
+ - Dựng dialog bằng `v-dialog` thủ công theo anatomy §4 — diện mạo mô phỏng `f-dialog`.
470
+ - Dùng `dense flat` cho toolbar bên trong dialog — không thêm color hay dark.
471
+ - Dùng `class="pa-0"` cho v-card trong dialog (không dùng inline style).
472
+ - Form dùng **floating label** (`label` trong attr của field) — w:12 cho field dài, 6+6 cho field ngắn.
473
+ - Với mỗi hàng, kiểm tra trục dọc của các control; hàng trộn input/button/icon/checkbox/label dùng `align-center`, chỉ một cột lệch mới dùng `align-self-center`. Không bù bằng margin thủ công.
474
+ - Hàng cuối của dialog dùng `v-card-actions[class="mr-1 mb-1"]` + `v-spacer`; các nút căn phải và giữ chiều ngang tự nhiên.
475
+ - Chỉ action quan trọng nhất được tô nền `primary`; action phụ dùng `f-button` + `"text": ""`, không tô nền.
476
+ - Giữ kích thước icon mặc định; không tự thêm `small`/`:small` cho icon hoặc nút icon.
477
+ - Đặt `v-if` permission guard trên `col` wrapper, không phải trên element.
478
+ - Dùng `:items-per-page: -1` + `hide-default-footer: true` cho table không cần phân trang.
479
+ - Dùng `CONFIRM` trước mọi action xóa dữ liệu.
480
+ - Dùng pixel width (`"w": "350"`) cho filter inputs trên toolbar row.
481
+ - Dùng `MESS`/`MESSBOX`/`CONFIRM` (hệ thông báo có sẵn) cho mọi phản hồi — xem §11.
482
+ - Dùng `:checkvalid: false` cho hầu hết f-button (chỉ `true` khi cần validate form đăng ký).
483
+ - Conditional color: `"(item.Active == 0 ? 'red' : 'primary')"` cho status toggles.
484
+
485
+ ### Don't
486
+ - Đừng viết lại `outlined`, `dense`, `hide-details` trong module.json — runtime tự inject từ `defaultControlAttr`.
487
+ - Đừng dùng label `div` rời bên trái cho form (pattern w:3 + w:9 cũ) — chuẩn là floating label.
488
+ - Đừng dùng `color="primary" dark` cho toolbar trong dialog.
489
+ - Đừng thêm `elevation` hay `outlined` cho v-card trong dialog.
490
+ - Đừng dùng `persistent`, `fullscreen` cho dialog thông thường.
491
+ - Đừng dùng nhiều màu accent trên cùng một màn hình — chỉ primary + một màu semantic.
492
+ - Đừng để button xóa màu `error` (đỏ) — dùng `warning` (cam).
493
+ - Đừng hardcode height cho table — dùng `":height": -16` (fill tới đáy, tự đo) cho bảng chính.
494
+ - Đừng dùng `@click` trong JSON — luôn dùng `v-on:click`.
495
+ - Đừng tự dựng `v-snackbar`/`v-alert`/toast riêng trong controls để báo kết quả — dùng `MESS`/`MESSBOX` có sẵn (§11).
496
+
497
+ ---
498
+
499
+ ## 14. Template `{projectId}/DESIGN.md` — nơi tích luỹ chuẩn riêng của project
500
+
501
+ Khi user góp ý về UI, AI phải ghi quy tắc vào `{projectId}/DESIGN.md` theo template dưới (tạo file nếu chưa có). File này **ghi đè** quy tắc cùng chủ đề của chuẩn chung — mục nào không có thì vẫn theo fui/DESIGN.md. Mỗi quy tắc phải viết ở dạng **tổng quát + ví dụ đúng/sai**, không ghi lại tình huống cụ thể kiểu nhật ký.
502
+
503
+ ```markdown
504
+ # DESIGN — {Tên project}
505
+
506
+ > Ghi đè fui/DESIGN.md. Mục không đề cập → theo chuẩn chung.
507
+ > Mỗi quy tắc: phát biểu tổng quát + ví dụ ĐÚNG/SAI (nếu diễn đạt được bằng JSON).
508
+
509
+ ## 1. Khung trang (container, mw-*, page-navigation)
510
+ <!-- vd: "Mọi trang nhập liệu dùng mw-1200" -->
511
+
512
+ ## 2. Toolbar / hàng filter
513
+ <!-- vd: "Nút Thêm luôn đứng cuối hàng filter, sau nút Tìm" -->
514
+
515
+ ## 3. Bảng dữ liệu (f-table)
516
+ <!-- vd: "Cột Tác vụ luôn dùng t-menu khi có ≥2 hành động" -->
517
+
518
+ ## 4. Dialog
519
+ <!-- vd: "Dialog form của project này luôn width 600" -->
520
+
521
+ ## 5. Form
522
+ <!-- vd: "Field ngày luôn đặt cặp Từ ngày/Đến ngày w:6+6" -->
523
+
524
+ ## 6. Màu / icon / nhãn nút
525
+ <!-- vd: "Nút lưu ghi 'Ghi lại' thay vì 'Lưu'" -->
526
+
527
+ ## 7. Cấm trong project này
528
+ <!-- vd: "Không dùng v-chip trong bảng" -->
529
+ ```
530
+
531
+ **Quy trình ghi (bắt buộc sau mỗi góp ý UI của user):**
532
+ 1. Sửa module theo góp ý → 2. Chuyển góp ý thành quy tắc tổng quát, ghi vào đúng mục ở trên → 3. Nếu quy tắc đáng áp dụng cho mọi project → đề xuất user đưa vào fui/DESIGN.md (chuẩn chung), chờ user quyết.