gladvn 0.2.36 → 0.2.37

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 (134) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/scripts/strip-comments.ts +79 -0
  4. package/src/blocks/auth-form.tsx +34 -30
  5. package/src/blocks/auth-recovery.tsx +9 -13
  6. package/src/blocks/auth-split.tsx +46 -36
  7. package/src/blocks/settings.tsx +84 -117
  8. package/src/components/macro/alert-preset.tsx +3 -1
  9. package/src/components/macro/carousel-preset.tsx +0 -1
  10. package/src/components/macro/checkbox-preset.test.tsx +2 -2
  11. package/src/components/macro/checkbox-preset.tsx +1 -2
  12. package/src/components/macro/command-preset.tsx +1 -1
  13. package/src/components/macro/date-picker.tsx +5 -18
  14. package/src/components/macro/dialog-preset.tsx +5 -3
  15. package/src/components/macro/input-preset.tsx +0 -1
  16. package/src/components/macro/select-preset.tsx +1 -1
  17. package/src/components/macro/switch-preset.test.tsx +1 -1
  18. package/src/components/micro/accordion.test.tsx +6 -12
  19. package/src/components/micro/alert-dialog.tsx +0 -2
  20. package/src/components/micro/alert.test.tsx +5 -8
  21. package/src/components/micro/alert.tsx +0 -2
  22. package/src/components/micro/badge.test.tsx +5 -7
  23. package/src/components/micro/badge.tsx +1 -3
  24. package/src/components/micro/button.test.tsx +19 -26
  25. package/src/components/micro/button.tsx +3 -11
  26. package/src/components/micro/calendar.tsx +12 -13
  27. package/src/components/micro/card.test.tsx +3 -5
  28. package/src/components/micro/carousel.tsx +0 -1
  29. package/src/components/micro/chart.tsx +3 -2
  30. package/src/components/micro/checkbox.test.tsx +9 -18
  31. package/src/components/micro/combobox.tsx +1 -3
  32. package/src/components/micro/command.tsx +23 -11
  33. package/src/components/micro/context-menu.tsx +0 -2
  34. package/src/components/micro/dialog.test.tsx +6 -14
  35. package/src/components/micro/dialog.tsx +0 -2
  36. package/src/components/micro/drawer.tsx +0 -3
  37. package/src/components/micro/dropdown-menu.test.tsx +8 -14
  38. package/src/components/micro/dropdown-menu.tsx +0 -2
  39. package/src/components/micro/field.tsx +3 -3
  40. package/src/components/micro/hover-card.tsx +0 -2
  41. package/src/components/micro/input-group.tsx +9 -42
  42. package/src/components/micro/input.test.tsx +15 -24
  43. package/src/components/micro/navigation-menu.tsx +0 -2
  44. package/src/components/micro/popover.test.tsx +5 -9
  45. package/src/components/micro/progress.tsx +5 -1
  46. package/src/components/micro/select.test.tsx +5 -18
  47. package/src/components/micro/select.tsx +3 -5
  48. package/src/components/micro/separator.tsx +1 -1
  49. package/src/components/micro/sheet.test.tsx +6 -14
  50. package/src/components/micro/sheet.tsx +0 -2
  51. package/src/components/micro/sidebar.tsx +5 -6
  52. package/src/components/micro/sonner.tsx +0 -1
  53. package/src/components/micro/switch.test.tsx +9 -18
  54. package/src/components/micro/switch.tsx +1 -1
  55. package/src/components/micro/tabs.test.tsx +5 -11
  56. package/src/components/micro/theme-provider.tsx +0 -12
  57. package/src/components/micro/toggle-group.tsx +1 -12
  58. package/src/components/micro/tooltip.test.tsx +7 -12
  59. package/src/dev/App.tsx +6 -6
  60. package/src/dev/components/BlockViewer.tsx +15 -4
  61. package/src/dev/components/Container.tsx +20 -0
  62. package/src/dev/components/GladvnLogo.tsx +3 -9
  63. package/src/dev/components/code-highlighter.tsx +5 -3
  64. package/src/dev/components/showcase.tsx +116 -168
  65. package/src/dev/sections/buttons.tsx +4 -9
  66. package/src/dev/sections/display.tsx +68 -72
  67. package/src/dev/sections/feedback.tsx +304 -314
  68. package/src/dev/sections/forms.tsx +10 -14
  69. package/src/dev/sections/interactive.tsx +32 -32
  70. package/src/dev/sections/overview.tsx +2 -10
  71. package/src/dev/showcase/accordion.tsx +512 -554
  72. package/src/dev/showcase/alert-dialog.tsx +525 -565
  73. package/src/dev/showcase/alert.tsx +352 -402
  74. package/src/dev/showcase/aspect-ratio.tsx +167 -193
  75. package/src/dev/showcase/avatar.tsx +231 -269
  76. package/src/dev/showcase/badge.tsx +92 -140
  77. package/src/dev/showcase/breadcrumb.tsx +113 -135
  78. package/src/dev/showcase/button.tsx +140 -173
  79. package/src/dev/showcase/calendar.tsx +187 -237
  80. package/src/dev/showcase/card.tsx +229 -261
  81. package/src/dev/showcase/carousel.tsx +288 -315
  82. package/src/dev/showcase/chart.tsx +44 -50
  83. package/src/dev/showcase/checkbox.tsx +286 -330
  84. package/src/dev/showcase/collapsible.tsx +143 -160
  85. package/src/dev/showcase/combobox.tsx +327 -369
  86. package/src/dev/showcase/command.tsx +106 -120
  87. package/src/dev/showcase/context-menu.tsx +93 -107
  88. package/src/dev/showcase/dialog.tsx +585 -630
  89. package/src/dev/showcase/drawer.tsx +176 -196
  90. package/src/dev/showcase/dropdown-menu.tsx +183 -201
  91. package/src/dev/showcase/empty.tsx +232 -274
  92. package/src/dev/showcase/hover-card.tsx +153 -180
  93. package/src/dev/showcase/input-group.tsx +221 -253
  94. package/src/dev/showcase/input-otp.tsx +204 -250
  95. package/src/dev/showcase/input.tsx +246 -325
  96. package/src/dev/showcase/item.tsx +134 -152
  97. package/src/dev/showcase/kbd.tsx +149 -172
  98. package/src/dev/showcase/label.tsx +50 -68
  99. package/src/dev/showcase/menubar.tsx +194 -213
  100. package/src/dev/showcase/navigation-menu.tsx +119 -133
  101. package/src/dev/showcase/overview-components/ArchitectureSection.tsx +126 -0
  102. package/src/dev/showcase/overview-components/CodeBlock.tsx +50 -0
  103. package/src/dev/showcase/overview-components/ColorPaletteSection.tsx +44 -0
  104. package/src/dev/showcase/overview-components/DashboardPreview.tsx +159 -0
  105. package/src/dev/showcase/overview-components/FeatureGridSection.tsx +535 -0
  106. package/src/dev/showcase/overview-components/FooterCTA.tsx +137 -0
  107. package/src/dev/showcase/overview-components/HeroSection.tsx +65 -0
  108. package/src/dev/showcase/overview-components/PrinciplesSection.tsx +128 -0
  109. package/src/dev/showcase/overview.tsx +21 -1163
  110. package/src/dev/showcase/pagination.tsx +144 -190
  111. package/src/dev/showcase/popover.tsx +181 -196
  112. package/src/dev/showcase/progress.tsx +141 -189
  113. package/src/dev/showcase/radio-group.tsx +272 -332
  114. package/src/dev/showcase/resizable.tsx +119 -141
  115. package/src/dev/showcase/scroll-area.tsx +21 -36
  116. package/src/dev/showcase/select.tsx +262 -322
  117. package/src/dev/showcase/separator.tsx +75 -73
  118. package/src/dev/showcase/sheet.tsx +333 -361
  119. package/src/dev/showcase/sidebar.tsx +53 -59
  120. package/src/dev/showcase/skeleton.tsx +93 -112
  121. package/src/dev/showcase/slider.tsx +244 -296
  122. package/src/dev/showcase/sonner.tsx +251 -258
  123. package/src/dev/showcase/spinner.tsx +46 -67
  124. package/src/dev/showcase/switch.tsx +298 -362
  125. package/src/dev/showcase/table.tsx +76 -80
  126. package/src/dev/showcase/tabs.tsx +302 -355
  127. package/src/dev/showcase/textarea.tsx +240 -293
  128. package/src/dev/showcase/toast.tsx +48 -54
  129. package/src/dev/showcase/toggle-group.tsx +104 -129
  130. package/src/dev/showcase/toggle.tsx +82 -102
  131. package/src/dev/showcase/tooltip.tsx +173 -192
  132. package/src/dev/showcase/why.tsx +6 -12
  133. package/src/hooks/use-mobile.test.ts +3 -2
  134. package/src/lib/utils.test.ts +5 -4
