@suphark/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +21 -0
  3. package/README.md +120 -0
  4. package/components.json +21 -0
  5. package/package.json +108 -0
  6. package/scripts/audit-base-ui-props.mjs +179 -0
  7. package/scripts/audit-tailwind-typography.mjs +100 -0
  8. package/src/components/design-system/design-system-showcase.tsx +138 -0
  9. package/src/components/design-system/sections/showcase-data-display.tsx +454 -0
  10. package/src/components/design-system/sections/showcase-feedback.tsx +273 -0
  11. package/src/components/design-system/sections/showcase-forms.tsx +373 -0
  12. package/src/components/design-system/sections/showcase-foundations.tsx +384 -0
  13. package/src/components/design-system/sections/showcase-guidelines-recipes.tsx +397 -0
  14. package/src/components/design-system/sections/showcase-overlays-navigation.tsx +479 -0
  15. package/src/components/design-system/sections/showcase-overview.tsx +368 -0
  16. package/src/components/design-system/sections/showcase-primitives.tsx +463 -0
  17. package/src/components/shared/__tests__/multi-select-combobox.test.tsx +180 -0
  18. package/src/components/shared/__tests__/name-id-fields.test.ts +24 -0
  19. package/src/components/shared/button/add-new-button.tsx +19 -0
  20. package/src/components/shared/button/base/action-button.tsx +134 -0
  21. package/src/components/shared/button/base/link-button.tsx +130 -0
  22. package/src/components/shared/button/cancel-button.tsx +27 -0
  23. package/src/components/shared/button/confirm-button.tsx +26 -0
  24. package/src/components/shared/button/delete-button.tsx +36 -0
  25. package/src/components/shared/button/floating-save-button.tsx +89 -0
  26. package/src/components/shared/button/index.ts +13 -0
  27. package/src/components/shared/button/print-button.tsx +67 -0
  28. package/src/components/shared/button/refresh-button.tsx +63 -0
  29. package/src/components/shared/button/save-button.tsx +29 -0
  30. package/src/components/shared/button/submit-button.tsx +58 -0
  31. package/src/components/shared/client-redirect.tsx +11 -0
  32. package/src/components/shared/combobox.tsx +116 -0
  33. package/src/components/shared/data-list.tsx +65 -0
  34. package/src/components/shared/date/date-range-picker.tsx +106 -0
  35. package/src/components/shared/description-list.tsx +27 -0
  36. package/src/components/shared/empty-row.tsx +13 -0
  37. package/src/components/shared/empty-state.tsx +31 -0
  38. package/src/components/shared/env-snippet.tsx +62 -0
  39. package/src/components/shared/form/__tests__/simple-select.test.tsx +72 -0
  40. package/src/components/shared/form/form-field-boolean.tsx +93 -0
  41. package/src/components/shared/form/form-field-color-select.tsx +86 -0
  42. package/src/components/shared/form/form-field-combobox.tsx +167 -0
  43. package/src/components/shared/form/form-field-date.tsx +55 -0
  44. package/src/components/shared/form/form-field-formatted-number.tsx +103 -0
  45. package/src/components/shared/form/form-field-input.tsx +372 -0
  46. package/src/components/shared/form/form-field-radio-cards.tsx +127 -0
  47. package/src/components/shared/form/form-field-radio-group.tsx +56 -0
  48. package/src/components/shared/form/form-field-select.tsx +312 -0
  49. package/src/components/shared/form/simple-select.tsx +152 -0
  50. package/src/components/shared/form-dialog.tsx +109 -0
  51. package/src/components/shared/form-message.tsx +30 -0
  52. package/src/components/shared/initials.tsx +33 -0
  53. package/src/components/shared/layout/error-state.tsx +160 -0
  54. package/src/components/shared/layout/page-shell.tsx +57 -0
  55. package/src/components/shared/link/transition-link.tsx +72 -0
  56. package/src/components/shared/multi-select-combobox.tsx +392 -0
  57. package/src/components/shared/name-id-fields.tsx +133 -0
  58. package/src/components/shared/navigation/page-breadcrumb.tsx +100 -0
  59. package/src/components/shared/notice.tsx +35 -0
  60. package/src/components/shared/number/formatted-number.tsx +133 -0
  61. package/src/components/shared/page-header.tsx +25 -0
  62. package/src/components/shared/page-skeleton.tsx +18 -0
  63. package/src/components/shared/row-actions.tsx +93 -0
  64. package/src/components/shared/row-menu.tsx +55 -0
  65. package/src/components/shared/secret-reveal.tsx +53 -0
  66. package/src/components/shared/section-card.tsx +44 -0
  67. package/src/components/shared/stat.tsx +26 -0
  68. package/src/components/shared/status-badge.tsx +47 -0
  69. package/src/components/shared/text/primary-secondary-text.tsx +186 -0
  70. package/src/components/shared/theme/index.ts +4 -0
  71. package/src/components/shared/theme/theme-menu-items.tsx +43 -0
  72. package/src/components/shared/theme/theme-provider.tsx +39 -0
  73. package/src/components/shared/theme/theme-switch.tsx +36 -0
  74. package/src/components/shared/theme/theme-toggle.tsx +76 -0
  75. package/src/components/shared/time/client-date-formatter.tsx +188 -0
  76. package/src/components/shared/ui-text.tsx +47 -0
  77. package/src/components/ui/__tests__/combobox.test.tsx +40 -0
  78. package/src/components/ui/__tests__/date-picker.test.tsx +53 -0
  79. package/src/components/ui/__tests__/slider.test.tsx +18 -0
  80. package/src/components/ui/__tests__/tabs.test.tsx +33 -0
  81. package/src/components/ui/accordion.tsx +69 -0
  82. package/src/components/ui/alert-dialog.tsx +161 -0
  83. package/src/components/ui/alert.tsx +68 -0
  84. package/src/components/ui/aspect-ratio.tsx +22 -0
  85. package/src/components/ui/attachment.tsx +194 -0
  86. package/src/components/ui/avatar.tsx +92 -0
  87. package/src/components/ui/badge.tsx +48 -0
  88. package/src/components/ui/breadcrumb.tsx +102 -0
  89. package/src/components/ui/button-group.tsx +77 -0
  90. package/src/components/ui/button.tsx +57 -0
  91. package/src/components/ui/calendar.tsx +184 -0
  92. package/src/components/ui/card.tsx +87 -0
  93. package/src/components/ui/carousel.tsx +230 -0
  94. package/src/components/ui/chart.tsx +338 -0
  95. package/src/components/ui/checkbox.tsx +27 -0
  96. package/src/components/ui/collapsible.tsx +17 -0
  97. package/src/components/ui/combobox.tsx +272 -0
  98. package/src/components/ui/command.tsx +180 -0
  99. package/src/components/ui/context-menu.tsx +244 -0
  100. package/src/components/ui/date-picker.tsx +308 -0
  101. package/src/components/ui/dialog.tsx +137 -0
  102. package/src/components/ui/drawer.tsx +208 -0
  103. package/src/components/ui/dropdown-menu.tsx +257 -0
  104. package/src/components/ui/empty.tsx +93 -0
  105. package/src/components/ui/field.tsx +223 -0
  106. package/src/components/ui/form.tsx +161 -0
  107. package/src/components/ui/hover-card.tsx +46 -0
  108. package/src/components/ui/input-group.tsx +145 -0
  109. package/src/components/ui/input-otp.tsx +85 -0
  110. package/src/components/ui/input.tsx +19 -0
  111. package/src/components/ui/item.tsx +187 -0
  112. package/src/components/ui/kbd.tsx +26 -0
  113. package/src/components/ui/label.tsx +19 -0
  114. package/src/components/ui/menubar.tsx +266 -0
  115. package/src/components/ui/navigation-menu.tsx +160 -0
  116. package/src/components/ui/pagination.tsx +117 -0
  117. package/src/components/ui/popover.tsx +76 -0
  118. package/src/components/ui/progress.tsx +66 -0
  119. package/src/components/ui/radio-group.tsx +38 -0
  120. package/src/components/ui/relative-date.tsx +40 -0
  121. package/src/components/ui/resizable.tsx +41 -0
  122. package/src/components/ui/scroll-area.tsx +67 -0
  123. package/src/components/ui/searchable-select.tsx +124 -0
  124. package/src/components/ui/select.tsx +189 -0
  125. package/src/components/ui/separator.tsx +21 -0
  126. package/src/components/ui/sheet.tsx +124 -0
  127. package/src/components/ui/sidebar.tsx +691 -0
  128. package/src/components/ui/skeleton.tsx +13 -0
  129. package/src/components/ui/slider.tsx +55 -0
  130. package/src/components/ui/sonner.tsx +45 -0
  131. package/src/components/ui/spinner.tsx +16 -0
  132. package/src/components/ui/switch.tsx +32 -0
  133. package/src/components/ui/table.tsx +95 -0
  134. package/src/components/ui/tabs.tsx +79 -0
  135. package/src/components/ui/textarea.tsx +17 -0
  136. package/src/components/ui/toggle-group.tsx +86 -0
  137. package/src/components/ui/toggle.tsx +44 -0
  138. package/src/components/ui/tooltip.tsx +54 -0
  139. package/src/hooks/use-copy-to-clipboard.ts +27 -0
  140. package/src/hooks/use-mobile.ts +21 -0
  141. package/src/index.ts +156 -0
  142. package/src/lib/formatters.ts +44 -0
  143. package/src/lib/permission.ts +75 -0
  144. package/src/lib/status-colors.ts +52 -0
  145. package/src/lib/utils.ts +6 -0
  146. package/src/next.ts +15 -0
  147. package/src/styles.css +214 -0
