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
@@ -14,15 +14,12 @@ import {
14
14
  DocsH3,
15
15
  DocsP,
16
16
  ExampleGrid,
17
- ExampleSection,
17
+ ShowcaseExample,
18
18
  Showcase,
19
19
  ShowcaseDocs
20
20
  } from "../../dev/components/showcase";
21
21
  import { type Size } from "../../lib/types";
22
22
 
23
- // ──────────────────────────────────────────────────────────
24
- // RHF Form Demo (Macro)
25
- // ──────────────────────────────────────────────────────────
26
23
  const formSchema = z.object({
27
24
  marketing: z.boolean().default(false).optional() });
28
25
  type FormValues = z.infer<typeof formSchema>;
@@ -85,57 +82,47 @@ function SwitchForm({ size }: { size: Size }) {
85
82
  );
86
83
  }`;
87
84
 
88
- // ──────────────────────────────────────────────────────────
89
- // SECTION 1: Macro Content
90
- // ──────────────────────────────────────────────────────────
91
85
  function SwitchMacroShowcase({ globalSize }: { globalSize: Size }) {
92
86
  const [checked, setChecked] = useState(false);
93
87
 
94
88
  return (
95
- <div className="space-y-10 mt-6">
89
+ <div className="space-y-10">
96
90
  <ExampleGrid>
97
- <ExampleSection
98
- label="Tiêu chuẩn"
99
- description="Công tắc cơ bản có nhãn và mô tả."
100
- codeString={`<SwitchPreset
91
+ <ShowcaseExample title="Tiêu chuẩn" description="Công tắc cơ bản có nhãn và mô tả." code={`<SwitchPreset
101
92
  className="w-full"
102
93
  label="Chế độ máy bay"
103
94
  description="Vô hiệu hóa tất cả các kết nối không dây."
104
- />`}
105
- >
106
- <SwitchPreset
107
- className="w-full"
108
- size={globalSize}
109
- label="Chế độ máy bay"
110
- description="Vô hiệu hóa tất cả các kết nối không dây."
111
- />
112
- </ExampleSection>
95
+ />`} preview={
96
+ <>
97
+ <SwitchPreset
98
+ className="w-full"
99
+ size={globalSize}
100
+ label="Chế độ máy bay"
101
+ description="Vô hiệu hóa tất cả các kết nối không dây."
102
+ />
103
+ </>
104
+ } />
113
105
 
114
- <ExampleSection
115
- label="Trạng thái Lỗi (Error)"
116
- description="Báo lỗi khi bật/tắt thất bại."
117
- codeString={`<div className="w-full flex flex-col gap-6">
106
+ <ShowcaseExample title="Trạng thái Lỗi (Error)" description="Báo lỗi khi bật/tắt thất bại." code={`<div className="w-full flex flex-col gap-6">
118
107
  <SwitchPreset
119
108
  label="Kết nối mạng (Lỗi)"
120
109
  errorMessage="Mất kết nối mạng. Không thể lưu cài đặt."
121
110
  />
122
- </div>`}
123
- >
124
- <div className="w-full flex flex-col gap-6">
125
- <SwitchPreset
126
- size={globalSize}
127
- label="Kết nối mạng (Lỗi)"
128
- errorMessage="Mất kết nối mạng. Không thể lưu cài đặt."
129
- />
130
- </div>
131
- </ExampleSection>
111
+ </div>`} preview={
112
+ <>
113
+ <div className="w-full flex flex-col gap-6">
114
+ <SwitchPreset
115
+ size={globalSize}
116
+ label="Kết nối mạng (Lỗi)"
117
+ errorMessage="Mất kết nối mạng. Không thể lưu cài đặt."
118
+ />
119
+ </div>
120
+ </>
121
+ } />
132
122
  </ExampleGrid>
133
123
 
134
124
  <ExampleGrid>
135
- <ExampleSection
136
- label="Khóa / Bất hoạt (Disabled)"
137
- description="Người dùng không thể tương tác với công tắc."
138
- codeString={`<div className="w-full flex flex-col gap-6">
125
+ <ShowcaseExample title="Khóa / Bất hoạt (Disabled)" description="Người dùng không thể tương tác với công tắc." code={`<div className="w-full flex flex-col gap-6">
139
126
  <SwitchPreset
140
127
  label="Đồng bộ danh bạ"
141
128
  description="Yêu cầu cấp quyền truy cập vào danh bạ."
@@ -147,29 +134,27 @@ function SwitchMacroShowcase({ globalSize }: { globalSize: Size }) {
147
134
  defaultChecked
148
135
  disabled
149
136
  />
150
- </div>`}
151
- >
152
- <div className="w-full flex flex-col gap-6">
153
- <SwitchPreset
154
- size={globalSize}
155
- label="Đồng bộ danh bạ"
156
- description="Yêu cầu cấp quyền truy cập vào danh bạ."
157
- disabled
158
- />
159
- <SwitchPreset
160
- size={globalSize}
161
- label="Dữ liệu di động"
162
- description="Dữ liệu di động đang bị tắt trên toàn cầu."
163
- defaultChecked
164
- disabled
165
- />
166
- </div>
167
- </ExampleSection>
137
+ </div>`} preview={
138
+ <>
139
+ <div className="w-full flex flex-col gap-6">
140
+ <SwitchPreset
141
+ size={globalSize}
142
+ label="Đồng bộ danh bạ"
143
+ description="Yêu cầu cấp quyền truy cập vào danh bạ."
144
+ disabled
145
+ />
146
+ <SwitchPreset
147
+ size={globalSize}
148
+ label="Dữ liệu di động"
149
+ description="Dữ liệu di động đang bị tắt trên toàn cầu."
150
+ defaultChecked
151
+ disabled
152
+ />
153
+ </div>
154
+ </>
155
+ } />
168
156
 
169
- <ExampleSection
170
- label="Nhãn phức tạp (Custom Content)"
171
- description="Truyền React Node vào Label để tạo giao diện phong phú."
172
- codeString={`<SwitchPreset
157
+ <ShowcaseExample title="Nhãn phức tạp (Custom Content)" description="Truyền React Node vào Label để tạo giao diện phong phú." code={`<SwitchPreset
173
158
  label={
174
159
  <span className="flex items-center gap-2">
175
160
  Xác thực 2 bước (2FA)
@@ -179,75 +164,66 @@ function SwitchMacroShowcase({ globalSize }: { globalSize: Size }) {
179
164
  </span>
180
165
  }
181
166
  description="Thêm một lớp bảo mật bổ sung cho tài khoản của bạn. Chúng tôi sẽ yêu cầu mã xác nhận mỗi khi bạn đăng nhập từ thiết bị mới."
182
- />`}
183
- >
184
- <SwitchPreset
185
- size={globalSize}
186
- label={
187
- <span className="flex items-center gap-2">
188
- Xác thực 2 bước (2FA)
189
- <span className="rounded bg-success/20 px-1.5 py-0.5 text-[10px] font-semibold text-success">
190
- KHUYÊN DÙNG
191
- </span>
192
- </span>
193
- }
194
- description="Thêm một lớp bảo mật bổ sung cho tài khoản của bạn. Chúng tôi sẽ yêu cầu mã xác nhận mỗi khi bạn đăng nhập từ thiết bị mới."
195
- />
196
- </ExampleSection>
167
+ />`} preview={
168
+ <>
169
+ <SwitchPreset
170
+ size={globalSize}
171
+ label={
172
+ <span className="flex items-center gap-2">
173
+ Xác thực 2 bước (2FA)
174
+ <span className="rounded bg-success/20 px-1.5 py-0.5 text-[10px] font-semibold text-success">
175
+ KHUYÊN DÙNG
176
+ </span>
177
+ </span>
178
+ }
179
+ description="Thêm một lớp bảo mật bổ sung cho tài khoản của bạn. Chúng tôi sẽ yêu cầu mã xác nhận mỗi khi bạn đăng nhập từ thiết bị mới."
180
+ />
181
+ </>
182
+ } />
197
183
  </ExampleGrid>
198
184
 
199
185
  <ExampleGrid>
200
- <ExampleSection
201
- label="React State (Controlled Mode)"
202
- description="Sử dụng biến state của React để điều khiển."
203
- codeString={`const [checked, setChecked] = useState(false); return (
186
+ <ShowcaseExample title="React State (Controlled Mode)" description="Sử dụng biến state của React để điều khiển." code={`const [checked, setChecked] = useState(false); return (
204
187
  <SwitchPreset
205
188
  checked={checked}
206
189
  onCheckedChange={(c) => setChecked(!!c)}
207
190
  label="Chế độ nhà phát triển"
208
191
  />
209
- );`}
210
- >
211
- <div className="w-full flex flex-col gap-4">
212
- <SwitchPreset
213
- size={globalSize}
214
- checked={checked}
215
- onCheckedChange={(c) => setChecked(!!c)}
216
- label="Chế độ nhà phát triển"
217
- description="Bật các tính năng thử nghiệm nội bộ."
218
- />
219
- <p className="text-sm text-muted-foreground">
220
- Trạng thái:{" "}
221
- <span className="font-mono font-bold text-foreground">
222
- {checked ? "BẬT" : "TẮT"}
223
- </span>
224
- </p>
225
- </div>
226
- </ExampleSection>
192
+ );`} preview={
193
+ <>
194
+ <div className="w-full flex flex-col gap-4">
195
+ <SwitchPreset
196
+ size={globalSize}
197
+ checked={checked}
198
+ onCheckedChange={(c) => setChecked(!!c)}
199
+ label="Chế độ nhà phát triển"
200
+ description="Bật các tính năng thử nghiệm nội bộ."
201
+ />
202
+ <p className="text-sm text-muted-foreground">
203
+ Trạng thái:{" "}
204
+ <span className="font-mono font-bold text-foreground">
205
+ {checked ? "BẬT" : "TẮT"}
206
+ </span>
207
+ </p>
208
+ </div>
209
+ </>
210
+ } />
227
211
 
228
- <ExampleSection
229
- label="Tích hợp React Hook Form"
230
- description="Dùng Controller của RHF để bọc SwitchPreset."
231
- codeString={rhfCode}
232
- >
233
- <SwitchForm size={globalSize} />
234
- </ExampleSection>
212
+ <ShowcaseExample title="Tích hợp React Hook Form" description="Dùng Controller của RHF để bọc SwitchPreset." code={rhfCode} preview={
213
+ <>
214
+ <SwitchForm size={globalSize} />
215
+ </>
216
+ } />
235
217
  </ExampleGrid>
236
218
  </div>
237
219
  );
238
220
  }
239
221
 
240
- // ──────────────────────────────────────────────────────────
241
- // SECTION 2: Micro Content
242
- // ──────────────────────────────────────────────────────────
243
222
  function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
244
223
  return (
245
- <div className="space-y-10 mt-6">
224
+ <div className="space-y-10">
246
225
  <ExampleGrid>
247
- <ExampleSection
248
- label="Cơ bản (Primitive)"
249
- description="Kết nối thủ công Switch và SwitchThumb."
250
- codeString={`<div className="flex items-center gap-4">
226
+ <ShowcaseExample title="Cơ bản (Primitive)" description="Kết nối thủ công Switch và SwitchThumb." code={`<div className="flex items-center gap-4">
251
227
  <Switch id="sw-micro">
252
228
  <SwitchThumb />
253
229
  </Switch>
@@ -257,22 +233,20 @@ function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
257
233
  >
258
234
  Công tắc đơn trần
259
235
  </label>
260
- </div>`}
261
- >
262
- <div className="flex items-center gap-4">
263
- <Switch size={globalSize} id="sw-micro">
264
- <SwitchThumb />
265
- </Switch>
266
- <label htmlFor="sw-micro" className="text-sm cursor-pointer">
267
- Công tắc đơn trần
268
- </label>
269
- </div>
270
- </ExampleSection>
236
+ </div>`} preview={
237
+ <>
238
+ <div className="flex items-center gap-4">
239
+ <Switch size={globalSize} id="sw-micro">
240
+ <SwitchThumb />
241
+ </Switch>
242
+ <label htmlFor="sw-micro" className="text-sm cursor-pointer">
243
+ Công tắc đơn trần
244
+ </label>
245
+ </div>
246
+ </>
247
+ } />
271
248
 
272
- <ExampleSection
273
- label="Layout Đảo ngược (Reverse)"
274
- description="Dùng Field với orientation='horizontal' để đẩy Switch sang bên phải."
275
- codeString={`<div className="w-full space-y-4">
249
+ <ShowcaseExample title="Layout Đảo ngược (Reverse)" description="Dùng Field với orientation='horizontal' để đẩy Switch sang bên phải." code={`<div className="w-full space-y-4">
276
250
  <Field
277
251
  orientation="horizontal"
278
252
  className="justify-between"
@@ -301,48 +275,46 @@ function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
301
275
  <SwitchThumb />
302
276
  </Switch>
303
277
  </Field>
304
- </div>`}
305
- >
306
- <div className="w-full space-y-4">
307
- <Field
308
- orientation="horizontal"
309
- size={globalSize}
310
- className="justify-between"
311
- >
312
- <FieldLabel
313
- htmlFor="switch-notif"
314
- className="font-normal cursor-pointer"
315
- >
316
- Thông báo đẩy
317
- </FieldLabel>
318
- <Switch id="switch-notif" size={globalSize} defaultChecked>
319
- <SwitchThumb />
320
- </Switch>
321
- </Field>
322
- <Field
323
- orientation="horizontal"
324
- size={globalSize}
325
- className="justify-between"
326
- >
327
- <FieldLabel
328
- htmlFor="switch-dark"
329
- className="font-normal cursor-pointer"
330
- >
331
- Chế độ tối (Dark Mode)
332
- </FieldLabel>
333
- <Switch id="switch-dark" size={globalSize}>
334
- <SwitchThumb />
335
- </Switch>
336
- </Field>
337
- </div>
338
- </ExampleSection>
278
+ </div>`} preview={
279
+ <>
280
+ <div className="w-full space-y-4">
281
+ <Field
282
+ orientation="horizontal"
283
+ size={globalSize}
284
+ className="justify-between"
285
+ >
286
+ <FieldLabel
287
+ htmlFor="switch-notif"
288
+ className="font-normal cursor-pointer"
289
+ >
290
+ Thông báo đẩy
291
+ </FieldLabel>
292
+ <Switch id="switch-notif" size={globalSize} defaultChecked>
293
+ <SwitchThumb />
294
+ </Switch>
295
+ </Field>
296
+ <Field
297
+ orientation="horizontal"
298
+ size={globalSize}
299
+ className="justify-between"
300
+ >
301
+ <FieldLabel
302
+ htmlFor="switch-dark"
303
+ className="font-normal cursor-pointer"
304
+ >
305
+ Chế độ tối (Dark Mode)
306
+ </FieldLabel>
307
+ <Switch id="switch-dark" size={globalSize}>
308
+ <SwitchThumb />
309
+ </Switch>
310
+ </Field>
311
+ </div>
312
+ </>
313
+ } />
339
314
  </ExampleGrid>
340
315
 
341
316
  <ExampleGrid>
342
- <ExampleSection
343
- label="Khóa (Disabled)"
344
- description="Các công tắc đảo ngược nhưng bị vô hiệu hoá."
345
- codeString={`<div className="w-full space-y-4">
317
+ <ShowcaseExample title="Khóa (Disabled)" description="Các công tắc đảo ngược nhưng bị vô hiệu hoá." code={`<div className="w-full space-y-4">
346
318
  <Field
347
319
  orientation="horizontal"
348
320
  className="justify-between"
@@ -371,46 +343,44 @@ function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
371
343
  <SwitchThumb />
372
344
  </Switch>
373
345
  </Field>
374
- </div>`}
375
- >
376
- <div className="w-full space-y-4">
377
- <Field
378
- orientation="horizontal"
379
- size={globalSize}
380
- className="justify-between"
381
- >
382
- <FieldLabel
383
- htmlFor="switch-d1"
384
- className="font-normal text-muted-foreground"
385
- >
386
- Bluetooth
387
- </FieldLabel>
388
- <Switch id="switch-d1" disabled size={globalSize} defaultChecked>
389
- <SwitchThumb />
390
- </Switch>
391
- </Field>
392
- <Field
393
- orientation="horizontal"
394
- size={globalSize}
395
- className="justify-between"
396
- >
397
- <FieldLabel
398
- htmlFor="switch-d2"
399
- className="font-normal text-muted-foreground"
400
- >
401
- Vị trí (GPS)
402
- </FieldLabel>
403
- <Switch id="switch-d2" disabled size={globalSize}>
404
- <SwitchThumb />
405
- </Switch>
406
- </Field>
407
- </div>
408
- </ExampleSection>
346
+ </div>`} preview={
347
+ <>
348
+ <div className="w-full space-y-4">
349
+ <Field
350
+ orientation="horizontal"
351
+ size={globalSize}
352
+ className="justify-between"
353
+ >
354
+ <FieldLabel
355
+ htmlFor="switch-d1"
356
+ className="font-normal text-muted-foreground"
357
+ >
358
+ Bluetooth
359
+ </FieldLabel>
360
+ <Switch id="switch-d1" disabled size={globalSize} defaultChecked>
361
+ <SwitchThumb />
362
+ </Switch>
363
+ </Field>
364
+ <Field
365
+ orientation="horizontal"
366
+ size={globalSize}
367
+ className="justify-between"
368
+ >
369
+ <FieldLabel
370
+ htmlFor="switch-d2"
371
+ className="font-normal text-muted-foreground"
372
+ >
373
+ Vị trí (GPS)
374
+ </FieldLabel>
375
+ <Switch id="switch-d2" disabled size={globalSize}>
376
+ <SwitchThumb />
377
+ </Switch>
378
+ </Field>
379
+ </div>
380
+ </>
381
+ } />
409
382
 
410
- <ExampleSection
411
- label="Trạng thái Lỗi thủ công"
412
- description="Tự gắn aria-invalid vào Switch."
413
- codeString={`<Field
383
+ <ShowcaseExample title="Trạng thái Lỗi thủ công" description="Tự gắn aria-invalid vào Switch." code={`<Field
414
384
  orientation="horizontal"
415
385
  data-invalid={true}
416
386
  className="justify-between items-start"
@@ -431,40 +401,37 @@ function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
431
401
  >
432
402
  <SwitchThumb />
433
403
  </Switch>
434
- </Field>`}
435
- >
436
- <Field
437
- orientation="horizontal"
438
- data-invalid={true}
439
- size={globalSize}
440
- className="justify-between items-start"
441
- >
442
- <div className="grid gap-1.5">
443
- <FieldLabel
444
- htmlFor="switch-err"
445
- className="font-normal cursor-pointer"
446
- >
447
- Tự động sao lưu
448
- </FieldLabel>
449
- <FieldError>Máy chủ sao lưu đang offline.</FieldError>
450
- </div>
451
- <Switch
452
- id="switch-err"
453
- size={globalSize}
454
- aria-invalid={true}
455
- defaultChecked
456
- >
457
- <SwitchThumb />
458
- </Switch>
459
- </Field>
460
- </ExampleSection>
404
+ </Field>`} preview={
405
+ <>
406
+ <Field
407
+ orientation="horizontal"
408
+ data-invalid={true}
409
+ size={globalSize}
410
+ className="justify-between items-start"
411
+ >
412
+ <div className="grid gap-1.5">
413
+ <FieldLabel
414
+ htmlFor="switch-err"
415
+ className="font-normal cursor-pointer"
416
+ >
417
+ Tự động sao lưu
418
+ </FieldLabel>
419
+ <FieldError>Máy chủ sao lưu đang offline.</FieldError>
420
+ </div>
421
+ <Switch
422
+ id="switch-err"
423
+ size={globalSize}
424
+ aria-invalid={true}
425
+ defaultChecked
426
+ >
427
+ <SwitchThumb />
428
+ </Switch>
429
+ </Field>
430
+ </>
431
+ } />
461
432
  </ExampleGrid>
462
433
 
463
- <ExampleSection
464
- label="🧭 Use Case Comparison"
465
- description="So sánh nhanh khi nào dùng Micro và Macro."
466
- fullWidth
467
- codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
434
+ <ShowcaseExample title="🧭 So sánh Use Case" description="So sánh nhanh khi nào dùng Micro và Macro." code={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
468
435
  {/* Story 1: Macro wins */}
469
436
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
470
437
  <div className="flex items-start gap-3">
@@ -554,141 +521,110 @@ function SwitchMicroShowcase({ globalSize }: { globalSize: Size }) {
554
521
  </div>
555
522
  </div>
556
523
  </div>
557
- </div>`}
558
- >
559
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
560
- {/* Story 1: Macro wins */}
561
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
562
- <div className="flex items-start gap-3">
563
- <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
564
- <svg
565
- xmlns="http://www.w3.org/2000/svg"
566
- className="size-4"
567
- viewBox="0 0 24 24"
568
- fill="none"
569
- stroke="currentColor"
570
- strokeWidth="2"
571
- strokeLinecap="round"
572
- strokeLinejoin="round"
573
- aria-hidden="true"
574
- >
575
- <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
576
- </svg>
577
- </span>
578
- <div>
579
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
580
- Story 1 · Dùng Macro
581
- </p>
582
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
583
- Form thông thường
584
- </h3>
585
- </div>
586
- </div>
587
- <p className="text-xs text-muted-foreground leading-relaxed">
588
- Bạn cần một Switch giống như Checkbox (công tắc ở bên trái, chữ
589
- bên phải). Dùng Preset cho nhanh gọn.
590
- </p>
591
- <div className="rounded-lg bg-muted/50 p-3">
592
- <SwitchPreset
593
- size="sm"
594
- label="Đồng ý điều khoản"
595
- description="Bật để tiếp tục."
596
- />
597
- </div>
598
- </div>
524
+ </div>`} preview={
525
+ <>
526
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
527
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
528
+ <div className="flex items-start gap-3">
529
+ <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
530
+ <svg
531
+ xmlns="http://www.w3.org/2000/svg"
532
+ className="size-4"
533
+ viewBox="0 0 24 24"
534
+ fill="none"
535
+ stroke="currentColor"
536
+ strokeWidth="2"
537
+ strokeLinecap="round"
538
+ strokeLinejoin="round"
539
+ aria-hidden="true"
540
+ >
541
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
542
+ </svg>
543
+ </span>
544
+ <div>
545
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
546
+ Story 1 · Dùng Macro
547
+ </p>
548
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
549
+ Form thông thường
550
+ </h3>
551
+ </div>
552
+ </div>
553
+ <p className="text-xs text-muted-foreground leading-relaxed">
554
+ Bạn cần một Switch giống như Checkbox (công tắc ở bên trái, chữ
555
+ bên phải). Dùng Preset cho nhanh gọn.
556
+ </p>
557
+ <div className="rounded-lg bg-muted/50 p-3">
558
+ <SwitchPreset
559
+ size="sm"
560
+ label="Đồng ý điều khoản"
561
+ description="Bật để tiếp tục."
562
+ />
563
+ </div>
564
+ </div>
599
565
 
600
- {/* Story 2: Micro wins */}
601
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
602
- <div className="flex items-start gap-3">
603
- <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
604
- <svg
605
- xmlns="http://www.w3.org/2000/svg"
606
- className="size-4"
607
- viewBox="0 0 24 24"
608
- fill="none"
609
- stroke="currentColor"
610
- strokeWidth="2"
611
- strokeLinecap="round"
612
- strokeLinejoin="round"
613
- aria-hidden="true"
614
- >
615
- <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
616
- </svg>
617
- </span>
618
- <div>
619
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
620
- Story 2 · Dùng Micro
621
- </p>
622
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
623
- Menu Cài đặt (iOS Style)
624
- </h3>
625
- </div>
626
- </div>
627
- <p className="text-xs text-muted-foreground leading-relaxed">
628
- Giống như iPhone, chữ nằm bên trái Công tắc nằm tít bên phải
629
- của dòng. Macro không hỗ trợ layout này nên bạn dùng cấu trúc
630
- Field + Micro.
631
- </p>
632
- <div className="rounded-lg bg-muted/50 p-3 border border-border divide-y">
633
- <div className="p-2 flex justify-between items-center">
634
- <span className="text-sm font-medium">Wi-Fi</span>
635
- <Switch size="sm" defaultChecked>
636
- <SwitchThumb />
637
- </Switch>
638
- </div>
639
- <div className="p-2 flex justify-between items-center">
640
- <span className="text-sm font-medium">Bluetooth</span>
641
- <Switch size="sm">
642
- <SwitchThumb />
643
- </Switch>
644
- </div>
645
- </div>
646
- </div>
647
- </div>
648
- </ExampleSection>
566
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
567
+ <div className="flex items-start gap-3">
568
+ <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
569
+ <svg
570
+ xmlns="http://www.w3.org/2000/svg"
571
+ className="size-4"
572
+ viewBox="0 0 24 24"
573
+ fill="none"
574
+ stroke="currentColor"
575
+ strokeWidth="2"
576
+ strokeLinecap="round"
577
+ strokeLinejoin="round"
578
+ aria-hidden="true"
579
+ >
580
+ <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
581
+ </svg>
582
+ </span>
583
+ <div>
584
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
585
+ Story 2 · Dùng Micro
586
+ </p>
587
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
588
+ Menu Cài đặt (iOS Style)
589
+ </h3>
590
+ </div>
591
+ </div>
592
+ <p className="text-xs text-muted-foreground leading-relaxed">
593
+ Giống như iPhone, chữ nằm bên trái và Công tắc nằm tít bên phải
594
+ của dòng. Macro không hỗ trợ layout này nên bạn dùng cấu trúc
595
+ Field + Micro.
596
+ </p>
597
+ <div className="rounded-lg bg-muted/50 p-3 border border-border divide-y">
598
+ <div className="p-2 flex justify-between items-center">
599
+ <span className="text-sm font-medium">Wi-Fi</span>
600
+ <Switch size="sm" defaultChecked>
601
+ <SwitchThumb />
602
+ </Switch>
603
+ </div>
604
+ <div className="p-2 flex justify-between items-center">
605
+ <span className="text-sm font-medium">Bluetooth</span>
606
+ <Switch size="sm">
607
+ <SwitchThumb />
608
+ </Switch>
609
+ </div>
610
+ </div>
611
+ </div>
612
+ </div>
613
+ </>
614
+ } />
649
615
  </div>
650
616
  );
651
617
  }
652
618
 
653
- // ──────────────────────────────────────────────────────────
654
- // SECTION 3: Entry point
655
- // ──────────────────────────────────────────────────────────
656
619
  export default function SwitchShowcase() {
657
620
  const { size: globalSize } = useDevContext();
658
621
  return (
659
622
  <Showcase
660
623
  title="Switch"
661
624
  description="Thành phần điều khiển cho phép người dùng chuyển đổi qua lại giữa 2 trạng thái Bật / Tắt."
662
- generalConcept={
663
- <div className="space-y-4">
664
- <ShowcaseDocs>
665
- <DocsH3>Khi nào nên dùng Macro</DocsH3>
666
- <DocsP>
667
- <DocsCode>SwitchPreset</DocsCode> đóng gói Switch + Label +
668
- Description + Error Message. Nó tự động căn chỉnh khoảng cách và
669
- liên kết ID. Dùng trong 95% trường hợp làm màn hình cài đặt
670
- (Settings) hoặc form yêu cầu bật/tắt tính năng.
671
- </DocsP>
672
- </ShowcaseDocs>
673
- <ShowcaseDocs>
674
- <DocsH3>Khi nào nên dùng Micro</DocsH3>
675
- <DocsP>
676
- Dùng <DocsCode>Switch</DocsCode> và{" "}
677
- <DocsCode>SwitchThumb</DocsCode> nguyên thuỷ khi bạn cần một
678
- layout không theo chuẩn <DocsCode>SwitchPreset</DocsCode> (ví dụ:
679
- Switch nằm bên phải Label thay vì nằm bên trái).
680
- </DocsP>
681
- </ShowcaseDocs>
682
- </div>
683
- }
684
- tabs={[
685
- {
686
- label: "Micro (Primitive)",
687
- content: <SwitchMicroShowcase globalSize={globalSize} /> },
688
- {
689
- label: "Macro (Preset)",
690
- content: <SwitchMacroShowcase globalSize={globalSize} /> },
691
- ]}
625
+
626
+ micro={{ content: <SwitchMicroShowcase globalSize={globalSize} /> }}
627
+ macro={{ content: <SwitchMacroShowcase globalSize={globalSize} /> }}
692
628
  />
693
629
  );
694
630
  }