@@ -12,159 +12,146 @@ import {
12
12
  import {
13
13
  DocsP,
14
14
  ExampleGrid,
15
- ExampleSection,
15
+ ShowcaseExample,
16
16
  Showcase,
17
17
  ShowcaseDocs
18
18
  } from "../../dev/components/showcase";
19
19
 
20
- // ──────────────────────────────────────────────────────────
21
- // Shared Data
22
- // ──────────────────────────────────────────────────────────
23
20
  const faqItems = [
24
21
  {
25
- q: "Is it accessible?",
26
- a: "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
22
+ q: "Hỗ trợ Accessible (a11y) không?",
23
+ a: " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
27
24
  {
28
- q: "Is it styled?",
29
- a: "Yes. It comes with default styles that match the other components' aesthetic. You can override every token via CSS variables." },
25
+ q: " CSS sẵn không?",
26
+ a: "Có nha. Style mặc định bao đẹp, match với các component khác. Override qua CSS variable." },
30
27
  {
31
- q: "Is it animated?",
32
- a: "Yes. It's animated by default with smooth expand/collapse transitions, but you can disable animation if you prefer." },
28
+ q: " animation không?",
29
+ a: "Đầy đủ. Mở ra đóng lại mượt mà, nhưng nếu không thích thì tắt cũng dễ òm." },
33
30
  {
34
- q: "Can I nest accordions?",
35
- a: "Yes. You can nest accordion components inside each other to create multi-level collapsible sections." },
31
+ q: " lồng nhau (nest) được không?",
32
+ a: "Thoải mái luôn. Bro lồng bao nhiêu cái accordion vào nhau tuỳ thích." },
36
33
  ];
37
34
 
38
35
  const presetItems = [
39
36
  {
40
37
  value: "item-1",
41
- title: "Is it accessible?",
38
+ title: "Hỗ trợ Accessible (a11y) không?",
42
39
  content:
43
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
40
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
44
41
  {
45
42
  value: "item-2",
46
- title: "Is it styled?",
43
+ title: " CSS sẵn không?",
47
44
  content:
48
- "Yes. It comes with default styles that match the other components' aesthetic." },
45
+ "Có nha. Style mặc định bao đẹp, match với các component khác. Override vô tư qua CSS variable." },
49
46
  {
50
47
  value: "item-3",
51
- title: "Is it animated?",
52
- content: "Yes. It's animated by default with smooth transitions." },
48
+ title: " animation không?",
49
+ content: "Đầy đủ. Mở ra đóng lại mượt mà, nhưng nếu không thích thì tắt cũng dễ òm." },
53
50
  ];
54
51
 