@@ -0,0 +1,368 @@
1
+ "use client";
2
+
3
+ import { Badge } from "@suphark/ui/components/ui/badge";
4
+ import { Button } from "@suphark/ui/components/ui/button";
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@suphark/ui/components/ui/card";
13
+ import {
14
+ InputGroup,
15
+ InputGroupAddon,
16
+ InputGroupInput,
17
+ } from "@suphark/ui/components/ui/input-group";
18
+ import { Kbd } from "@suphark/ui/components/ui/kbd";
19
+ import {
20
+ Accessibility,
21
+ ArrowRight,
22
+ Boxes,
23
+ CheckCircle2,
24
+ Compass,
25
+ FileCode2,
26
+ Layers,
27
+ Palette,
28
+ RefreshCw,
29
+ Search,
30
+ Sparkles,
31
+ Zap,
32
+ } from "lucide-react";
33
+
34
+ interface ShowcaseOverviewProps {
35
+ onSelectTab: (tab: string) => void;
36
+ searchQuery: string;
37
+ onSearchChange: (query: string) => void;
38
+ }
39
+
40
+ export function ShowcaseOverview({
41
+ onSelectTab,
42
+ searchQuery,
43
+ onSearchChange,
44
+ }: ShowcaseOverviewProps) {
45
+ const pillars = [
46
+ {
47
+ id: "guidelines",
48
+ tab: "guidelines-recipes",
49
+ title: "1. Web Interface Guidelines",
50
+ subtitle: "Mandatory Baseline Standard",
51
+ icon: Accessibility,
52
+ badge: "Baseline",
53
+ description:
54
+ "มาตรฐานการเข้าถึง (A11y), Keyboard Navigation, Focus Rings, Accessible Labels, Error Recovery และ Motion Accessibility ตาม Vercel Web Interface Guidelines",
55
+ highlights: [
56
+ "Visible focus rings (focus-visible:ring-2)",
57
+ "Icon buttons have aria-label / sr-only",
58
+ "Dialogs/Sheets require accessible Title & Description",
59
+ "Clear error guidance without user-blame",
60
+ ],
61
+ },
62
+ {
63
+ id: "shadcn",
64
+ tab: "primitives",
65
+ title: "2. shadcn/ui Primitives",
66
+ subtitle: "Source-Owned UI Architecture",
67
+ icon: Boxes,
68
+ badge: "60+ Primitives",
69
+ description:
70
+ "คอมโพเนนต์พื้นฐานที่ครอบคลุมทั้ง UI และ Base UI ผสมผสานผ่าน Tailwind v4 Semantic Tokens และ Composition-first pattern",
71
+ highlights: [
72
+ "FieldGroup + Field for unified forms",
73
+ "InputGroup for icons & embedded actions",
74
+ "Button loading with Spinner + data-icon",
75
+ "Items strictly within their Group containers",
76
+ ],
77
+ },
78
+ {
79
+ id: "frontend-design",
80
+ tab: "guidelines-recipes",
81
+ title: "3. Frontend Design & UX Voice",
82
+ subtitle: "Intentionality & Copywriting",
83
+ icon: Sparkles,
84
+ badge: "User Voice",
85
+ description:
86
+ "การออกแบบที่เจาะจงกับแอปงานภายในของ Suphark การจัดลำดับสายตา ความกระชับสแกนง่าย และภาษา UX ที่เน้นสิ่งที่ผู้ใช้ควบคุมได้ (Active Voice)",
87
+ highlights: [
88
+ "Dense & scannable operational density",
89
+ "Active voice actions ('Save changes', not 'Submit')",
90
+ "Action-to-toast consistency ('Publish' -> 'Published')",
91
+ "Empty states as invitations to act",
92
+ ],
93
+ },
94
+ {
95
+ id: "redesign",
96
+ tab: "guidelines-recipes",
97
+ title: "4. Redesign Workflow",
98
+ subtitle: "Behavior-Preserving Evolution",
99
+ icon: RefreshCw,
100
+ badge: "Safety",
101
+ description:
102
+ "ระเบียบการปรับปรุง UI โดยคงความสามารถเดิม 100% เช่น RBAC Permissions, Data Contracts, Routes, Server Actions, Filters, และ Pagination",
103
+ highlights: [
104
+ "Preserve server action guards & auth contracts",
105
+ "Preserve URL search params & filter states",
106
+ "Preserve loading skeletons & empty fallbacks",
107
+ "Zero-regression verification plan",
108
+ ],
109
+ },
110
+ ];
111
+
112
+ const quickLinks = [
113
+ { name: "Semantic Color Tokens", tab: "foundations", icon: Palette },
114
+ { name: "Buttons & Action Hierarchy", tab: "primitives", icon: Zap },
115
+ { name: "Field-based Forms & InputGroup", tab: "forms", icon: Layers },
116
+ { name: "Data Tables & States", tab: "data-display", icon: Boxes },
117
+ { name: "Overlays (Dialog, Sheet, Drawer)", tab: "overlays", icon: Compass },
118
+ { name: "Domain Patterns & Code Recipes", tab: "domain-patterns", icon: FileCode2 },
119
+ ];
120
+
121
+ return (
122
+ <div className="flex flex-col gap-8">
123
+ {/* Hero Banner */}
124
+ <section className="relative overflow-hidden rounded-2xl border bg-gradient-to-br from-card via-card to-muted/40 p-6 md:p-8 shadow-xs">
125
+ <div className="flex flex-col gap-4 max-w-4xl">
126
+ <div className="flex flex-wrap items-center gap-2">
127
+ <Badge variant="default" className="gap-1">
128
+ <Sparkles className="size-3" /> @suphark/ui Design System
129
+ </Badge>
130
+ <Badge variant="secondary">Next.js App Router</Badge>
131
+ <Badge variant="outline">Tailwind v4</Badge>
132
+ <Badge variant="outline">shadcn/ui</Badge>
133
+ <Badge variant="outline">Web Interface Guidelines</Badge>
134
+ </div>
135
+
136
+ <h2 className="text-2xl md:text-3xl font-bold tracking-tight text-foreground">
137
+ ภาพรวมระบบการออกแบบและมาตรฐาน UI ของทุกแอป
138
+ </h2>
139
+
140
+ <p className="text-sm md:text-base text-muted-foreground leading-relaxed">
141
+ ศูนย์กลางมาตรฐานการออกแบบและการประกอบคอมโพเนนต์สำหรับทุกแอปของ Suphark (Pi Auth, DueBell, Pi
142
+ PDF, supplychain) เน้นความกระชับ สแกนง่าย รองรับงานประจำวันที่มีข้อมูลหนาแน่น (Operational Density)
143
+ ผสาน 4 เสาหลัก: <strong>Web Interface Guidelines</strong>,{" "}
144
+ <strong>shadcn/ui Primitives</strong>,<strong>Frontend Design & UX Copy</strong>, และ{" "}
145
+ <strong>Redesign Safety Workflow</strong>
146
+ </p>
147
+
148
+ <div className="flex flex-wrap items-center gap-3 pt-2">
149
+ <Button onClick={() => onSelectTab("primitives")} className="gap-2">
150
+ <Boxes className="size-4" /> สำรวจคอมโพเนนต์ทั้งหมด
151
+ </Button>
152
+ <Button
153
+ variant="outline"
154
+ onClick={() => onSelectTab("domain-patterns")}
155
+ className="gap-2"
156
+ >
157
+ <Compass className="size-4" /> ตัวอย่างหน้าจอ
158
+ </Button>
159
+ <Button
160
+ variant="ghost"
161
+ onClick={() => onSelectTab("guidelines-recipes")}
162
+ className="gap-2"
163
+ >
164
+ <FileCode2 className="size-4" /> Code Recipes & Agent Rules
165
+ </Button>
166
+ </div>
167
+ </div>
168
+ </section>
169
+
170
+ {/* Global Quick Search */}
171
+ <section className="flex flex-col gap-3">
172
+ <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
173
+ <div>
174
+ <h3 className="text-lg font-semibold text-foreground">ค้นหาคอมโพเนนต์และคู่มือ</h3>
175
+ <p className="text-xs text-muted-foreground">
176
+ พิมพ์ชื่อคอมโพเนนต์, Token, Pattern หรือ Rule ที่ต้องการค้นหา
177
+ </p>
178
+ </div>
179
+ <div className="w-full sm:w-80">
180
+ <InputGroup>
181
+ <InputGroupAddon>
182
+ <Search className="size-4 text-muted-foreground" />
183
+ </InputGroupAddon>
184
+ <InputGroupInput
185
+ placeholder="เช่น button, field, dialog, token..."
186
+ value={searchQuery}
187
+ onChange={(e) => onSearchChange(e.target.value)}
188
+ />
189
+ </InputGroup>
190
+ </div>
191
+ </div>
192
+
193
+ {/* Quick jump tags */}
194
+ <div className="flex flex-wrap items-center gap-2 pt-1">
195
+ <span className="text-xs text-muted-foreground flex items-center gap-1">
196
+ <Kbd>Jump to</Kbd>
197
+ </span>
198
+ {quickLinks.map((link) => (
199
+ <button
200
+ key={link.name}
201
+ type="button"
202
+ onClick={() => onSelectTab(link.tab)}
203
+ className="inline-flex items-center gap-1.5 rounded-md border bg-card px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer"
204
+ >
205
+ <link.icon className="size-3" />
206
+ {link.name}
207
+ </button>
208
+ ))}
209
+ </div>
210
+ </section>
211
+
212
+ {/* The 4 Pillars */}
213
+ <section className="flex flex-col gap-4">
214
+ <div className="flex flex-col gap-1">
215
+ <h3 className="text-lg font-semibold text-foreground">
216
+ สถาปัตยกรรม 4 เสาหลัก (The 4 UI Pillars)
217
+ </h3>
218
+ <p className="text-xs text-muted-foreground">
219
+ ทุกหน้าจอและฟีเจอร์ใน codebase นี้ต้องสอดคล้องกับหลักการทั้ง 4 ด้านอย่างเคร่งครัด
220
+ </p>
221
+ </div>
222
+
223
+ <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
224
+ {pillars.map((pillar) => {
225
+ const Icon = pillar.icon;
226
+ return (
227
+ <Card
228
+ key={pillar.id}
229
+ className="flex flex-col justify-between border transition-all hover:border-primary/50 hover:shadow-xs"
230
+ >
231
+ <CardHeader className="pb-3">
232
+ <div className="flex items-center justify-between gap-2">
233
+ <div className="flex size-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
234
+ <Icon className="size-5" />
235
+ </div>
236
+ <Badge variant="secondary" className="text-xs font-normal">
237
+ {pillar.badge}
238
+ </Badge>
239
+ </div>
240
+ <CardTitle className="text-base font-semibold pt-2">{pillar.title}</CardTitle>
241
+ <CardDescription className="text-xs">{pillar.subtitle}</CardDescription>
242
+ </CardHeader>
243
+
244
+ <CardContent className="flex flex-col gap-3 pb-3">
245
+ <p className="text-xs text-muted-foreground leading-relaxed">
246
+ {pillar.description}
247
+ </p>
248
+ <div className="flex flex-col gap-1.5 rounded-md bg-muted/50 p-2.5">
249
+ {pillar.highlights.map((item) => (
250
+ <div key={item} className="flex items-start gap-1.5 text-xs">
251
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
252
+ <span className="text-foreground/90">{item}</span>
253
+ </div>
254
+ ))}
255
+ </div>
256
+ </CardContent>
257
+
258
+ <CardFooter className="pt-0">
259
+ <Button
260
+ variant="ghost"
261
+ size="sm"
262
+ className="w-full justify-between text-xs"
263
+ onClick={() => onSelectTab(pillar.tab)}
264
+ >
265
+ ดูรายละเอียด
266
+ <ArrowRight className="size-3.5" />
267
+ </Button>
268
+ </CardFooter>
269
+ </Card>
270
+ );
271
+ })}
272
+ </div>
273
+ </section>
274
+
275
+ {/* Operational Principles */}
276
+ <section className="rounded-xl border bg-card p-6">
277
+ <div className="flex flex-col gap-4">
278
+ <div className="flex flex-col gap-1">
279
+ <h3 className="text-base font-semibold">กติกางานออกแบบระดับระบบ (System Design Rules)</h3>
280
+ <p className="text-xs text-muted-foreground">
281
+ ข้อควรปฏิบัติและข้อห้ามสำหรับการสร้างและแก้ไข UI ใน codebase นี้
282
+ </p>
283
+ </div>
284
+
285
+ <div className="grid gap-4 md:grid-cols-2">
286
+ <div className="flex flex-col gap-2 rounded-lg border border-primary/20 bg-primary/5 p-4">
287
+ <h4 className="font-semibold text-xs text-primary uppercase tracking-wider">
288
+ ✓ สิ่งที่ต้องทำ (Do)
289
+ </h4>
290
+ <ul className="flex flex-col gap-2 text-xs text-muted-foreground">
291
+ <li className="flex items-start gap-2">
292
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
293
+ <span>
294
+ ใช้ <code>FieldGroup</code> และ <code>Field</code> เป็นโครงสร้างฟอร์มเสมอ
295
+ </span>
296
+ </li>
297
+ <li className="flex items-start gap-2">
298
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
299
+ <span>
300
+ ใช้ <code>flex flex-col gap-*</code> หรือ grid gap แทน <code>space-x/y</code>
301
+ </span>
302
+ </li>
303
+ <li className="flex items-start gap-2">
304
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
305
+ <span>
306
+ ใส่ <code>aria-label</code> ใน icon-only button ทุกตัวโดยไม่มีข้อยกเว้น
307
+ </span>
308
+ </li>
309
+ <li className="flex items-start gap-2">
310
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
311
+ <span>
312
+ ใช้ <code>size-*</code> เมื่อความกว้างและความสูงเท่ากัน (เช่น Avatar, Icon box)
313
+ </span>
314
+ </li>
315
+ <li className="flex items-start gap-2">
316
+ <CheckCircle2 className="size-3.5 text-primary mt-0.5 shrink-0" />
317
+ <span>
318
+ เตรียม 3 สถานะข้อมูลเสมอ: Ready, Loading Skeleton, และ Empty State ที่มี CTA
319
+ </span>
320
+ </li>
321
+ </ul>
322
+ </div>
323
+
324
+ <div className="flex flex-col gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-4">
325
+ <h4 className="font-semibold text-xs text-destructive uppercase tracking-wider">
326
+ ✕ สิ่งที่ต้องหลีกเลี่ยง (Avoid)
327
+ </h4>
328
+ <ul className="flex flex-col gap-2 text-xs text-muted-foreground">
329
+ <li className="flex items-start gap-2">
330
+ <span className="text-destructive font-bold shrink-0">•</span>
331
+ <span>
332
+ ห้ามใช้ raw color utility เช่น <code>bg-blue-500</code> หรือ{" "}
333
+ <code>text-red-500</code> ในระบบงานจริง
334
+ </span>
335
+ </li>
336
+ <li className="flex items-start gap-2">
337
+ <span className="text-destructive font-bold shrink-0">•</span>
338
+ <span>
339
+ ห้ามกำหนด arbitrary pixel font sizes เช่น <code>text-[10px]</code> หรือ{" "}
340
+ <code>text-[9px]</code>
341
+ </span>
342
+ </li>
343
+ <li className="flex items-start gap-2">
344
+ <span className="text-destructive font-bold shrink-0">•</span>
345
+ <span>
346
+ ห้ามใส่ manual <code>z-index</code> บน overlay (Dialog, Sheet, Popover จัดการเอง)
347
+ </span>
348
+ </li>
349
+ <li className="flex items-start gap-2">
350
+ <span className="text-destructive font-bold shrink-0">•</span>
351
+ <span>
352
+ ห้ามแก้ไขไฟล์ใน <code>src/components/ui/*</code> โดยตรงโดยไม่ได้รับอนุญาต
353
+ </span>
354
+ </li>
355
+ <li className="flex items-start gap-2">
356
+ <span className="text-destructive font-bold shrink-0">•</span>
357
+ <span>
358
+ ห้ามสร้าง Dialog หรือ Sheet โดยไม่มี Title และ Description สำหรับ Screen Reader
359
+ </span>
360
+ </li>
361
+ </ul>
362
+ </div>
363
+ </div>
364
+ </div>
365
+ </section>
366
+ </div>
367
+ );
368
+ }