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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/scripts/strip-comments.ts +79 -0
- package/src/blocks/auth-form.tsx +34 -30
- package/src/blocks/auth-recovery.tsx +9 -13
- package/src/blocks/auth-split.tsx +46 -36
- package/src/blocks/settings.tsx +84 -117
- package/src/components/macro/alert-preset.tsx +3 -1
- package/src/components/macro/carousel-preset.tsx +0 -1
- package/src/components/macro/checkbox-preset.test.tsx +2 -2
- package/src/components/macro/checkbox-preset.tsx +1 -2
- package/src/components/macro/command-preset.tsx +1 -1
- package/src/components/macro/date-picker.tsx +5 -18
- package/src/components/macro/dialog-preset.tsx +5 -3
- package/src/components/macro/input-preset.tsx +0 -1
- package/src/components/macro/select-preset.tsx +1 -1
- package/src/components/macro/switch-preset.test.tsx +1 -1
- package/src/components/micro/accordion.test.tsx +6 -12
- package/src/components/micro/alert-dialog.tsx +0 -2
- package/src/components/micro/alert.test.tsx +5 -8
- package/src/components/micro/alert.tsx +0 -2
- package/src/components/micro/badge.test.tsx +5 -7
- package/src/components/micro/badge.tsx +1 -3
- package/src/components/micro/button.test.tsx +19 -26
- package/src/components/micro/button.tsx +3 -11
- package/src/components/micro/calendar.tsx +12 -13
- package/src/components/micro/card.test.tsx +3 -5
- package/src/components/micro/carousel.tsx +0 -1
- package/src/components/micro/chart.tsx +3 -2
- package/src/components/micro/checkbox.test.tsx +9 -18
- package/src/components/micro/combobox.tsx +1 -3
- package/src/components/micro/command.tsx +23 -11
- package/src/components/micro/context-menu.tsx +0 -2
- package/src/components/micro/dialog.test.tsx +6 -14
- package/src/components/micro/dialog.tsx +0 -2
- package/src/components/micro/drawer.tsx +0 -3
- package/src/components/micro/dropdown-menu.test.tsx +8 -14
- package/src/components/micro/dropdown-menu.tsx +0 -2
- package/src/components/micro/field.tsx +3 -3
- package/src/components/micro/hover-card.tsx +0 -2
- package/src/components/micro/input-group.tsx +9 -42
- package/src/components/micro/input.test.tsx +15 -24
- package/src/components/micro/navigation-menu.tsx +0 -2
- package/src/components/micro/popover.test.tsx +5 -9
- package/src/components/micro/progress.tsx +5 -1
- package/src/components/micro/select.test.tsx +5 -18
- package/src/components/micro/select.tsx +3 -5
- package/src/components/micro/separator.tsx +1 -1
- package/src/components/micro/sheet.test.tsx +6 -14
- package/src/components/micro/sheet.tsx +0 -2
- package/src/components/micro/sidebar.tsx +5 -6
- package/src/components/micro/sonner.tsx +0 -1
- package/src/components/micro/switch.test.tsx +9 -18
- package/src/components/micro/switch.tsx +1 -1
- package/src/components/micro/tabs.test.tsx +5 -11
- package/src/components/micro/theme-provider.tsx +0 -12
- package/src/components/micro/toggle-group.tsx +1 -12
- package/src/components/micro/tooltip.test.tsx +7 -12
- package/src/dev/App.tsx +6 -6
- package/src/dev/components/BlockViewer.tsx +15 -4
- package/src/dev/components/Container.tsx +20 -0
- package/src/dev/components/GladvnLogo.tsx +3 -9
- package/src/dev/components/code-highlighter.tsx +5 -3
- package/src/dev/components/showcase.tsx +116 -168
- package/src/dev/sections/buttons.tsx +4 -9
- package/src/dev/sections/display.tsx +68 -72
- package/src/dev/sections/feedback.tsx +304 -314
- package/src/dev/sections/forms.tsx +10 -14
- package/src/dev/sections/interactive.tsx +32 -32
- package/src/dev/sections/overview.tsx +2 -10
- package/src/dev/showcase/accordion.tsx +512 -554
- package/src/dev/showcase/alert-dialog.tsx +525 -565
- package/src/dev/showcase/alert.tsx +352 -402
- package/src/dev/showcase/aspect-ratio.tsx +167 -193
- package/src/dev/showcase/avatar.tsx +231 -269
- package/src/dev/showcase/badge.tsx +92 -140
- package/src/dev/showcase/breadcrumb.tsx +113 -135
- package/src/dev/showcase/button.tsx +140 -173
- package/src/dev/showcase/calendar.tsx +187 -237
- package/src/dev/showcase/card.tsx +229 -261
- package/src/dev/showcase/carousel.tsx +288 -315
- package/src/dev/showcase/chart.tsx +44 -50
- package/src/dev/showcase/checkbox.tsx +286 -330
- package/src/dev/showcase/collapsible.tsx +143 -160
- package/src/dev/showcase/combobox.tsx +327 -369
- package/src/dev/showcase/command.tsx +106 -120
- package/src/dev/showcase/context-menu.tsx +93 -107
- package/src/dev/showcase/dialog.tsx +585 -630
- package/src/dev/showcase/drawer.tsx +176 -196
- package/src/dev/showcase/dropdown-menu.tsx +183 -201
- package/src/dev/showcase/empty.tsx +232 -274
- package/src/dev/showcase/hover-card.tsx +153 -180
- package/src/dev/showcase/input-group.tsx +221 -253
- package/src/dev/showcase/input-otp.tsx +204 -250
- package/src/dev/showcase/input.tsx +246 -325
- package/src/dev/showcase/item.tsx +134 -152
- package/src/dev/showcase/kbd.tsx +149 -172
- package/src/dev/showcase/label.tsx +50 -68
- package/src/dev/showcase/menubar.tsx +194 -213
- package/src/dev/showcase/navigation-menu.tsx +119 -133
- package/src/dev/showcase/overview-components/ArchitectureSection.tsx +126 -0
- package/src/dev/showcase/overview-components/CodeBlock.tsx +50 -0
- package/src/dev/showcase/overview-components/ColorPaletteSection.tsx +44 -0
- package/src/dev/showcase/overview-components/DashboardPreview.tsx +159 -0
- package/src/dev/showcase/overview-components/FeatureGridSection.tsx +535 -0
- package/src/dev/showcase/overview-components/FooterCTA.tsx +137 -0
- package/src/dev/showcase/overview-components/HeroSection.tsx +65 -0
- package/src/dev/showcase/overview-components/PrinciplesSection.tsx +128 -0
- package/src/dev/showcase/overview.tsx +21 -1163
- package/src/dev/showcase/pagination.tsx +144 -190
- package/src/dev/showcase/popover.tsx +181 -196
- package/src/dev/showcase/progress.tsx +141 -189
- package/src/dev/showcase/radio-group.tsx +272 -332
- package/src/dev/showcase/resizable.tsx +119 -141
- package/src/dev/showcase/scroll-area.tsx +21 -36
- package/src/dev/showcase/select.tsx +262 -322
- package/src/dev/showcase/separator.tsx +75 -73
- package/src/dev/showcase/sheet.tsx +333 -361
- package/src/dev/showcase/sidebar.tsx +53 -59
- package/src/dev/showcase/skeleton.tsx +93 -112
- package/src/dev/showcase/slider.tsx +244 -296
- package/src/dev/showcase/sonner.tsx +251 -258
- package/src/dev/showcase/spinner.tsx +46 -67
- package/src/dev/showcase/switch.tsx +298 -362
- package/src/dev/showcase/table.tsx +76 -80
- package/src/dev/showcase/tabs.tsx +302 -355
- package/src/dev/showcase/textarea.tsx +240 -293
- package/src/dev/showcase/toast.tsx +48 -54
- package/src/dev/showcase/toggle-group.tsx +104 -129
- package/src/dev/showcase/toggle.tsx +82 -102
- package/src/dev/showcase/tooltip.tsx +173 -192
- package/src/dev/showcase/why.tsx +6 -12
- package/src/hooks/use-mobile.test.ts +3 -2
- package/src/lib/utils.test.ts +5 -4
|
@@ -12,159 +12,146 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
DocsP,
|
|
14
14
|
ExampleGrid,
|
|
15
|
-
|
|
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: "
|
|
26
|
-
a: "
|
|
22
|
+
q: "Hỗ trợ Accessible (a11y) không?",
|
|
23
|
+
a: "Có chứ. Component tuân thủ chuẩn WAI-ARIA. Bàn phím hay screen reader cân hết." },
|
|
27
24
|
{
|
|
28
|
-
q: "
|
|
29
|
-
a: "
|
|
25
|
+
q: "Có CSS sẵn không?",
|
|
26
|
+
a: "Có nha. Style mặc định bao đẹp, match với các component khác. Override vô tư qua CSS variable." },
|
|
30
27
|
{
|
|
31
|
-
q: "
|
|
32
|
-
a: "
|
|
28
|
+
q: "Có 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: "
|
|
35
|
-
a: "
|
|
31
|
+
q: "Có 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: "
|
|
38
|
+
title: "Hỗ trợ Accessible (a11y) không?",
|
|
42
39
|
content:
|
|
43
|
-
"
|
|
40
|
+
"Có 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: "
|
|
43
|
+
title: "Có CSS sẵn không?",
|
|
47
44
|
content:
|
|
48
|
-
"
|
|
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: "
|
|
52
|
-
content: "
|
|
48
|
+
title: "Có 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
|
|
56
|
+
<div className="space-y-10">
|
|
63
57
|
<ExampleGrid>
|
|
64
|
-
<
|
|
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: "
|
|
64
|
+
title: "Hỗ trợ Accessible (a11y) không?",
|
|
74
65
|
content:
|
|
75
|
-
"
|
|
66
|
+
"Có 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: "
|
|
69
|
+
title: "Có CSS sẵn không?",
|
|
79
70
|
content:
|
|
80
|
-
"
|
|
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: "
|
|
74
|
+
title: "Có animation không?",
|
|
84
75
|
content:
|
|
85
|
-
"
|
|
76
|
+
"Đầy đủ. Mở ra đóng lại mượt mà." },
|
|
86
77
|
]}
|
|
87
|
-
/>`}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
"Có 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: "Có 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: "Có 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: "
|
|
111
|
+
title: "Hỗ trợ Accessible (a11y) không?",
|
|
123
112
|
content:
|
|
124
|
-
"
|
|
113
|
+
"Có 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: "
|
|
116
|
+
title: "Có CSS sẵn không?",
|
|
128
117
|
content:
|
|
129
|
-
"
|
|
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: "
|
|
121
|
+
title: "Có animation không?",
|
|
133
122
|
content:
|
|
134
|
-
"
|
|
123
|
+
"Đầy đủ. Mở ra đóng lại mượt mà." },
|
|
135
124
|
]}
|
|
136
|
-
/>`}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
+
"Có 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: "Có 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: "Có 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
|
-
<
|
|
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: "
|
|
178
|
-
content: "
|
|
164
|
+
title: "Hỗ trợ Accessible (a11y) không?",
|
|
165
|
+
content: "Có 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: "
|
|
182
|
-
content: "
|
|
168
|
+
title: "Có 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: "
|
|
186
|
-
content: "
|
|
172
|
+
title: "Có animation không?",
|
|
173
|
+
content: "Đầy đủ. Mở ra đóng lại mượt mà." },
|
|
187
174
|
]}
|
|
188
175
|
/>
|
|
189
|
-
);`}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
+
"Có 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: "Có 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: "Có 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: "
|
|
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
|
|
224
|
+
title: "Tính năng Premium (Đã khoá)",
|
|
240
225
|
content:
|
|
241
|
-
"
|
|
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: "
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
<
|
|
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: "
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
|
329
|
+
title: "Chế độ Controlled",
|
|
349
330
|
content:
|
|
350
|
-
"
|
|
331
|
+
"Sử dụng props value và onValueChange để kiểm soát các mục đang mở." },
|
|
351
332
|
]}
|
|
352
333
|
/>
|
|
353
334
|
) },
|
|
354
335
|
]}
|
|
355
|
-
/>`}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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 và 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
|
|
382
|
+
<div className="space-y-10">
|
|
404
383
|
<ExampleGrid>
|
|
405
|
-
<
|
|
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={["
|
|
386
|
+
defaultValue={["Hỗ trợ Accessible (a11y) không?"]}
|
|
411
387
|
>
|
|
412
|
-
<AccordionItem value="
|
|
388
|
+
<AccordionItem value="Hỗ trợ Accessible (a11y) không?">
|
|
413
389
|
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
414
390
|
<AccordionContent>
|
|
415
|
-
|
|
391
|
+
Có 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
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
+
Có 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={["
|
|
441
|
+
defaultValue={["Hỗ trợ Accessible (a11y) không?", "Is it styled?"]}
|
|
468
442
|
>
|
|
469
|
-
<AccordionItem value="
|
|
443
|
+
<AccordionItem value="Hỗ trợ Accessible (a11y) không?">
|
|
470
444
|
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
471
445
|
<AccordionContent>
|
|
472
|
-
|
|
446
|
+
Có 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
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
+
Có 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
|
-
<
|
|
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
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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>
|
|
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
|
|
580
|
+
Chế độ Controlled
|
|
611
581
|
</AccordionTrigger>
|
|
612
582
|
<AccordionContent>
|
|
613
583
|
Use the value and onValueChange props to
|
|
614
|
-
control which
|
|
584
|
+
control which các mục đang mở.
|
|
615
585
|
</AccordionContent>
|
|
616
586
|
</AccordionItem>
|
|
617
587
|
<AccordionItem value="animation">
|
|
618
588
|
<AccordionTrigger>
|
|
619
|
-
|
|
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
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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 và 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
|
-
<
|
|
676
|
-
|
|
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
|
-
|
|
650
|
+
Có 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
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
<
|
|
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
|
+
Có 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: "
|
|
781
|
-
title: "
|
|
744
|
+
value: "Hỗ trợ Accessible (a11y) không?",
|
|
745
|
+
title: "Hỗ trợ Accessible (a11y) không?",
|
|
782
746
|
content:
|
|
783
|
-
"
|
|
747
|
+
"Có chứ. Component tuân thủ chuẩn WAI-ARIA." },
|
|
784
748
|
{
|
|
785
749
|
value: "Is it styled?",
|
|
786
|
-
title: "
|
|
750
|
+
title: "Có CSS sẵn không?",
|
|
787
751
|
content:
|
|
788
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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ỉ là 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: "Có chứ. Component tuân thủ chuẩn WAI-ARIA." },
|
|
853
|
+
{
|
|
854
|
+
value: "Is it styled?",
|
|
855
|
+
title: "Có 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
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
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
|
-
</
|
|
946
|
-
|
|
947
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
982
|
-
|
|
983
|
-
{ label: "Macro (Preset)", content: <AccordionMacroShowcase /> },
|
|
984
|
-
]}
|
|
941
|
+
micro={{ content: <AccordionMicroShowcase /> }}
|
|
942
|
+
macro={{ content: <AccordionMacroShowcase /> }}
|
|
985
943
|
/>
|
|
986
944
|
);
|
|
987
945
|
}
|