55
- // ──────────────────────────────────────────────────────────
56
- // SECTION 1: Macro Content (không export)
57
- // ──────────────────────────────────────────────────────────
58
52
  function AccordionMacroShowcase() {
59
53
  const [controlledValue, setControlledValue] = useState<string[]>([]);
60
54
 
61
55
  return (
62
- <div className="space-y-10 mt-6">
56
+ <div className="space-y-10">
63
57
  <ExampleGrid>
64
- <ExampleSection
65
- label="Tiêu Chuẩn (Standard)"
66
- description="Accordion mở đơn cơ bản."
67
- codeString={`<AccordionPreset
58
+ <ShowcaseExample title="Tiêu Chuẩn (Standard)" description="Accordion mở đơn cơ bản." code={`<AccordionPreset
68
59
  className="w-full"
69
60
  defaultValue={["item-1"]}
70
61
  items={[
71
62
  {
72
63
  value: "item-1",
73
- title: "Is it accessible?",
64
+ title: "Hỗ trợ Accessible (a11y) không?",
74
65
  content:
75
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
66
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
76
67
  {
77
68
  value: "item-2",
78
- title: "Is it styled?",
69
+ title: " CSS sẵn không?",
79
70
  content:
80
- "Yes. It comes with default styles that match the other components' aesthetic." },
71
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
81
72
  {
82
73
  value: "item-3",
83
- title: "Is it animated?",
74
+ title: " animation không?",
84
75
  content:
85
- "Yes. It's animated by default with smooth transitions." },
76
+ "Đầy đủ. Mở ra đóng lại mượt mà." },
86
77
  ]}
87
- />`}
88
- >
89
- <AccordionPreset
90
- className="w-full"
91
- defaultValue={["item-1"]}
92
- items={[
93
- {
94
- value: "item-1",
95
- title: "Is it accessible?",
96
- content:
97
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
98
- {
99
- value: "item-2",
100
- title: "Is it styled?",
101
- content:
102
- "Yes. It comes with default styles that match the other components' aesthetic." },
103
- {
104
- value: "item-3",
105
- title: "Is it animated?",
106
- content:
107
- "Yes. It's animated by default with smooth transitions." },
108
- ]}
109
- />
110
- </ExampleSection>
111
-
112
- <ExampleSection
113
- label="Mở Nhiều (Multiple Expansion)"
114
- description="Cho phép mở nhiều mục cùng một lúc."
115
- codeString={`<AccordionPreset
78
+ />`} preview={
79
+ <>
80
+ <AccordionPreset
81
+ className="w-full"
82
+ defaultValue={["item-1"]}
83
+ items={[
84
+ {
85
+ value: "item-1",
86
+ title: "Hỗ trợ Accessible (a11y) không?",
87
+ content:
88
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
89
+ {
90
+ value: "item-2",
91
+ title: " CSS sẵn không?",
92
+ content:
93
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
94
+ {
95
+ value: "item-3",
96
+ title: " animation không?",
97
+ content:
98
+ "Đầy đủ. Mở ra đóng lại mượt mà." },
99
+ ]}
100
+ />
101
+ </>
102
+ } />
103
+
104
+ <ShowcaseExample title="Mở Nhiều (Multiple Expansion)" description="Cho phép mở nhiều mục cùng một lúc." code={`<AccordionPreset
116
105
  className="w-full"
117
106
  multiple
118
107
  defaultValue={["item-1", "item-2"]}
119
108
  items={[
120
109
  {
121
110
  value: "item-1",
122
- title: "Is it accessible?",
111
+ title: "Hỗ trợ Accessible (a11y) không?",
123
112
  content:
124
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
113
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
125
114
  {
126
115
  value: "item-2",
127
- title: "Is it styled?",
116
+ title: " CSS sẵn không?",
128
117
  content:
129
- "Yes. It comes with default styles that match the other components' aesthetic." },
118
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
130
119
  {
131
120
  value: "item-3",
132
- title: "Is it animated?",
121
+ title: " animation không?",
133
122
  content:
134
- "Yes. It's animated by default with smooth transitions." },
123
+ "Đầy đủ. Mở ra đóng lại mượt mà." },
135
124
  ]}
136
- />`}
137
- >
138
- <AccordionPreset
139
- className="w-full"
140
- multiple
141
- defaultValue={["item-1", "item-2"]}
142
- items={[
143
- {
144
- value: "item-1",
145
- title: "Is it accessible?",
146
- content:
147
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
148
- {
149
- value: "item-2",
150
- title: "Is it styled?",
151
- content:
152
- "Yes. It comes with default styles that match the other components' aesthetic." },
153
- {
154
- value: "item-3",
155
- title: "Is it animated?",
156
- content:
157
- "Yes. It's animated by default with smooth transitions." },
158
- ]}
159
- />
160
- </ExampleSection>
125
+ />`} preview={
126
+ <>
127
+ <AccordionPreset
128
+ className="w-full"
129
+ multiple
130
+ defaultValue={["item-1", "item-2"]}
131
+ items={[
132
+ {
133
+ value: "item-1",
134
+ title: "Hỗ trợ Accessible (a11y) không?",
135
+ content:
136
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
137
+ {
138
+ value: "item-2",
139
+ title: " CSS sẵn không?",
140
+ content:
141
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
142
+ {
143
+ value: "item-3",
144
+ title: " animation không?",
145
+ content:
146
+ "Đầy đủ. Mở ra đóng lại mượt mà." },
147
+ ]}
148
+ />
149
+ </>
150
+ } />
161
151
  </ExampleGrid>
162
152
 
163
153
  <ExampleGrid>
164
- <ExampleSection
165
- label="Controlled"
166
- description="Trạng thái mở được quản lý bằng state. Click vào các mục để xem state thay đổi."
167
- codeString={`const [controlledValue, setControlledValue] = useState<string[]>([]);
154
+ <ShowcaseExample title="Controlled" description="Trạng thái mở được quản lý bằng state. Click vào các mục để xem state thay đổi." code={`const [controlledValue, setControlledValue] = useState<string[]>([]);
168
155
  return (
169
156
  <AccordionPreset
170
157
  className="w-full"
@@ -174,113 +161,109 @@ return (
174
161
  items={[
175
162
  {
176
163
  value: "item-1",
177
- title: "Is it accessible?",
178
- content: "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
164
+ title: "Hỗ trợ Accessible (a11y) không?",
165
+ content: " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
179
166
  {
180
167
  value: "item-2",
181
- title: "Is it styled?",
182
- content: "Yes. It comes with default styles that match the other components' aesthetic." },
168
+ title: " CSS sẵn không?",
169
+ content: "Có nha. Style mặc định bao đẹp, match với các component khác." },
183
170
  {
184
171
  value: "item-3",
185
- title: "Is it animated?",
186
- content: "Yes. It's animated by default with smooth transitions." },
172
+ title: " animation không?",
173
+ content: "Đầy đủ. Mở ra đóng lại mượt mà." },
187
174
  ]}
188
175
  />
189
- );`}
190
- >
191
- <div className="flex w-full flex-col gap-3">
192
- <p className="text-xs text-muted-foreground">
193
- Open:{" "}
194
- <code className="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">
195
- {controlledValue.length > 0
196
- ? controlledValue.map((v) => `"${v}"`).join(", ")
197
- : "(none)"}
198
- </code>
199
- </p>
200
- <AccordionPreset
201
- className="w-full"
202
- multiple
203
- value={controlledValue}
204
- onValueChange={setControlledValue}
205
- items={[
206
- {
207
- value: "item-1",
208
- title: "Is it accessible?",
209
- content:
210
- "Yes. It adheres to the WAI-ARIA design pattern. Keyboard navigation and screen readers are fully supported." },
211
- {
212
- value: "item-2",
213
- title: "Is it styled?",
214
- content:
215
- "Yes. It comes with default styles that match the other components' aesthetic." },
216
- {
217
- value: "item-3",
218
- title: "Is it animated?",
219
- content:
220
- "Yes. It's animated by default with smooth transitions." },
221
- ]}
222
- />
223
- </div>
224
- </ExampleSection>
225
-
226
- <ExampleSection
227
- label="Disabled (Vô hiệu hoá)"
228
- description="Từng mục riêng lẻ có thể bị vô hiệu hóa trong khi các mục khác vẫn tương tác bình thường."
229
- codeString={`<AccordionPreset
176
+ );`} preview={
177
+ <>
178
+ <div className="flex w-full flex-col gap-3">
179
+ <p className="text-xs text-muted-foreground">
180
+ Open:{" "}
181
+ <code className="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">
182
+ {controlledValue.length > 0
183
+ ? controlledValue.map((v) => `"${v}"`).join(", ")
184
+ : "(none)"}
185
+ </code>
186
+ </p>
187
+ <AccordionPreset
188
+ className="w-full"
189
+ multiple
190
+ value={controlledValue}
191
+ onValueChange={setControlledValue}
192
+ items={[
193
+ {
194
+ value: "item-1",
195
+ title: "Hỗ trợ Accessible (a11y) không?",
196
+ content:
197
+ " chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
198
+ {
199
+ value: "item-2",
200
+ title: " CSS sẵn không?",
201
+ content:
202
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
203
+ {
204
+ value: "item-3",
205
+ title: " animation không?",
206
+ content:
207
+ "Đầy đủ. Mở ra đóng lại mượt mà." },
208
+ ]}
209
+ />
210
+ </div>
211
+ </>
212
+ } />
213
+
214
+ <ShowcaseExample title="Disabled (Vô hiệu hoá)" description="Từng mục riêng lẻ có thể bị vô hiệu hóa trong khi các mục khác vẫn tương tác bình thường." code={`<AccordionPreset
230
215
  className="w-full"
231
216
  items={[
232
217
  {
233
218
  value: "enabled-1",
234
- title: "Available Feature",
219
+ title: "Tính năng có sẵn",
235
220
  content:
236
221
  "This feature is available and can be expanded normally." },
237
222
  {
238
223
  value: "disabled-1",
239
- title: "Premium Feature (Locked)",
224
+ title: "Tính năng Premium (Đã khoá)",
240
225
  content:
241
- "This content is hidden behind a premium plan.",
226
+ "Nội dung này yêu cầu gói tài khoản Premium.",
242
227
  disabled: true },
243
228
  {
244
229
  value: "enabled-2",
245
- title: "Another Feature",
230
+ title: "Tính năng khác",
246
231
  content:
247
232
  "This is another available feature you can interact with freely." },
248
233
  ]}
249
- />`}
250
- >
251
- <AccordionPreset
252
- className="w-full"
253
- items={[
254
- {
255
- value: "enabled-1",
256
- title: "Available Feature",
257
- content:
258
- "This feature is available and can be expanded normally." },
259
- {
260
- value: "disabled-1",
261
- title: "Premium Feature (Locked)",
262
- content: "This content is hidden behind a premium plan.",
263
- disabled: true },
264
- {
265
- value: "enabled-2",
266
- title: "Another Feature",
267
- content:
268
- "This is another available feature you can interact with freely." },
269
- ]}
270
- />
271
- </ExampleSection>
234
+ />`} preview={
235
+ <>
236
+ <AccordionPreset
237
+ className="w-full"
238
+ items={[
239
+ {
240
+ value: "enabled-1",
241
+ title: "Tính năng có sẵn",
242
+ content:
243
+ "This feature is available and can be expanded normally." },
244
+ {
245
+ value: "disabled-1",
246
+ title: "Tính năng Premium (Đã khoá)",
247
+ content: "Nội dung này yêu cầu gói tài khoản Premium.",
248
+ disabled: true },
249
+ {
250
+ value: "enabled-2",
251
+ title: "Tính năng khác",
252
+ content:
253
+ "This is another available feature you can interact with freely." },
254
+ ]}
255
+ />
256
+ </>
257
+ } />
272
258
  </ExampleGrid>
273
259
 
274
260
  <ExampleGrid>
275
- <ExampleSection
276
- label="Nội Dung Phức Tạp"
277
- description="Render các React Node bên trong nội dung."
278
- codeString={`<AccordionPreset
261
+ <ShowcaseExample title="Nội Dung Phức Tạp" description="Render các React Node bên trong nội dung." code={`<AccordionPreset
279
262
  className="w-full"
280
263
  items={[
281
264
  {
282
265
  value: "profile",
283
- title: "User Profile Settings",
266
+ title: "Cài đặt Hồ sơ Người dùng",
284
267
  content: (
285
268
  <div className="flex flex-col items-start gap-3">
286
269
  <p className="text-sm">
@@ -293,44 +276,42 @@ return (
293
276
  </div>
294
277
  ) },
295
278
  ]}
296
- />`}
297
- >
298
- <AccordionPreset
299
- className="w-full"
300
- items={[
301
- {
302
- value: "profile",
303
- title: "User Profile Settings",
304
- content: (
305
- <div className="flex flex-col items-start gap-3">
306
- <p className="text-sm">
307
- Update your personal information and preferences.
308
- </p>
309
- <button className="rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground">
310
- Edit Profile
311
- </button>
312
- </div>
313
- ) },
314
- ]}
315
- />
316
- </ExampleSection>
317
-
318
- <ExampleSection
319
- label="Lồng Nhau (Nested Accordions)"
320
- description="Nội dung bên trong có thể chứa một Accordion khác."
321
- codeString={`<AccordionPreset
279
+ />`} preview={
280
+ <>
281
+ <AccordionPreset
282
+ className="w-full"
283
+ items={[
284
+ {
285
+ value: "profile",
286
+ title: "Cài đặt Hồ sơ Người dùng",
287
+ content: (
288
+ <div className="flex flex-col items-start gap-3">
289
+ <p className="text-sm">
290
+ Update your personal information and preferences.
291
+ </p>
292
+ <button className="rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground">
293
+ Edit Profile
294
+ </button>
295
+ </div>
296
+ ) },
297
+ ]}
298
+ />
299
+ </>
300
+ } />
301
+
302
+ <ShowcaseExample title="Lồng Nhau (Nested Accordions)" description="Nội dung bên trong có thể chứa một Accordion khác." code={`<AccordionPreset
322
303
  className="w-full"
323
304
  items={[
324
305
  {
325
306
  value: "getting-started",
326
- title: "Getting Started",
307
+ title: "Bắt đầu nhanh",
327
308
  content: (
328
309
  <AccordionPreset
329
310
  className="w-full"
330
311
  items={[
331
312
  {
332
313
  value: "installation",
333
- title: "Installation",
314
+ title: "Cài đặt",
334
315
  content:
335
316
  "Run npm install to add the component to your project." },
336
317
  ]}
@@ -338,81 +319,76 @@ return (
338
319
  ) },
339
320
  {
340
321
  value: "advanced",
341
- title: "Advanced Usage",
322
+ title: "Sử dụng nâng cao",
342
323
  content: (
343
324
  <AccordionPreset
344
325
  className="w-full"
345
326
  items={[
346
327
  {
347
328
  value: "controlled",
348
- title: "Controlled Mode",
329
+ title: "Chế độ Controlled",
349
330
  content:
350
- "Use the value and onValueChange props to control which items are open." },
331
+ "Sử dụng props value onValueChange để kiểm soát các mục đang mở." },
351
332
  ]}
352
333
  />
353
334
  ) },
354
335
  ]}
355
- />`}
356
- >
357
- <AccordionPreset
358
- className="w-full"
359
- items={[
360
- {
361
- value: "getting-started",
362
- title: "Getting Started",
363
- content: (
364
- <AccordionPreset
365
- className="w-full"
366
- items={[
367
- {
368
- value: "installation",
369
- title: "Installation",
370
- content:
371
- "Run npm install to add the component to your project." },
372
- ]}
373
- />
374
- ) },
375
- {
376
- value: "advanced",
377
- title: "Advanced Usage",
378
- content: (
379
- <AccordionPreset
380
- className="w-full"
381
- items={[
382
- {
383
- value: "controlled",
384
- title: "Controlled Mode",
385
- content:
386
- "Use the value and onValueChange props to control which items are open." },
387
- ]}
388
- />
389
- ) },
390
- ]}
391
- />
392
- </ExampleSection>
336
+ />`} preview={
337
+ <>
338
+ <AccordionPreset
339
+ className="w-full"
340
+ items={[
341
+ {
342
+ value: "getting-started",
343
+ title: "Bắt đầu nhanh",
344
+ content: (
345
+ <AccordionPreset
346
+ className="w-full"
347
+ items={[
348
+ {
349
+ value: "installation",
350
+ title: "Cài đặt",
351
+ content:
352
+ "Run npm install to add the component to your project." },
353
+ ]}
354
+ />
355
+ ) },
356
+ {
357
+ value: "advanced",
358
+ title: "Sử dụng nâng cao",
359
+ content: (
360
+ <AccordionPreset
361
+ className="w-full"
362
+ items={[
363
+ {
364
+ value: "controlled",
365
+ title: "Chế độ Controlled",
366
+ content:
367
+ "Sử dụng props value onValueChange để kiểm soát các mục đang mở." },
368
+ ]}
369
+ />
370
+ ) },
371
+ ]}
372
+ />
373
+ </>
374
+ } />
393
375
  </ExampleGrid>
394
376
  </div>
395
377
  );
396
378
  }
397
379
 
398
- // ──────────────────────────────────────────────────────────
399
- // SECTION 2: Micro Content (không export)
400
- // ──────────────────────────────────────────────────────────
401
380
  function AccordionMicroShowcase() {
402
381
  return (
403
- <div className="space-y-10 mt-6">
382
+ <div className="space-y-10">
404
383
  <ExampleGrid>
405
- <ExampleSection
406
- label="Mở Đơn (Single Expand)"
407
- description="Chỉ một mục được phép mở tại một thời điểm (mặc định)."
408
- codeString={`<Accordion
384
+ <ShowcaseExample title="Mở Đơn (Single Expand)" description="Chỉ một mục được phép mở tại một thời điểm (mặc định)." code={`<Accordion
409
385
  className="w-full"
410
- defaultValue={["Is it accessible?"]}
386
+ defaultValue={["Hỗ trợ Accessible (a11y) không?"]}
411
387
  >
412
- <AccordionItem value="Is it accessible?">
388
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
413
389
  <AccordionTrigger>Is it accessible?</AccordionTrigger>
414
390
  <AccordionContent>
415
- Yes. It adheres to the WAI-ARIA design pattern.
391
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
416
392
  Keyboard navigation and screen readers are fully
417
393
  supported.
418
394
  </AccordionContent>
@@ -433,43 +409,41 @@ function AccordionMicroShowcase() {
433
409
  animation if you prefer.
434
410
  </AccordionContent>
435
411
  </AccordionItem>
436
- </Accordion>`}
437
- >
438
- <Accordion className="w-full" defaultValue={["Is it accessible?"]}>
439
- <AccordionItem value="Is it accessible?">
440
- <AccordionTrigger>Is it accessible?</AccordionTrigger>
441
- <AccordionContent>
442
- Yes. It adheres to the WAI-ARIA design pattern.
443
- </AccordionContent>
444
- </AccordionItem>
445
- <AccordionItem value="Is it styled?">
446
- <AccordionTrigger>Is it styled?</AccordionTrigger>
447
- <AccordionContent>
448
- Yes. It comes with default styles that match the other
449
- components' aesthetic.
450
- </AccordionContent>
451
- </AccordionItem>
452
- <AccordionItem value="Is it animated?">
453
- <AccordionTrigger>Is it animated?</AccordionTrigger>
454
- <AccordionContent>
455
- Yes. It's animated by default with smooth transitions.
456
- </AccordionContent>
457
- </AccordionItem>
458
- </Accordion>
459
- </ExampleSection>
460
-
461
- <ExampleSection
462
- label="Mở Nhiều (Multiple Expand)"
463
- description="Cho phép mở nhiều mục cùng lúc."
464
- codeString={`<Accordion
412
+ </Accordion>`} preview={
413
+ <>
414
+ <Accordion className="w-full" defaultValue={["Hỗ trợ Accessible (a11y) không?"]}>
415
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
416
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
417
+ <AccordionContent>
418
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
419
+ </AccordionContent>
420
+ </AccordionItem>
421
+ <AccordionItem value="Is it styled?">
422
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
423
+ <AccordionContent>
424
+ Yes. It comes with default styles that match the other
425
+ components' aesthetic.
426
+ </AccordionContent>
427
+ </AccordionItem>
428
+ <AccordionItem value="Is it animated?">
429
+ <AccordionTrigger>Is it animated?</AccordionTrigger>
430
+ <AccordionContent>
431
+ Đầy đủ. Mở ra đóng lại mượt mà.
432
+ </AccordionContent>
433
+ </AccordionItem>
434
+ </Accordion>
435
+ </>
436
+ } />
437
+
438
+ <ShowcaseExample title="Mở Nhiều (Multiple Expand)" description="Cho phép mở nhiều mục cùng lúc." code={`<Accordion
465
439
  className="w-full"
466
440
  multiple
467
- defaultValue={["Is it accessible?", "Is it styled?"]}
441
+ defaultValue={["Hỗ trợ Accessible (a11y) không?", "Is it styled?"]}
468
442
  >
469
- <AccordionItem value="Is it accessible?">
443
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
470
444
  <AccordionTrigger>Is it accessible?</AccordionTrigger>
471
445
  <AccordionContent>
472
- Yes. It adheres to the WAI-ARIA design pattern.
446
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
473
447
  Keyboard navigation and screen readers are fully
474
448
  supported.
475
449
  </AccordionContent>
@@ -490,41 +464,39 @@ function AccordionMicroShowcase() {
490
464
  animation if you prefer.
491
465
  </AccordionContent>
492
466
  </AccordionItem>
493
- </Accordion>`}
494
- >
495
- <Accordion
496
- className="w-full"
497
- multiple
498
- defaultValue={["Is it accessible?", "Is it styled?"]}
499
- >
500
- <AccordionItem value="Is it accessible?">
501
- <AccordionTrigger>Is it accessible?</AccordionTrigger>
502
- <AccordionContent>
503
- Yes. It adheres to the WAI-ARIA design pattern.
504
- </AccordionContent>
505
- </AccordionItem>
506
- <AccordionItem value="Is it styled?">
507
- <AccordionTrigger>Is it styled?</AccordionTrigger>
508
- <AccordionContent>
509
- Yes. It comes with default styles that match the other
510
- components' aesthetic.
511
- </AccordionContent>
512
- </AccordionItem>
513
- <AccordionItem value="Is it animated?">
514
- <AccordionTrigger>Is it animated?</AccordionTrigger>
515
- <AccordionContent>
516
- Yes. It's animated by default with smooth transitions.
517
- </AccordionContent>
518
- </AccordionItem>
519
- </Accordion>
520
- </ExampleSection>
467
+ </Accordion>`} preview={
468
+ <>
469
+ <Accordion
470
+ className="w-full"
471
+ multiple
472
+ defaultValue={["Hỗ trợ Accessible (a11y) không?", "Is it styled?"]}
473
+ >
474
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
475
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
476
+ <AccordionContent>
477
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
478
+ </AccordionContent>
479
+ </AccordionItem>
480
+ <AccordionItem value="Is it styled?">
481
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
482
+ <AccordionContent>
483
+ Yes. It comes with default styles that match the other
484
+ components' aesthetic.
485
+ </AccordionContent>
486
+ </AccordionItem>
487
+ <AccordionItem value="Is it animated?">
488
+ <AccordionTrigger>Is it animated?</AccordionTrigger>
489
+ <AccordionContent>
490
+ Đầy đủ. Mở ra đóng lại mượt mà.
491
+ </AccordionContent>
492
+ </AccordionItem>
493
+ </Accordion>
494
+ </>
495
+ } />
521
496
  </ExampleGrid>
522
497
 
523
498
  <ExampleGrid>
524
- <ExampleSection
525
- label="Disabled (Vô hiệu hoá)"
526
- description="Từng mục riêng lẻ có thể bị vô hiệu hóa trong khi các mục khác vẫn tương tác bình thường."
527
- codeString={`<Accordion className="w-full">
499
+ <ShowcaseExample title="Disabled (Vô hiệu hoá)" description="Từng mục riêng lẻ có thể bị vô hiệu hóa trong khi các mục khác vẫn tương tác bình thường." code={`<Accordion className="w-full">
528
500
  <AccordionItem value="enabled-1">
529
501
  <AccordionTrigger>Available Feature</AccordionTrigger>
530
502
  <AccordionContent>
@@ -547,35 +519,33 @@ function AccordionMicroShowcase() {
547
519
  with freely.
548
520
  </AccordionContent>
549
521
  </AccordionItem>
550
- </Accordion>`}
551
- >
552
- <Accordion className="w-full">
553
- <AccordionItem value="enabled-1">
554
- <AccordionTrigger>Available Feature</AccordionTrigger>
555
- <AccordionContent>
556
- This feature is available and can be expanded normally. Click to
557
- see the details.
558
- </AccordionContent>
559
- </AccordionItem>
560
- <AccordionItem value="disabled-1" disabled>
561
- <AccordionTrigger>Premium Feature (Locked)</AccordionTrigger>
562
- <AccordionContent>
563
- This content is hidden behind a premium plan.
564
- </AccordionContent>
565
- </AccordionItem>
566
- <AccordionItem value="enabled-2">
567
- <AccordionTrigger>Another Feature</AccordionTrigger>
568
- <AccordionContent>
569
- This is another available feature you can interact with freely.
570
- </AccordionContent>
571
- </AccordionItem>
572
- </Accordion>
573
- </ExampleSection>
574
-
575
- <ExampleSection
576
- label="Lồng Nhau (Nested Accordions)"
577
- description="Nội dung bên trong có thể chứa một Accordion khác để tạo cấu trúc nhiều cấp."
578
- codeString={`<Accordion className="w-full max-w-lg">
522
+ </Accordion>`} preview={
523
+ <>
524
+ <Accordion className="w-full">
525
+ <AccordionItem value="enabled-1">
526
+ <AccordionTrigger>Available Feature</AccordionTrigger>
527
+ <AccordionContent>
528
+ This feature is available and can be expanded normally. Click to
529
+ see the details.
530
+ </AccordionContent>
531
+ </AccordionItem>
532
+ <AccordionItem value="disabled-1" disabled>
533
+ <AccordionTrigger>Premium Feature (Locked)</AccordionTrigger>
534
+ <AccordionContent>
535
+ This content is hidden behind a premium plan.
536
+ </AccordionContent>
537
+ </AccordionItem>
538
+ <AccordionItem value="enabled-2">
539
+ <AccordionTrigger>Another Feature</AccordionTrigger>
540
+ <AccordionContent>
541
+ This is another available feature you can interact with freely.
542
+ </AccordionContent>
543
+ </AccordionItem>
544
+ </Accordion>
545
+ </>
546
+ } />
547
+
548
+ <ShowcaseExample title="Lồng Nhau (Nested Accordions)" description="Nội dung bên trong có thể chứa một Accordion khác để tạo cấu trúc nhiều cấp." code={`<Accordion className="w-full max-w-lg">
579
549
  <AccordionItem value="getting-started">
580
550
  <AccordionTrigger>Getting Started</AccordionTrigger>
581
551
  <AccordionContent>
@@ -602,21 +572,21 @@ function AccordionMicroShowcase() {
602
572
  </AccordionContent>
603
573
  </AccordionItem>
604
574
  <AccordionItem value="advanced">
605
- <AccordionTrigger>Advanced Usage</AccordionTrigger>
575
+ <AccordionTrigger>Sử dụng nâng cao</AccordionTrigger>
606
576
  <AccordionContent>
607
577
  <Accordion>
608
578
  <AccordionItem value="controlled">
609
579
  <AccordionTrigger>
610
- Controlled Mode
580
+ Chế độ Controlled
611
581
  </AccordionTrigger>
612
582
  <AccordionContent>
613
583
  Use the value and onValueChange props to
614
- control which items are open.
584
+ control which các mục đang mở.
615
585
  </AccordionContent>
616
586
  </AccordionItem>
617
587
  <AccordionItem value="animation">
618
588
  <AccordionTrigger>
619
- Custom Animation
589
+ Tuỳ chỉnh Animation
620
590
  </AccordionTrigger>
621
591
  <AccordionContent>
622
592
  Override transition duration and easing via
@@ -626,60 +596,58 @@ function AccordionMicroShowcase() {
626
596
  </Accordion>
627
597
  </AccordionContent>
628
598
  </AccordionItem>
629
- </Accordion>`}
630
- >
631
- <Accordion className="w-full max-w-lg">
632
- <AccordionItem value="getting-started">
633
- <AccordionTrigger>Getting Started</AccordionTrigger>
634
- <AccordionContent>
635
- <Accordion>
636
- <AccordionItem value="installation">
637
- <AccordionTrigger>Installation</AccordionTrigger>
638
- <AccordionContent>
639
- Run npm install to add the component to your project.
640
- </AccordionContent>
641
- </AccordionItem>
642
- <AccordionItem value="configuration">
643
- <AccordionTrigger>Configuration</AccordionTrigger>
644
- <AccordionContent>
645
- Import and wrap your content with the Accordion component.
646
- </AccordionContent>
647
- </AccordionItem>
648
- </Accordion>
649
- </AccordionContent>
650
- </AccordionItem>
651
- <AccordionItem value="advanced">
652
- <AccordionTrigger>Advanced Usage</AccordionTrigger>
653
- <AccordionContent>
654
- <Accordion>
655
- <AccordionItem value="controlled">
656
- <AccordionTrigger>Controlled Mode</AccordionTrigger>
657
- <AccordionContent>
658
- Use the value and onValueChange props to control which
659
- items are open.
660
- </AccordionContent>
661
- </AccordionItem>
662
- <AccordionItem value="animation">
663
- <AccordionTrigger>Custom Animation</AccordionTrigger>
664
- <AccordionContent>
665
- Override transition duration and easing via className.
666
- </AccordionContent>
667
- </AccordionItem>
668
- </Accordion>
669
- </AccordionContent>
670
- </AccordionItem>
671
- </Accordion>
672
- </ExampleSection>
599
+ </Accordion>`} preview={
600
+ <>
601
+ <Accordion className="w-full max-w-lg">
602
+ <AccordionItem value="getting-started">
603
+ <AccordionTrigger>Getting Started</AccordionTrigger>
604
+ <AccordionContent>
605
+ <Accordion>
606
+ <AccordionItem value="installation">
607
+ <AccordionTrigger>Installation</AccordionTrigger>
608
+ <AccordionContent>
609
+ Run npm install to add the component to your project.
610
+ </AccordionContent>
611
+ </AccordionItem>
612
+ <AccordionItem value="configuration">
613
+ <AccordionTrigger>Configuration</AccordionTrigger>
614
+ <AccordionContent>
615
+ Import and wrap your content with the Accordion component.
616
+ </AccordionContent>
617
+ </AccordionItem>
618
+ </Accordion>
619
+ </AccordionContent>
620
+ </AccordionItem>
621
+ <AccordionItem value="advanced">
622
+ <AccordionTrigger>Sử dụng nâng cao</AccordionTrigger>
623
+ <AccordionContent>
624
+ <Accordion>
625
+ <AccordionItem value="controlled">
626
+ <AccordionTrigger>Chế độ Controlled</AccordionTrigger>
627
+ <AccordionContent>
628
+ Sử dụng props value onValueChange để kiểm soát
629
+ các mục đang mở.
630
+ </AccordionContent>
631
+ </AccordionItem>
632
+ <AccordionItem value="animation">
633
+ <AccordionTrigger>Tuỳ chỉnh Animation</AccordionTrigger>
634
+ <AccordionContent>
635
+ Thay đổi thời gian chuyển đổi và easing thông qua className.
636
+ </AccordionContent>
637
+ </AccordionItem>
638
+ </Accordion>
639
+ </AccordionContent>
640
+ </AccordionItem>
641
+ </Accordion>
642
+ </>
643
+ } />
673
644
  </ExampleGrid>
674
645
 
675
- <ExampleSection
676
- label="FAQ Hoàn Chỉnh"
677
- description="Ví dụ một phần hỏi đáp FAQ hoàn chỉnh."
678
- codeString={`<Accordion className="w-full max-w-lg">
679
- <AccordionItem value="Is it accessible?">
646
+ <ShowcaseExample title="FAQ Hoàn Chỉnh" description="Ví dụ một phần hỏi đáp FAQ hoàn chỉnh." code={`<Accordion className="w-full max-w-lg">
647
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
680
648
  <AccordionTrigger>Is it accessible?</AccordionTrigger>
681
649
  <AccordionContent>
682
- Yes. It adheres to the WAI-ARIA design pattern.
650
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
683
651
  Keyboard navigation and screen readers are fully
684
652
  supported.
685
653
  </AccordionContent>
@@ -709,44 +677,40 @@ function AccordionMicroShowcase() {
709
677
  other to create multi-level collapsible sections.
710
678
  </AccordionContent>
711
679
  </AccordionItem>
712
- </Accordion>`}
713
- >
714
- <Accordion className="w-full max-w-lg">
715
- <AccordionItem value="Is it accessible?">
716
- <AccordionTrigger>Is it accessible?</AccordionTrigger>
717
- <AccordionContent>
718
- Yes. It adheres to the WAI-ARIA design pattern.
719
- </AccordionContent>
720
- </AccordionItem>
721
- <AccordionItem value="Is it styled?">
722
- <AccordionTrigger>Is it styled?</AccordionTrigger>
723
- <AccordionContent>
724
- Yes. It comes with default styles that match the other components'
725
- aesthetic.
726
- </AccordionContent>
727
- </AccordionItem>
728
- <AccordionItem value="Is it animated?">
729
- <AccordionTrigger>Is it animated?</AccordionTrigger>
730
- <AccordionContent>
731
- Yes. It's animated by default with smooth transitions.
732
- </AccordionContent>
733
- </AccordionItem>
734
- <AccordionItem value="Can I nest accordions?">
735
- <AccordionTrigger>Can I nest accordions?</AccordionTrigger>
736
- <AccordionContent>
737
- Yes. You can nest accordion components inside each other to create
738
- multi-level collapsible sections.
739
- </AccordionContent>
740
- </AccordionItem>
741
- </Accordion>
742
- </ExampleSection>
743
-
744
- {/* ── Use Case Comparison ─────────────────────── */}
745
- <ExampleSection
746
- label="🧭 Use Case Comparison"
747
- description="Các kịch bản thực tế giúp bạn quyết định nên dùng Micro (Accordion) hay Macro (AccordionPreset)."
748
- fullWidth
749
- codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
680
+ </Accordion>`} preview={
681
+ <>
682
+ <Accordion className="w-full max-w-lg">
683
+ <AccordionItem value="Hỗ trợ Accessible (a11y) không?">
684
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
685
+ <AccordionContent>
686
+ chứ. Component tuân thủ chuẩn WAI-ARIA.
687
+ </AccordionContent>
688
+ </AccordionItem>
689
+ <AccordionItem value="Is it styled?">
690
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
691
+ <AccordionContent>
692
+ Yes. It comes with default styles that match the other components'
693
+ aesthetic.
694
+ </AccordionContent>
695
+ </AccordionItem>
696
+ <AccordionItem value="Is it animated?">
697
+ <AccordionTrigger>Is it animated?</AccordionTrigger>
698
+ <AccordionContent>
699
+ Đầy đủ. Mở ra đóng lại mượt mà.
700
+ </AccordionContent>
701
+ </AccordionItem>
702
+ <AccordionItem value="Can I nest accordions?">
703
+ <AccordionTrigger>Can I nest accordions?</AccordionTrigger>
704
+ <AccordionContent>
705
+ Yes. You can nest accordion components inside each other to create
706
+ multi-level collapsible sections.
707
+ </AccordionContent>
708
+ </AccordionItem>
709
+ </Accordion>
710
+ </>
711
+ } />
712
+
713
+ <ShowcaseExample title="🧭 So sánh Use Case" description="Các kịch bản thực tế giúp bạn quyết định nên dùng Micro (Accordion) hay Macro (AccordionPreset)." code={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
750
714
  {/* ── Story 1: Macro wins ── */}
751
715
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
752
716
  <div className="flex items-start gap-3">
@@ -777,15 +741,15 @@ function AccordionMicroShowcase() {
777
741
  className="w-full"
778
742
  items={[
779
743
  {
780
- value: "Is it accessible?",
781
- title: "Is it accessible?",
744
+ value: "Hỗ trợ Accessible (a11y) không?",
745
+ title: "Hỗ trợ Accessible (a11y) không?",
782
746
  content:
783
- "Yes. It adheres to the WAI-ARIA design pattern." },
747
+ " chứ. Component tuân thủ chuẩn WAI-ARIA." },
784
748
  {
785
749
  value: "Is it styled?",
786
- title: "Is it styled?",
750
+ title: " CSS sẵn không?",
787
751
  content:
788
- "Yes. It comes with default styles that match the other components' aesthetic." },
752
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
789
753
  ]}
790
754
  />
791
755
  </div>
@@ -828,7 +792,7 @@ function AccordionMicroShowcase() {
828
792
  <AccordionTrigger className="gap-3">
829
793
  <SlidersHorizontalIcon className="size-4 text-primary" />
830
794
  <span className="flex-1 text-left">
831
- Advanced Settings
795
+ Cài đặt nâng cao
832
796
  </span>
833
797
  <span className="mr-2 rounded bg-primary/10 px-2 py-0.5 text-[10px] uppercase tracking-wider text-primary">
834
798
  New
@@ -855,133 +819,127 @@ function AccordionMicroShowcase() {
855
819
  </p>
856
820
  </div>
857
821
  </div>
858
- </div>`}
859
- >
860
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
861
- {/* ── Story 1: Macro wins ── */}
862
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
863
- <div className="flex items-start gap-3">
864
- <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
865
- <SettingsIcon className="size-4" aria-hidden="true" />
866
- </span>
867
- <div>
868
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
869
- Story 1 · Dùng Macro
870
- </p>
871
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
872
- Render danh sách FAQ từ API
873
- </h3>
874
- </div>
875
- </div>
876
-
877
- <p className="text-xs text-muted-foreground leading-relaxed">
878
- Bạn nhận được một mảng dữ liệu FAQ (hỏi đáp) từ server. Nội dung
879
- đơn giản chỉ là text. Dùng Macro để tiết kiệm code.
880
- </p>
881
-
882
- <div className="rounded-lg bg-muted/50 p-3">
883
- <AccordionPreset
884
- className="w-full"
885
- items={[
886
- {
887
- value: "Is it accessible?",
888
- title: "Is it accessible?",
889
- content: "Yes. It adheres to the WAI-ARIA design pattern." },
890
- {
891
- value: "Is it styled?",
892
- title: "Is it styled?",
893
- content:
894
- "Yes. It comes with default styles that match the other components' aesthetic." },
895
- ]}
896
- />
897
- </div>
898
-
899
- <div className="rounded-md border border-border border-green-500/20 bg-green-500/5 px-3 py-2">
900
- <p className="text-xs font-medium text-green-700 dark:text-green-400">
901
- Dùng <code className="font-mono">AccordionPreset</code> Tự
902
- động lặp qua array, không cần viết lại JSX cho từng thẻ Item.
903
- </p>
904
- </div>
905
- </div>
906
-
907
- {/* ── Story 2: Micro wins ── */}
908
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
909
- <div className="flex items-start gap-3">
910
- <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
911
- <BoxIcon className="size-4" aria-hidden="true" />
912
- </span>
913
- <div>
914
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
915
- Story 2 · Dùng Micro
916
- </p>
917
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
918
- Tuỳ biến Trigger / Form phức tạp
919
- </h3>
920
- </div>
921
- </div>
922
-
923
- <p className="text-xs text-muted-foreground leading-relaxed">
924
- Trigger cần hiển thị Icon hoặc Badge. Nội dung bên trong là một
925
- Form phức tạp (chứ không phải text đơn thuần). Macro không thể làm
926
- được việc này.
927
- </p>
822
+ </div>`} preview={
823
+ <>
824
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
825
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
826
+ <div className="flex items-start gap-3">
827
+ <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
828
+ <SettingsIcon className="size-4" aria-hidden="true" />
829
+ </span>
830
+ <div>
831
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
832
+ Story 1 · Dùng Macro
833
+ </p>
834
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
835
+ Render danh sách FAQ từ API
836
+ </h3>
837
+ </div>
838
+ </div>
839
+
840
+ <p className="text-xs text-muted-foreground leading-relaxed">
841
+ Bạn nhận được một mảng dữ liệu FAQ (hỏi đáp) từ server. Nội dung
842
+ đơn giản chỉ text. Dùng Macro để tiết kiệm code.
843
+ </p>
844
+
845
+ <div className="rounded-lg bg-muted/50 p-3">
846
+ <AccordionPreset
847
+ className="w-full"
848
+ items={[
849
+ {
850
+ value: "Hỗ trợ Accessible (a11y) không?",
851
+ title: "Hỗ trợ Accessible (a11y) không?",
852
+ content: " chứ. Component tuân thủ chuẩn WAI-ARIA." },
853
+ {
854
+ value: "Is it styled?",
855
+ title: " CSS sẵn không?",
856
+ content:
857
+ "Có nha. Style mặc định bao đẹp, match với các component khác." },
858
+ ]}
859
+ />
860
+ </div>
861
+
862
+ <div className="rounded-md border border-border border-green-500/20 bg-green-500/5 px-3 py-2">
863
+ <p className="text-xs font-medium text-green-700 dark:text-green-400">
864
+ ✅ Dùng <code className="font-mono">AccordionPreset</code> Tự
865
+ động lặp qua array, không cần viết lại JSX cho từng thẻ Item.
866
+ </p>
867
+ </div>
868
+ </div>
928
869
 
929
- <div className="rounded-lg bg-muted/50 p-3">
930
- <Accordion className="w-full">
931
- <AccordionItem value="settings">
932
- <AccordionTrigger className="gap-3">
933
- <SlidersHorizontalIcon className="size-4 text-primary" />
934
- <span className="flex-1 text-left">Advanced Settings</span>
935
- <span className="mr-2 rounded bg-primary/10 px-2 py-0.5 text-[10px] uppercase tracking-wider text-primary">
936
- New
937
- </span>
938
- </AccordionTrigger>
939
- <AccordionContent>
940
- <div className="flex items-center gap-3 rounded border border-border p-3 text-xs text-muted-foreground">
941
- <span>
942
- Nội dung tuỳ biến hoàn toàn, ví dụ: Form, Toggle, v.v.
943
- </span>
870
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
871
+ <div className="flex items-start gap-3">
872
+ <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
873
+ <BoxIcon className="size-4" aria-hidden="true" />
874
+ </span>
875
+ <div>
876
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
877
+ Story 2 · Dùng Micro
878
+ </p>
879
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
880
+ Tuỳ biến Trigger / Form phức tạp
881
+ </h3>
882
+ </div>
883
+ </div>
884
+
885
+ <p className="text-xs text-muted-foreground leading-relaxed">
886
+ Trigger cần hiển thị Icon hoặc Badge. Nội dung bên trong là một
887
+ Form phức tạp (chứ không phải text đơn thuần). Macro không thể làm
888
+ được việc này.
889
+ </p>
890
+
891
+ <div className="rounded-lg bg-muted/50 p-3">
892
+ <Accordion className="w-full">
893
+ <AccordionItem value="settings">
894
+ <AccordionTrigger className="gap-3">
895
+ <SlidersHorizontalIcon className="size-4 text-primary" />
896
+ <span className="flex-1 text-left">Cài đặt nâng cao</span>
897
+ <span className="mr-2 rounded bg-primary/10 px-2 py-0.5 text-[10px] uppercase tracking-wider text-primary">
898
+ New
899
+ </span>
900
+ </AccordionTrigger>
901
+ <AccordionContent>
902
+ <div className="flex items-center gap-3 rounded border border-border p-3 text-xs text-muted-foreground">
903
+ <span>
904
+ Nội dung tuỳ biến hoàn toàn, ví dụ: Form, Toggle, v.v.
905
+ </span>
906
+ </div>
907
+ </AccordionContent>
908
+ </AccordionItem>
909
+ </Accordion>
910
+ </div>
911
+
912
+ <div className="rounded-md border border-border border-blue-500/20 bg-blue-500/5 px-3 py-2">
913
+ <p className="text-xs font-medium text-blue-700 dark:text-blue-400">
914
+ ✅ Dùng <code className="font-mono">Accordion</code> (Micro) —
915
+ Toàn quyền kiểm soát cấu trúc HTML của Trigger và Content.
916
+ </p>
917
+ </div>
944
918
  </div>
945
- </AccordionContent>
946
- </AccordionItem>
947
- </Accordion>
948
- </div>
949
-
950
- <div className="rounded-md border border-border border-blue-500/20 bg-blue-500/5 px-3 py-2">
951
- <p className="text-xs font-medium text-blue-700 dark:text-blue-400">
952
- ✅ Dùng <code className="font-mono">Accordion</code> (Micro) —
953
- Toàn quyền kiểm soát cấu trúc HTML của Trigger và Content.
954
- </p>
955
- </div>
956
- </div>
957
- </div>
958
- </ExampleSection>
919
+ </div>
920
+ </>
921
+ } />
959
922
  </div>
960
923
  );
961
924
  }
962
925
 
963
- // ──────────────────────────────────────────────────────────
964
- // SECTION 3: Entry point (export default)
965
- // ──────────────────────────────────────────────────────────
966
926
  export default function AccordionShowcase() {
967
927
  return (
968
928
  <Showcase
969
929
  title="Accordion"
970
930
  description="Tập hợp các tiêu đề có thể tương tác xếp chồng lên nhau theo chiều dọc, mỗi tiêu đề sẽ mở ra một phần nội dung."
971
- generalConcept={
931
+ guideline={
972
932
  <ShowcaseDocs>
973
933
  <DocsP>
974
934
  Dùng để gom nhóm các khối nội dung lớn nhằm tiết kiệm không gian
975
- hiển thị (ví dụ: FAQ, Advanced Settings). Không nên dùng Accordion
935
+ hiển thị (ví dụ: FAQ, Cài đặt nâng cao). Không nên dùng Accordion
976
936
  nếu nội dung bên trong quá quan trọng và cần user phải nhìn thấy
977
937
  ngay lập tức.
978
938
  </DocsP>
979
939
  </ShowcaseDocs>
980
940
  }
981
- tabs={[
982
- { label: "Micro (Primitive)", content: <AccordionMicroShowcase /> },
983
- { label: "Macro (Preset)", content: <AccordionMacroShowcase /> },
984
- ]}
941
+ micro={{ content: <AccordionMicroShowcase /> }}
942
+ macro={{ content: <AccordionMacroShowcase /> }}
985
943
  />
986
944
  );
987
945
  }