gladvn 0.2.35 → 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 +2 -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
|
@@ -1,1172 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
CodeIcon,
|
|
10
|
-
ComponentIcon,
|
|
11
|
-
CopyIcon,
|
|
12
|
-
DatabaseIcon,
|
|
13
|
-
LayersIcon,
|
|
14
|
-
PaintbrushIcon,
|
|
15
|
-
PaletteIcon,
|
|
16
|
-
ShieldCheckIcon,
|
|
17
|
-
SlidersHorizontalIcon,
|
|
18
|
-
SparklesIcon
|
|
19
|
-
} from "lucide-react";
|
|
20
|
-
import { toast } from "sonner";
|
|
21
|
-
|
|
22
|
-
import { ProgressPreset as Progress } from "../../components/macro/progress-preset";
|
|
23
|
-
import {
|
|
24
|
-
Avatar,
|
|
25
|
-
AvatarFallback,
|
|
26
|
-
AvatarImage
|
|
27
|
-
} from "../../components/micro/avatar";
|
|
28
|
-
import { Button } from "../../components/micro/button";
|
|
29
|
-
import {
|
|
30
|
-
Card,
|
|
31
|
-
CardContent,
|
|
32
|
-
CardHeader,
|
|
33
|
-
CardTitle
|
|
34
|
-
} from "../../components/micro/card";
|
|
35
|
-
import { Label } from "../../components/micro/label";
|
|
36
|
-
import {
|
|
37
|
-
Select,
|
|
38
|
-
SelectContent,
|
|
39
|
-
SelectItem,
|
|
40
|
-
|
|
41
|
-
SelectTrigger,
|
|
42
|
-
SelectValue
|
|
43
|
-
} from "../../components/micro/select";
|
|
44
|
-
import { Switch } from "../../components/micro/switch";
|
|
45
|
-
import { ColorSwatch } from "../../dev/components/showcase";
|
|
46
|
-
import { COLORS, STATS } from "../../dev/data";
|
|
47
|
-
import { cn } from "../../lib/utils";
|
|
48
|
-
|
|
49
|
-
function CodeBlock({
|
|
50
|
-
type,
|
|
51
|
-
title,
|
|
52
|
-
children }: {
|
|
53
|
-
type: "success" | "destructive";
|
|
54
|
-
title: string;
|
|
55
|
-
children: React.ReactNode;
|
|
56
|
-
}) {
|
|
57
|
-
const isSuccess = type === "success";
|
|
58
|
-
return (
|
|
59
|
-
<div
|
|
60
|
-
className={cn(
|
|
61
|
-
"p-4 rounded-xl border border-border shadow-sm text-[11px] sm:text-xs font-mono",
|
|
62
|
-
isSuccess
|
|
63
|
-
? "border-success/20 bg-success/5"
|
|
64
|
-
: "border-destructive/20 bg-destructive/5 opacity-80",
|
|
65
|
-
)}
|
|
66
|
-
>
|
|
67
|
-
<div
|
|
68
|
-
className={cn(
|
|
69
|
-
"font-semibold mb-2 flex items-center gap-2",
|
|
70
|
-
isSuccess ? "text-success" : "text-destructive",
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
{isSuccess ? "✅" : "❌"} {title}
|
|
74
|
-
</div>
|
|
75
|
-
<div
|
|
76
|
-
className={cn(
|
|
77
|
-
"text-muted-foreground pl-3 border-l-2 leading-relaxed",
|
|
78
|
-
isSuccess ? "border-success/50" : "border-destructive/50",
|
|
79
|
-
)}
|
|
80
|
-
>
|
|
81
|
-
{children}
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { HeroSection } from "./overview-components/HeroSection";
|
|
3
|
+
import { DashboardPreview } from "./overview-components/DashboardPreview";
|
|
4
|
+
import { PrinciplesSection } from "./overview-components/PrinciplesSection";
|
|
5
|
+
import { ArchitectureSection } from "./overview-components/ArchitectureSection";
|
|
6
|
+
import { FeatureGridSection } from "./overview-components/FeatureGridSection";
|
|
7
|
+
import { ColorPaletteSection } from "./overview-components/ColorPaletteSection";
|
|
8
|
+
import { FooterCTA } from "./overview-components/FooterCTA";
|
|
86
9
|
|
|
87
10
|
export default function OverviewSection() {
|
|
88
|
-
const [copied, setCopied] = useState(false);
|
|
89
|
-
const [mounted, setMounted] = useState(false);
|
|
90
|
-
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
setMounted(true);
|
|
93
|
-
}, []);
|
|
94
|
-
|
|
95
|
-
const handleCopy = () => {
|
|
96
|
-
navigator.clipboard.writeText("npx gladvn init");
|
|
97
|
-
setCopied(true);
|
|
98
|
-
toast.success("Đã copy lệnh vào clipboard");
|
|
99
|
-
setTimeout(() => setCopied(false), 2000);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
11
|
return (
|
|
103
12
|
<div className="space-y-24 overflow-hidden pb-24 font-sans">
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<div
|
|
111
|
-
className="w-[30rem] h-[20rem] bg-primary/40 rounded-full mix-blend-multiply animate-pulse"
|
|
112
|
-
style={{ animationDuration: "8s" }}
|
|
113
|
-
/>
|
|
114
|
-
<div
|
|
115
|
-
className="w-[20rem] h-[15rem] bg-info/30 rounded-full mix-blend-multiply animate-pulse absolute top-10"
|
|
116
|
-
style={{ animationDuration: "10s" }}
|
|
117
|
-
/>
|
|
118
|
-
</div>
|
|
119
|
-
|
|
120
|
-
<div className="container relative z-10 flex flex-col items-center text-center px-4">
|
|
121
|
-
<div className="inline-flex items-center gap-2 px-4 py-1.5 mb-8 text-sm font-medium rounded-full border border-primary/20 bg-background/50 backdrop-blur-md shadow-sm animate-fade-up">
|
|
122
|
-
<CodeIcon className="w-3.5 h-3.5 text-primary" />
|
|
123
|
-
<span className="text-muted-foreground">
|
|
124
|
-
Copy mã · Tuỳ biến tự do · Không lock-in
|
|
125
|
-
</span>
|
|
126
|
-
</div>
|
|
127
|
-
|
|
128
|
-
<h1
|
|
129
|
-
className="max-w-4xl text-5xl md:text-7xl font-extrabold tracking-tighter mb-8 animate-fade-up"
|
|
130
|
-
style={{ animationDelay: "100ms", animationFillMode: "both" }}
|
|
131
|
-
>
|
|
132
|
-
<span className="block text-foreground drop-shadow-sm">
|
|
133
|
-
Tinh tế. Đẳng cấp.
|
|
134
|
-
</span>
|
|
135
|
-
<span className="block mt-2 bg-gradient-to-r leading-[1.2] from-primary via-info to-primary bg-[length:200%_auto] bg-clip-text text-transparent animate-[spin_8s_linear_infinite] [animation-name:gradient] [animation-duration:8s] [animation-timing-function:linear] [animation-iteration-count:infinite]">
|
|
136
|
-
Không giới hạn.
|
|
137
|
-
</span>
|
|
138
|
-
</h1>
|
|
139
|
-
|
|
140
|
-
<p
|
|
141
|
-
className="max-w-2xl text-lg md:text-xl text-muted-foreground leading-relaxed mb-10 animate-fade-up"
|
|
142
|
-
style={{ animationDelay: "200ms", animationFillMode: "both" }}
|
|
143
|
-
>
|
|
144
|
-
Phần lớn component library giữ code trong node_modules — bạn dùng
|
|
145
|
-
được nhưng không sửa được. gladvn copy thẳng vào{" "}
|
|
146
|
-
<code className="text-sm bg-primary/20 text-primary px-1.5 py-0.5 rounded">
|
|
147
|
-
src/
|
|
148
|
-
</code>{" "}
|
|
149
|
-
của bạn.{" "}
|
|
150
|
-
<strong className="text-foreground">
|
|
151
|
-
Đọc được, sửa được, xóa được.
|
|
152
|
-
</strong>
|
|
153
|
-
</p>
|
|
154
|
-
|
|
155
|
-
<div
|
|
156
|
-
className="max-w-2xl text-lg md:text-xl font-medium text-foreground/90 italic mt-2 p-5 border-l-4 border-primary bg-primary/5 rounded-r-xl shadow-sm animate-fade-up"
|
|
157
|
-
style={{ animationDelay: "300ms", animationFillMode: "both" }}
|
|
158
|
-
>
|
|
159
|
-
"Thư viện này sinh ra để giúp bạn code nhanh hơn, sống nhàn hơn, đừng tự làm khó mình."
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
|
|
163
|
-
{/* 3D Floating Showcase Dashboard */}
|
|
164
|
-
<div
|
|
165
|
-
className="mt-20 relative max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 animate-fade-up"
|
|
166
|
-
style={{ animationDelay: "500ms", animationFillMode: "both" }}
|
|
167
|
-
>
|
|
168
|
-
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent z-20 pointer-events-none h-full w-full" />
|
|
169
|
-
|
|
170
|
-
<div className="relative rounded-2xl border border-border bg-card/40 backdrop-blur-2xl shadow-2xl overflow-hidden [transform:perspective(1200px)_rotateX(5deg)] [transform-origin:top_center] hover:[transform:perspective(1200px)_rotateX(0deg)] transition-transform duration-700 ease-out">
|
|
171
|
-
<div className="h-12 bg-muted/30 border-b border-b-border flex items-center px-4 gap-2">
|
|
172
|
-
<div className="flex gap-2">
|
|
173
|
-
<div className="size-3.5 rounded-full bg-destructive/80 shadow-sm" />
|
|
174
|
-
<div className="size-3.5 rounded-full bg-warning/80 shadow-sm" />
|
|
175
|
-
<div className="size-3.5 rounded-full bg-success/80 shadow-sm" />
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
|
|
179
|
-
<div className="p-8 grid grid-cols-1 md:grid-cols-3 gap-8 relative">
|
|
180
|
-
<div className="space-y-6 md:col-span-1 z-10">
|
|
181
|
-
<Card className="bg-background/80 shadow-lg border-border/50 backdrop-blur-xl group hover:border-primary/50 transition-colors">
|
|
182
|
-
<CardHeader className="pb-3">
|
|
183
|
-
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
|
184
|
-
<div className="size-2 rounded-full bg-success animate-pulse shadow-[0_0_8px_var(--success)]" />
|
|
185
|
-
Hệ thống Thời gian thực
|
|
186
|
-
</CardTitle>
|
|
187
|
-
</CardHeader>
|
|
188
|
-
<CardContent>
|
|
189
|
-
<div className="space-y-5">
|
|
190
|
-
<div className="space-y-2">
|
|
191
|
-
<div className="flex justify-between text-xs font-medium">
|
|
192
|
-
<span className="text-muted-foreground">Tải CPU</span>
|
|
193
|
-
<span className="text-primary font-mono">
|
|
194
|
-
{mounted ? "24%" : "0%"}
|
|
195
|
-
</span>
|
|
196
|
-
</div>
|
|
197
|
-
<Progress value={mounted ? 24 : 0} className="h-1.5" />
|
|
198
|
-
</div>
|
|
199
|
-
<div className="space-y-2">
|
|
200
|
-
<div className="flex justify-between text-xs font-medium">
|
|
201
|
-
<span className="text-muted-foreground">Bộ nhớ</span>
|
|
202
|
-
<span className="text-warning font-mono">
|
|
203
|
-
{mounted ? "82%" : "0%"}
|
|
204
|
-
</span>
|
|
205
|
-
</div>
|
|
206
|
-
<Progress
|
|
207
|
-
value={mounted ? 82 : 0}
|
|
208
|
-
color="warning"
|
|
209
|
-
className="h-1.5"
|
|
210
|
-
/>
|
|
211
|
-
</div>
|
|
212
|
-
</div>
|
|
213
|
-
</CardContent>
|
|
214
|
-
</Card>
|
|
215
|
-
|
|
216
|
-
<div className="flex flex-col gap-4 p-5 rounded-xl border border-border/50 bg-background/60 backdrop-blur-xl shadow-lg">
|
|
217
|
-
<div className="flex items-center justify-between">
|
|
218
|
-
<Label className="text-sm font-medium cursor-pointer">
|
|
219
|
-
Auto-scaling
|
|
220
|
-
</Label>
|
|
221
|
-
<Switch defaultChecked />
|
|
222
|
-
</div>
|
|
223
|
-
<Select defaultValue="edge">
|
|
224
|
-
<SelectTrigger className="w-full bg-background/50">
|
|
225
|
-
<SelectValue placeholder="Chọn vùng" />
|
|
226
|
-
</SelectTrigger>
|
|
227
|
-
|
|
228
|
-
<SelectContent>
|
|
229
|
-
<SelectItem value="edge">
|
|
230
|
-
Edge Network (Toàn cầu)
|
|
231
|
-
</SelectItem>
|
|
232
|
-
<SelectItem value="us-east">
|
|
233
|
-
US East (Virginia)
|
|
234
|
-
</SelectItem>
|
|
235
|
-
<SelectItem value="ap-se">
|
|
236
|
-
AP South East (Sing)
|
|
237
|
-
</SelectItem>
|
|
238
|
-
</SelectContent>
|
|
239
|
-
|
|
240
|
-
</Select>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
|
|
244
|
-
<div className="md:col-span-2 rounded-xl border border-border/50 bg-muted/20 p-6 flex items-center justify-center relative overflow-hidden group/canvas">
|
|
245
|
-
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(var(--primary-rgb),0.1)_0,transparent_100%)] opacity-0 group-hover/canvas:opacity-100 transition-opacity duration-700" />
|
|
246
|
-
|
|
247
|
-
<div className="relative z-10 w-full max-w-md space-y-4 perspective-1000">
|
|
248
|
-
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:-translate-y-2 group-hover/canvas:rotate-1 transition-all duration-500 delay-75">
|
|
249
|
-
<div className="p-3 bg-primary/10 rounded-lg text-primary shadow-inner">
|
|
250
|
-
<LayersIcon className="size-6" />
|
|
251
|
-
</div>
|
|
252
|
-
<div>
|
|
253
|
-
<h4 className="font-bold text-sm">
|
|
254
|
-
Kiến trúc Micro/Macro
|
|
255
|
-
</h4>
|
|
256
|
-
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
257
|
-
Primitive nhỏ, lắp thành preset lớn
|
|
258
|
-
</p>
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
261
|
-
|
|
262
|
-
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:translate-x-2 group-hover/canvas:-rotate-1 transition-all duration-500 delay-150">
|
|
263
|
-
<div className="p-3 bg-info/10 rounded-lg text-info shadow-inner">
|
|
264
|
-
<DatabaseIcon className="size-6" />
|
|
265
|
-
</div>
|
|
266
|
-
<div>
|
|
267
|
-
<h4 className="font-bold text-sm">
|
|
268
|
-
Thiết kế theo Dữ liệu
|
|
269
|
-
</h4>
|
|
270
|
-
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
271
|
-
Truyền items vào root, không map() thủ công
|
|
272
|
-
</p>
|
|
273
|
-
</div>
|
|
274
|
-
</div>
|
|
275
|
-
|
|
276
|
-
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:-translate-y-1 transition-all duration-500 delay-200">
|
|
277
|
-
<div className="p-3 bg-success/10 rounded-lg text-success shadow-inner">
|
|
278
|
-
<ShieldCheckIcon className="size-6" />
|
|
279
|
-
</div>
|
|
280
|
-
<div>
|
|
281
|
-
<h4 className="font-bold text-sm">Styling có Kỷ luật</h4>
|
|
282
|
-
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
283
|
-
Nói không với Magic CSS
|
|
284
|
-
</p>
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
</div>
|
|
292
|
-
</section>
|
|
293
|
-
|
|
294
|
-
{/* 📈 STATS STRIP */}
|
|
295
|
-
<section className="container max-w-6xl mx-auto border-y border-y-border bg-muted/5 py-12 relative overflow-hidden">
|
|
296
|
-
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-primary/5 to-transparent animate-[pulse_4s_ease-in-out_infinite]" />
|
|
297
|
-
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-4 divide-x-0 md:divide-x relative z-10">
|
|
298
|
-
{STATS.map((s) => (
|
|
299
|
-
<div
|
|
300
|
-
key={s.label}
|
|
301
|
-
className="flex flex-col items-center justify-center text-center space-y-2 group"
|
|
302
|
-
>
|
|
303
|
-
<div className="text-4xl md:text-5xl font-black tracking-tighter text-foreground group-hover:text-primary group-hover:scale-110 transition-all duration-300">
|
|
304
|
-
{s.value}
|
|
305
|
-
</div>
|
|
306
|
-
<div className="text-xs md:text-sm font-bold uppercase tracking-[0.2em] text-muted-foreground">
|
|
307
|
-
{s.label}
|
|
308
|
-
</div>
|
|
309
|
-
</div>
|
|
310
|
-
))}
|
|
311
|
-
</div>
|
|
312
|
-
</section>
|
|
313
|
-
|
|
314
|
-
{/* 🧠 BENTO BOX PHILOSOPHIES */}
|
|
13
|
+
<HeroSection />
|
|
14
|
+
|
|
15
|
+
<DashboardPreview />
|
|
16
|
+
|
|
17
|
+
<PrinciplesSection />
|
|
18
|
+
|
|
315
19
|
<section className="container max-w-6xl mx-auto space-y-12 px-4">
|
|
316
|
-
<
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
</h2>
|
|
320
|
-
<p className="text-muted-foreground text-lg">
|
|
321
|
-
Nhiều dự án thường bắt đầu "bốc mùi" sau một thời gian — đụng vào đâu cũng sợ gãy, muốn sửa mà rén. gladvn chia code thành{" "}
|
|
322
|
-
<strong className="text-foreground">các tầng rạch ròi</strong>
|
|
323
|
-
{", "}giúp bạn luôn biết chính xác mình đang sửa cái gì, ảnh hưởng tới đâu. Tâm an, code mới nhàn!
|
|
324
|
-
</p>
|
|
325
|
-
</div>
|
|
326
|
-
|
|
327
|
-
{/* FULL OWNERSHIP - FEATURED BANNER */}
|
|
328
|
-
<div
|
|
329
|
-
id="ownership-section"
|
|
330
|
-
className="mb-12 rounded-[2.5rem] border-2 border-primary/50 bg-primary/5 p-4 sm:p-6 md:p-12 flex flex-col gap-10 group overflow-hidden relative hover:bg-primary/10 transition-colors duration-500 shadow-2xl shadow-primary/10"
|
|
331
|
-
>
|
|
332
|
-
<div className="flex flex-col md:flex-row items-start gap-6 md:gap-8">
|
|
333
|
-
<div className="relative z-10 flex-1 space-y-6">
|
|
334
|
-
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-primary text-primary-foreground text-sm font-bold uppercase tracking-wider shadow-lg shadow-primary/20">
|
|
335
|
-
<SparklesIcon className="size-4" /> Cốt lõi
|
|
336
|
-
</div>
|
|
337
|
-
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
338
|
-
Code là của bạn, 100%
|
|
339
|
-
</h3>
|
|
340
|
-
<p className="text-muted-foreground text-lg leading-relaxed max-w-2xl">
|
|
341
|
-
Chạy một lệnh — toàn bộ components, hooks, styles, contexts được
|
|
342
|
-
copy thẳng vào thư mục{" "}
|
|
343
|
-
<code className="text-sm bg-primary/20 text-primary px-1.5 py-0.5 rounded">
|
|
344
|
-
src/
|
|
345
|
-
</code>{" "}
|
|
346
|
-
của bạn.{" "}
|
|
347
|
-
<strong className="text-foreground">
|
|
348
|
-
Không qua node_modules. Không phụ thuộc vào ai.
|
|
349
|
-
</strong>{" "}
|
|
350
|
-
Đọc được, sửa được, xoá được từng dòng.
|
|
351
|
-
</p>
|
|
352
|
-
|
|
353
|
-
<div className="flex items-center gap-4 pt-2">
|
|
354
|
-
<button
|
|
355
|
-
onClick={handleCopy}
|
|
356
|
-
className="bg-background/80 hover:bg-background border-border backdrop-blur-md px-6 py-4 rounded-2xl border hover:border-primary/50 transition-colors font-mono text-sm shadow-inner flex items-center gap-4 cursor-pointer group/copy"
|
|
357
|
-
>
|
|
358
|
-
<span className="text-primary font-bold">~</span>
|
|
359
|
-
<span>npx gladvn init</span>
|
|
360
|
-
<div className="ml-4 text-muted-foreground group-hover/copy:text-primary transition-colors">
|
|
361
|
-
{copied ? (
|
|
362
|
-
<CheckIcon className="size-4 text-success" />
|
|
363
|
-
) : (
|
|
364
|
-
<CopyIcon className="size-4" />
|
|
365
|
-
)}
|
|
366
|
-
</div>
|
|
367
|
-
</button>
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
|
|
371
|
-
<div className="relative z-10 w-full md:w-1/3 flex flex-col gap-4">
|
|
372
|
-
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:-translate-x-2 transition-transform">
|
|
373
|
-
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
374
|
-
<CheckIcon className="size-4" />
|
|
375
|
-
</div>
|
|
376
|
-
<div>
|
|
377
|
-
<h4 className="font-bold text-success text-lg">
|
|
378
|
-
Toàn bộ Component & Hook
|
|
379
|
-
</h4>
|
|
380
|
-
<p className="text-xs text-success/80 mt-1">
|
|
381
|
-
Nằm gọn trong{" "}
|
|
382
|
-
<code className="opacity-80">
|
|
383
|
-
src/components/micro/ & macro/
|
|
384
|
-
</code>
|
|
385
|
-
</p>
|
|
386
|
-
</div>
|
|
387
|
-
</div>
|
|
388
|
-
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:translate-x-2 transition-transform">
|
|
389
|
-
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
390
|
-
<CheckIcon className="size-4" />
|
|
391
|
-
</div>
|
|
392
|
-
<div>
|
|
393
|
-
<h4 className="font-bold text-success text-lg">
|
|
394
|
-
CSS Token & Theme Config
|
|
395
|
-
</h4>
|
|
396
|
-
<p className="text-xs text-success/80 mt-1">
|
|
397
|
-
OKLCH color tokens, dark/light mode — đẹp ngay từ đầu
|
|
398
|
-
</p>
|
|
399
|
-
</div>
|
|
400
|
-
</div>
|
|
401
|
-
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:-translate-x-2 transition-transform">
|
|
402
|
-
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
403
|
-
<CheckIcon className="size-4" />
|
|
404
|
-
</div>
|
|
405
|
-
<div>
|
|
406
|
-
<h4 className="font-bold text-success text-lg">
|
|
407
|
-
Tự động cài Dependency
|
|
408
|
-
</h4>
|
|
409
|
-
<p className="text-xs text-success/80 mt-1">
|
|
410
|
-
Tự nhận diện npm, yarn, pnpm, bun
|
|
411
|
-
</p>
|
|
412
|
-
</div>
|
|
413
|
-
</div>
|
|
414
|
-
</div>
|
|
415
|
-
</div>
|
|
416
|
-
|
|
417
|
-
{/* WHERE TO EDIT GUIDE */}
|
|
418
|
-
<div className="relative z-10 border-t border-primary/20 pt-8">
|
|
419
|
-
<p className="text-sm font-bold uppercase tracking-wider text-primary mb-5">
|
|
420
|
-
Tuỳ chỉnh theo từng tầng kiến trúc
|
|
421
|
-
</p>
|
|
422
|
-
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
423
|
-
{/* MACRO — RECOMMENDED */}
|
|
424
|
-
<div className="p-5 rounded-2xl border-2 border-primary/40 bg-primary/5 space-y-3 relative">
|
|
425
|
-
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-primary bg-primary/10 px-2 py-0.5 rounded-full">
|
|
426
|
-
Nên bắt đầu ở đây
|
|
427
|
-
</div>
|
|
428
|
-
<div className="font-mono text-xs text-primary/70">
|
|
429
|
-
src/components/macro/
|
|
430
|
-
</div>
|
|
431
|
-
<h4 className="font-bold text-foreground text-base">
|
|
432
|
-
Macro — Khu vực an toàn
|
|
433
|
-
</h4>
|
|
434
|
-
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
435
|
-
Muốn tuỳ chỉnh? Bắt đầu từ đây nhé. Mỗi Macro là một khối độc lập — thêm footer cho DatePicker, giấu nút đóng của Dialog, v.v.{" "}
|
|
436
|
-
<strong className="text-foreground">
|
|
437
|
-
Cứ thoải mái vọc vạch
|
|
438
|
-
</strong>
|
|
439
|
-
, sửa cái nào thì chỉ ảnh hưởng cái đó thôi, chả lo "cháy nhà" hàng xóm.
|
|
440
|
-
</p>
|
|
441
|
-
</div>
|
|
442
|
-
|
|
443
|
-
{/* MICRO — CAUTION */}
|
|
444
|
-
<div className="p-5 rounded-2xl border border-warning/40 bg-warning/5 space-y-3 relative">
|
|
445
|
-
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-warning bg-warning/10 px-2 py-0.5 rounded-full">
|
|
446
|
-
Cẩn thận
|
|
447
|
-
</div>
|
|
448
|
-
<div className="font-mono text-xs text-warning/70">
|
|
449
|
-
src/components/micro/
|
|
450
|
-
</div>
|
|
451
|
-
<h4 className="font-bold text-foreground text-base">
|
|
452
|
-
Micro — Lãnh địa cốt lõi
|
|
453
|
-
</h4>
|
|
454
|
-
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
455
|
-
Mọi thứ đều xây từ đây. Sửa cái padding của Button hay animation của Tooltip thì{" "}
|
|
456
|
-
<strong className="text-foreground">
|
|
457
|
-
nguyên dàn app sẽ ăn theo
|
|
458
|
-
</strong>
|
|
459
|
-
. Cân nhắc kỹ chút trước khi gõ phím nhé, "sai một ly đi một dặm" đấy!
|
|
460
|
-
</p>
|
|
461
|
-
</div>
|
|
462
|
-
|
|
463
|
-
{/* CSS — HIGHEST IMPACT */}
|
|
464
|
-
<div className="p-5 rounded-2xl border border-destructive/30 bg-destructive/5 space-y-3 relative">
|
|
465
|
-
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-destructive bg-destructive/10 px-2 py-0.5 rounded-full">
|
|
466
|
-
Ảnh hưởng toàn cục
|
|
467
|
-
</div>
|
|
468
|
-
<div className="font-mono text-xs text-destructive/60">
|
|
469
|
-
src/index.css
|
|
470
|
-
</div>
|
|
471
|
-
<h4 className="font-bold text-foreground text-base">
|
|
472
|
-
CSS Token — Nút bấm hạt nhân
|
|
473
|
-
</h4>
|
|
474
|
-
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
475
|
-
Nơi nắm trùm về màu sắc, font, độ bo góc. Đổi một biến ở đây là{" "}
|
|
476
|
-
<strong className="text-foreground">
|
|
477
|
-
giao diện lột xác toàn tập
|
|
478
|
-
</strong>
|
|
479
|
-
. Rất đã khi cần thay áo mới (rebrand), nhưng tuyệt đối đừng dùng để vá lỗi vặt.
|
|
480
|
-
</p>
|
|
481
|
-
</div>
|
|
482
|
-
|
|
483
|
-
{/* BLOCKS — FLEXIBLE COMPOSITION */}
|
|
484
|
-
<div className="p-5 rounded-2xl border border-info/40 bg-info/5 space-y-3 relative">
|
|
485
|
-
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-info bg-info/10 px-2 py-0.5 rounded-full">
|
|
486
|
-
Lắp ghép linh hoạt
|
|
487
|
-
</div>
|
|
488
|
-
<div className="font-mono text-xs text-info/70">
|
|
489
|
-
src/blocks/
|
|
490
|
-
</div>
|
|
491
|
-
<h4 className="font-bold text-foreground text-base">
|
|
492
|
-
Blocks — Sân chơi tự do
|
|
493
|
-
</h4>
|
|
494
|
-
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
495
|
-
Chẳng có quy tắc nào ép bạn phải dùng 100% Micro hay Macro.
|
|
496
|
-
Layout quen thuộc thì <strong className="text-foreground">lấy Macro ra xài cho lẹ</strong>.
|
|
497
|
-
Gặp thiết kế dị biệt thì <strong className="text-foreground">mở Micro ra tự xếp hình</strong>.
|
|
498
|
-
Linh hoạt lên, code sao cho bản thân thấy sướng là được!
|
|
499
|
-
</p>
|
|
500
|
-
</div>
|
|
501
|
-
</div>
|
|
502
|
-
</div>
|
|
503
|
-
</div>
|
|
504
|
-
|
|
505
|
-
<div className="columns-1 md:columns-2 gap-6">
|
|
506
|
-
{/* Micro/Macro (Spans 2 columns) */}
|
|
507
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col justify-between group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
508
|
-
<div className="absolute -top-10 -right-10 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
509
|
-
<BlocksIcon className="w-80 h-80" />
|
|
510
|
-
</div>
|
|
511
|
-
<div className="relative z-10 space-y-4 mb-10">
|
|
512
|
-
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
513
|
-
Luật chơi Micro/Macro
|
|
514
|
-
</h3>
|
|
515
|
-
<p className="text-muted-foreground max-w-lg text-lg leading-relaxed">
|
|
516
|
-
Micro chỉ là những mảnh lego thuần túy — đẹp nhưng vô tri. Macro mới là người chỉ huy — sắp xếp các mảnh lego thành giao diện hoàn chỉnh.
|
|
517
|
-
<strong className="text-foreground block mt-2">
|
|
518
|
-
Micro không bao giờ được phép tự tiện lo chuyện layout (margin, width). Việc đó là của Macro!
|
|
519
|
-
</strong>
|
|
520
|
-
</p>
|
|
521
|
-
</div>
|
|
522
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
523
|
-
<CodeBlock type="success" title="Đúng — Để Macro lo layout:">
|
|
524
|
-
<span className="text-success/80">
|
|
525
|
-
{"/* Macro biết con mình là gì → gắn class chính xác */"}
|
|
526
|
-
</span>
|
|
527
|
-
<br />
|
|
528
|
-
<span className="text-foreground">{"<AlertDialogFooter>"}</span>
|
|
529
|
-
<br />
|
|
530
|
-
<span className="pl-4">
|
|
531
|
-
{'<Button variant="ghost">Trợ giúp</Button>'}
|
|
532
|
-
</span>
|
|
533
|
-
<br />
|
|
534
|
-
<span className="pl-4 text-success font-bold">
|
|
535
|
-
{'<Button className="ml-auto">Xác nhận</Button>'}
|
|
536
|
-
</span>
|
|
537
|
-
<br />
|
|
538
|
-
<span className="text-foreground">
|
|
539
|
-
{"</AlertDialogFooter>"}
|
|
540
|
-
</span>
|
|
541
|
-
</CodeBlock>
|
|
542
|
-
|
|
543
|
-
<CodeBlock type="destructive" title="Sai — Micro tự đoán layout:">
|
|
544
|
-
<span className="text-destructive/80">
|
|
545
|
-
{"/* Micro không biết con mình là gì → phải đoán bằng CSS */"}
|
|
546
|
-
</span>
|
|
547
|
-
<br />
|
|
548
|
-
<span className="text-foreground">{"<AlertDialogFooter"}</span>
|
|
549
|
-
<br />
|
|
550
|
-
<span className="pl-4 text-destructive font-bold line-through">
|
|
551
|
-
{'className="[&>*:last-child]:ml-auto"'}
|
|
552
|
-
</span>
|
|
553
|
-
<br />
|
|
554
|
-
<span className="text-foreground">{">"}</span>
|
|
555
|
-
<br />
|
|
556
|
-
<span className="pl-4">{"{children}"}</span>
|
|
557
|
-
<br />
|
|
558
|
-
<span className="text-foreground">
|
|
559
|
-
{"</AlertDialogFooter>"}
|
|
560
|
-
</span>
|
|
561
|
-
</CodeBlock>
|
|
562
|
-
</div>
|
|
563
|
-
</div>
|
|
564
|
-
|
|
565
|
-
{/* Style Encapsulation */}
|
|
566
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
567
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
568
|
-
<ShieldCheckIcon className="w-56 h-56" />
|
|
569
|
-
</div>
|
|
570
|
-
<div className="relative z-10 space-y-4">
|
|
571
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
572
|
-
Style Encapsulation
|
|
573
|
-
</h3>
|
|
574
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
575
|
-
Style của mỗi component không rò rỉ ra ngoài. Muốn tuỳ chỉnh thì
|
|
576
|
-
dùng <code>data-slot</code> — contract rõ ràng, có sẵn.{" "}
|
|
577
|
-
<strong className="text-foreground">
|
|
578
|
-
Refactor bên trong mà không ảnh hưởng bên ngoài.
|
|
579
|
-
</strong>
|
|
580
|
-
</p>
|
|
581
|
-
</div>
|
|
582
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
583
|
-
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-xs font-mono shadow-sm flex items-center">
|
|
584
|
-
<span className="text-destructive font-bold mr-3 text-lg">
|
|
585
|
-
❌
|
|
586
|
-
</span>
|
|
587
|
-
<span className="opacity-80 line-through">
|
|
588
|
-
{"[&>div>span]:color"}
|
|
589
|
-
</span>
|
|
590
|
-
</div>
|
|
591
|
-
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-xs font-mono shadow-sm flex items-center">
|
|
592
|
-
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
593
|
-
<span className="text-foreground font-medium">
|
|
594
|
-
data-[slot=icon]:color
|
|
595
|
-
</span>
|
|
596
|
-
</div>
|
|
597
|
-
</div>
|
|
598
|
-
</div>
|
|
599
|
-
|
|
600
|
-
{/* Orthogonal Styling (Spans 2 columns) */}
|
|
601
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
602
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
603
|
-
<SlidersHorizontalIcon className="w-80 h-80" />
|
|
604
|
-
</div>
|
|
605
|
-
<div className="relative z-10 space-y-4">
|
|
606
|
-
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
607
|
-
Variant × Color
|
|
608
|
-
</h3>
|
|
609
|
-
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
610
|
-
Variant (solid, outline, ghost...) và Color (primary,
|
|
611
|
-
destructive...) là hai trục độc lập. Kết hợp tự do mà class
|
|
612
|
-
không phình ra.
|
|
613
|
-
</p>
|
|
614
|
-
</div>
|
|
615
|
-
<div className="relative z-10 mt-auto pt-8 grid sm:grid-cols-2 gap-4">
|
|
616
|
-
<div className="p-3 sm:p-5 rounded-2xl border border-border bg-background/60 backdrop-blur-md shadow-sm hover:shadow-md transition-shadow">
|
|
617
|
-
<strong className="block text-foreground text-base mb-2 flex items-center gap-2">
|
|
618
|
-
<BoxIcon className="size-4 text-muted-foreground" /> Trục
|
|
619
|
-
Variant
|
|
620
|
-
</strong>
|
|
621
|
-
<span className="text-sm text-muted-foreground leading-relaxed">
|
|
622
|
-
solid, outline, ghost, soft. Quyết định cách component trông
|
|
623
|
-
như thế nào.
|
|
624
|
-
</span>
|
|
625
|
-
</div>
|
|
626
|
-
<div className="p-3 sm:p-5 rounded-2xl border border-border bg-background/60 backdrop-blur-md shadow-sm hover:shadow-md transition-shadow">
|
|
627
|
-
<strong className="block text-foreground text-base mb-2 flex items-center gap-2">
|
|
628
|
-
<PaintbrushIcon className="size-4 text-muted-foreground" />{" "}
|
|
629
|
-
Trục Color
|
|
630
|
-
</strong>
|
|
631
|
-
<span className="text-sm text-muted-foreground leading-relaxed">
|
|
632
|
-
primary, secondary, destructive. Quyết định bảng màu của
|
|
633
|
-
component.
|
|
634
|
-
</span>
|
|
635
|
-
</div>
|
|
636
|
-
</div>
|
|
637
|
-
</div>
|
|
638
|
-
|
|
639
|
-
{/* Zero-Prop Defaults */}
|
|
640
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
641
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
642
|
-
<ComponentIcon className="w-80 h-80" />
|
|
643
|
-
</div>
|
|
644
|
-
<div className="relative z-10 space-y-4">
|
|
645
|
-
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
646
|
-
Zero-prop Defaults
|
|
647
|
-
</h3>
|
|
648
|
-
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
649
|
-
Đặt component vào mà không truyền prop nào — vẫn chạy đẹp, vẫn
|
|
650
|
-
đúng behavior.{" "}
|
|
651
|
-
<strong className="text-foreground">
|
|
652
|
-
Không phải tra docs mỗi lần dùng.
|
|
653
|
-
</strong>
|
|
654
|
-
</p>
|
|
655
|
-
</div>
|
|
656
|
-
<div className="relative z-10 mt-auto pt-8 flex flex-col gap-4">
|
|
657
|
-
<div className="flex items-center justify-between gap-4 p-4 rounded-xl border border-success/20 bg-success/5 shadow-sm">
|
|
658
|
-
<Button>Click Me</Button>
|
|
659
|
-
<span className="text-[11px] sm:text-xs font-mono text-success font-medium">
|
|
660
|
-
{"<Button>Click Me</Button>"}
|
|
661
|
-
</span>
|
|
662
|
-
</div>
|
|
663
|
-
<div className="flex items-center justify-between gap-4 p-4 rounded-xl border border-destructive/20 bg-destructive/5 shadow-sm opacity-60">
|
|
664
|
-
<Button size="md" color="primary">
|
|
665
|
-
Click Me
|
|
666
|
-
</Button>
|
|
667
|
-
<span className="text-[11px] sm:text-xs font-mono text-destructive font-medium line-through">
|
|
668
|
-
{'<Button size="md" color="primary">...'}
|
|
669
|
-
</span>
|
|
670
|
-
</div>
|
|
671
|
-
</div>
|
|
672
|
-
</div>
|
|
673
|
-
|
|
674
|
-
{/* Headless Behavior Layer */}
|
|
675
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
676
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
677
|
-
<LayersIcon className="w-56 h-56" />
|
|
678
|
-
</div>
|
|
679
|
-
<div className="relative z-10 space-y-4">
|
|
680
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
681
|
-
Headless + Style
|
|
682
|
-
</h3>
|
|
683
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
684
|
-
Keyboard, focus, ARIA — Base UI lo hết. Micro component chỉ thêm
|
|
685
|
-
lớp style lên trên, không tự viết logic tương tác.{" "}
|
|
686
|
-
<strong className="text-foreground">
|
|
687
|
-
Behavior đúng sẵn, không cần test lại.
|
|
688
|
-
</strong>
|
|
689
|
-
</p>
|
|
690
|
-
</div>
|
|
691
|
-
<div className="relative z-10 mt-auto pt-8">
|
|
692
|
-
<div className="p-4 rounded-xl bg-foreground/5 border border-border/50 text-[11px] sm:text-xs font-mono shadow-inner space-y-1">
|
|
693
|
-
<div className="text-muted-foreground">
|
|
694
|
-
// Micro = Headless + Style
|
|
695
|
-
</div>
|
|
696
|
-
<div>
|
|
697
|
-
<span className="text-primary">{"<Base UI Select>"}</span>
|
|
698
|
-
<span className="text-muted-foreground"> ← behavior</span>
|
|
699
|
-
</div>
|
|
700
|
-
<div className="pl-4">
|
|
701
|
-
<span className="text-success">{"<SelectTrigger>"}</span>
|
|
702
|
-
<span className="text-muted-foreground"> ← style only</span>
|
|
703
|
-
</div>
|
|
704
|
-
</div>
|
|
705
|
-
</div>
|
|
706
|
-
</div>
|
|
707
|
-
{/* CSS Token Architecture */}
|
|
708
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
709
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
710
|
-
<PaletteIcon className="w-56 h-56" />
|
|
711
|
-
</div>
|
|
712
|
-
<div className="relative z-10 space-y-4">
|
|
713
|
-
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
714
|
-
CSS Token
|
|
715
|
-
</h3>
|
|
716
|
-
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
717
|
-
Không component nào hardcode màu hay spacing. Tất cả đều tham
|
|
718
|
-
chiếu từ hệ thống token chung.{" "}
|
|
719
|
-
<strong className="text-foreground">
|
|
720
|
-
Đổi một token — cả app cập nhật.
|
|
721
|
-
</strong>
|
|
722
|
-
</p>
|
|
723
|
-
</div>
|
|
724
|
-
<div className="relative z-10 mt-auto pt-8 grid sm:grid-cols-2 gap-4">
|
|
725
|
-
<div className="p-4 rounded-xl border border-success/20 bg-success/5 shadow-sm">
|
|
726
|
-
<div className="text-success font-semibold mb-2 text-sm">
|
|
727
|
-
✅ Token
|
|
728
|
-
</div>
|
|
729
|
-
<div className="text-[11px] font-mono text-success/80">
|
|
730
|
-
oklch(var(--primary))
|
|
731
|
-
</div>
|
|
732
|
-
</div>
|
|
733
|
-
<div className="p-4 rounded-xl border border-destructive/20 bg-destructive/5 shadow-sm opacity-60">
|
|
734
|
-
<div className="text-destructive font-semibold mb-2 text-sm">
|
|
735
|
-
❌ Hardcode
|
|
736
|
-
</div>
|
|
737
|
-
<div className="text-[11px] font-mono text-destructive/80 line-through">
|
|
738
|
-
#2563eb
|
|
739
|
-
</div>
|
|
740
|
-
</div>
|
|
741
|
-
</div>
|
|
742
|
-
</div>
|
|
743
|
-
|
|
744
|
-
{/* Strict Polymorphism */}
|
|
745
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
746
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
747
|
-
<CopyIcon className="w-56 h-56" />
|
|
748
|
-
</div>
|
|
749
|
-
<div className="relative z-10 space-y-4">
|
|
750
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
751
|
-
Polymorphism
|
|
752
|
-
</h3>
|
|
753
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
754
|
-
Dùng <code>render</code> prop để đổi thẻ HTML root — ví dụ biến
|
|
755
|
-
Button thành Link. Không cần prop <code>as</code> hay tạo
|
|
756
|
-
wrapper lồng nhau.
|
|
757
|
-
</p>
|
|
758
|
-
</div>
|
|
759
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
760
|
-
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
761
|
-
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
762
|
-
<span className="text-success/90">
|
|
763
|
-
<Button render={<Link/>}>
|
|
764
|
-
</span>
|
|
765
|
-
</div>
|
|
766
|
-
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
767
|
-
<span className="text-destructive font-bold mr-3 text-lg">
|
|
768
|
-
❌
|
|
769
|
-
</span>
|
|
770
|
-
<span className="text-destructive/80 line-through">
|
|
771
|
-
<Button as="a" href="/">
|
|
772
|
-
</span>
|
|
773
|
-
</div>
|
|
774
|
-
</div>
|
|
775
|
-
</div>
|
|
776
|
-
|
|
777
|
-
{/* Dumb Primitives */}
|
|
778
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
779
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
780
|
-
<BoxIcon className="w-56 h-56" />
|
|
781
|
-
</div>
|
|
782
|
-
<div className="relative z-10 space-y-4">
|
|
783
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
784
|
-
Stateless Primitive
|
|
785
|
-
</h3>
|
|
786
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
787
|
-
Micro component không chứa <code>useState</code> hay{" "}
|
|
788
|
-
<code>useEffect</code>. State nằm ở Headless UI hoặc Macro.{" "}
|
|
789
|
-
<strong className="text-foreground">
|
|
790
|
-
Component càng đơn giản, càng ít bug.
|
|
791
|
-
</strong>
|
|
792
|
-
</p>
|
|
793
|
-
</div>
|
|
794
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
795
|
-
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
796
|
-
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
797
|
-
<span className="text-success/90">
|
|
798
|
-
{"function Button({ ...props })"}
|
|
799
|
-
</span>
|
|
800
|
-
</div>
|
|
801
|
-
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
802
|
-
<span className="text-destructive font-bold mr-3 text-lg">
|
|
803
|
-
❌
|
|
804
|
-
</span>
|
|
805
|
-
<span className="text-destructive/80 line-through">
|
|
806
|
-
{"const [open, setOpen] = useState()"}
|
|
807
|
-
</span>
|
|
808
|
-
</div>
|
|
809
|
-
</div>
|
|
810
|
-
</div>
|
|
811
|
-
|
|
812
|
-
{/* Accessibility First */}
|
|
813
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
814
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
815
|
-
<AccessibilityIcon className="w-56 h-56" />
|
|
816
|
-
</div>
|
|
817
|
-
<div className="relative z-10 space-y-4">
|
|
818
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
819
|
-
Accessibility
|
|
820
|
-
</h3>
|
|
821
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
822
|
-
Semantic HTML, <code>aria-describedby</code> cho form, icon
|
|
823
|
-
trang trí tự ẩn khỏi screen reader.{" "}
|
|
824
|
-
<strong className="text-foreground">
|
|
825
|
-
Chuẩn WCAG — không cần nghĩ thêm.
|
|
826
|
-
</strong>
|
|
827
|
-
</p>
|
|
828
|
-
</div>
|
|
829
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
830
|
-
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
831
|
-
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
832
|
-
<span className="text-success/90">
|
|
833
|
-
<svg aria-hidden="true" />
|
|
834
|
-
</span>
|
|
835
|
-
</div>
|
|
836
|
-
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
837
|
-
<span className="text-destructive font-bold mr-3 text-lg">
|
|
838
|
-
❌
|
|
839
|
-
</span>
|
|
840
|
-
<span className="text-destructive/80 line-through">
|
|
841
|
-
<div role="button">
|
|
842
|
-
</span>
|
|
843
|
-
</div>
|
|
844
|
-
</div>
|
|
845
|
-
</div>
|
|
846
|
-
|
|
847
|
-
{/* Explicit State Contract */}
|
|
848
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
849
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
850
|
-
<DatabaseIcon className="w-56 h-56" />
|
|
851
|
-
</div>
|
|
852
|
-
<div className="relative z-10 space-y-4">
|
|
853
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
854
|
-
Explicit State Contract
|
|
855
|
-
</h3>
|
|
856
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
857
|
-
Component công khai trạng thái qua <code>data-attributes</code>,
|
|
858
|
-
không phải qua imperative ref. Bạn style và animate trực tiếp
|
|
859
|
-
trên từng trạng thái, không cần JavaScript.{" "}
|
|
860
|
-
<strong className="text-foreground">
|
|
861
|
-
State là public API — tường minh và ổn định.
|
|
862
|
-
</strong>
|
|
863
|
-
</p>
|
|
864
|
-
</div>
|
|
865
|
-
<div className="relative z-10 mt-auto pt-8">
|
|
866
|
-
<div className="p-4 rounded-xl bg-foreground/5 border border-border/50 text-[11px] sm:text-xs font-mono shadow-inner space-y-2">
|
|
867
|
-
<div>
|
|
868
|
-
<span className="text-success">data-[state=open]</span>
|
|
869
|
-
<span className="text-muted-foreground">:rotate-180</span>
|
|
870
|
-
</div>
|
|
871
|
-
<div>
|
|
872
|
-
<span className="text-success">data-disabled</span>
|
|
873
|
-
<span className="text-muted-foreground">:opacity-50</span>
|
|
874
|
-
</div>
|
|
875
|
-
<div className="pt-1 border-t border-border/30">
|
|
876
|
-
<span className="text-destructive/60 line-through">
|
|
877
|
-
ref.current.isOpen
|
|
878
|
-
</span>
|
|
879
|
-
</div>
|
|
880
|
-
</div>
|
|
881
|
-
</div>
|
|
882
|
-
</div>
|
|
883
|
-
|
|
884
|
-
{/* 3-Layer Source Ownership */}
|
|
885
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
886
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
887
|
-
<SlidersHorizontalIcon className="w-56 h-56" />
|
|
888
|
-
</div>
|
|
889
|
-
<div className="relative z-10 space-y-4">
|
|
890
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
891
|
-
3-Layer Source Ownership
|
|
892
|
-
</h3>
|
|
893
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
894
|
-
Source được phân tầng: <code>micro/</code> (primitive không có
|
|
895
|
-
layout cứng nhắc), <code>macro/</code> (preset lắp ráp có chủ
|
|
896
|
-
đích), <code>index.css</code> (token toàn hệ thống).{" "}
|
|
897
|
-
<strong className="text-foreground">
|
|
898
|
-
Sửa ở tầng nào chỉ ảnh hưởng đến tầng đó.
|
|
899
|
-
</strong>
|
|
900
|
-
</p>
|
|
901
|
-
</div>
|
|
902
|
-
<div className="relative z-10 mt-auto pt-6 space-y-2">
|
|
903
|
-
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
904
|
-
<span className="text-destructive font-bold">CSS</span>
|
|
905
|
-
<span className="text-muted-foreground">
|
|
906
|
-
index.css — token toàn cục
|
|
907
|
-
</span>
|
|
908
|
-
</div>
|
|
909
|
-
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
910
|
-
<span className="text-warning font-bold">Macro</span>
|
|
911
|
-
<span className="text-muted-foreground">
|
|
912
|
-
macro/ — preset lắp ráp
|
|
913
|
-
</span>
|
|
914
|
-
</div>
|
|
915
|
-
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
916
|
-
<span className="text-success font-bold">Micro</span>
|
|
917
|
-
<span className="text-muted-foreground">
|
|
918
|
-
micro/ — primitive thuần
|
|
919
|
-
</span>
|
|
920
|
-
</div>
|
|
921
|
-
</div>
|
|
922
|
-
</div>
|
|
923
|
-
|
|
924
|
-
{/* Pure Composition */}
|
|
925
|
-
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
926
|
-
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
927
|
-
<BlocksIcon className="w-56 h-56" />
|
|
928
|
-
</div>
|
|
929
|
-
<div className="relative z-10 space-y-4">
|
|
930
|
-
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
931
|
-
Pure Composition
|
|
932
|
-
</h3>
|
|
933
|
-
<p className="text-muted-foreground text-base leading-relaxed">
|
|
934
|
-
Design component theo dạng lắp ghép (ví dụ: Root, Trigger,
|
|
935
|
-
Content) thay vì ôm đồm nhận vào một mảng data rồi tự{" "}
|
|
936
|
-
<code>map()</code> bên trong.
|
|
937
|
-
</p>
|
|
938
|
-
</div>
|
|
939
|
-
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
940
|
-
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
941
|
-
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
942
|
-
<span className="text-success/90">
|
|
943
|
-
<Select>
|
|
944
|
-
<br />
|
|
945
|
-
<SelectTrigger/>
|
|
946
|
-
<br />
|
|
947
|
-
<SelectContent/>
|
|
948
|
-
<br />
|
|
949
|
-
</Select>
|
|
950
|
-
</span>
|
|
951
|
-
</div>
|
|
952
|
-
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
953
|
-
<span className="text-destructive font-bold mr-3 text-lg">
|
|
954
|
-
❌
|
|
955
|
-
</span>
|
|
956
|
-
<span className="text-destructive/80 line-through">
|
|
957
|
-
<Select items={[...]} />
|
|
958
|
-
</span>
|
|
959
|
-
</div>
|
|
960
|
-
</div>
|
|
961
|
-
</div>
|
|
962
|
-
</div>
|
|
963
|
-
</section>
|
|
964
|
-
|
|
965
|
-
{/* ✨ KILLER FEATURE: SCOPED THEME TUNNEL */}
|
|
966
|
-
<section className="container max-w-6xl mx-auto px-4 mb-16">
|
|
967
|
-
<div className="rounded-[2.5rem] border border-warning/30 bg-warning/5 p-10 md:p-16 shadow-xl relative overflow-hidden group">
|
|
968
|
-
<div className="absolute -top-10 -right-10 p-8 opacity-10 pointer-events-none group-hover:rotate-12 group-hover:scale-125 transition-all duration-1000 text-warning">
|
|
969
|
-
<SparklesIcon className="size-64 md:size-[400px]" />
|
|
970
|
-
</div>
|
|
971
|
-
|
|
972
|
-
<div className="relative z-10 max-w-3xl mb-14 space-y-5">
|
|
973
|
-
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight text-warning">
|
|
974
|
-
Scoped Theme Tunnel
|
|
975
|
-
</h3>
|
|
976
|
-
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
977
|
-
Dark section bên trong Light app? Dễ. Nhưng khi Tooltip hay Dialog
|
|
978
|
-
render nổi qua cơ chế Portaling — chúng thoát khỏi DOM tree hiện tại và{" "}
|
|
979
|
-
<strong className="text-foreground">mất theme</strong>. Hầu hết
|
|
980
|
-
thư viện bỏ cuộc ở đây.
|
|
981
|
-
</p>
|
|
982
|
-
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
983
|
-
Nhưng hiện tại thư viện đã áp dụng <strong>Zero-Portal API</strong> (kể từ v0.2.20).
|
|
984
|
-
Bạn không cần phải import <code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">ThemeWrapper</code> hay <code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">*Portal</code> nữa.
|
|
985
|
-
Toàn bộ logic portaling và ThemeWrapper đã được nhúng sẵn vào trong các <code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">*Content</code> components (VD: <code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">DialogContent</code>, <code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">TooltipContent</code>).
|
|
986
|
-
</p>
|
|
987
|
-
</div>
|
|
988
|
-
|
|
989
|
-
<div className="relative z-10 grid sm:grid-cols-2 gap-6 max-w-3xl">
|
|
990
|
-
<div className="p-6 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex flex-col gap-2">
|
|
991
|
-
<div className="text-success font-semibold text-lg flex items-center gap-2">
|
|
992
|
-
✅ gladvn
|
|
993
|
-
</div>
|
|
994
|
-
<p className="text-success/80 text-sm leading-relaxed">
|
|
995
|
-
Tooltip, Dialog trong dark section luôn đúng màu — kể cả khi
|
|
996
|
-
Portal render ra{" "}
|
|
997
|
-
<code className="opacity-80">document.body</code>.
|
|
998
|
-
</p>
|
|
999
|
-
</div>
|
|
1000
|
-
<div className="p-6 rounded-2xl border border-destructive/30 bg-destructive/10 shadow-sm opacity-80 flex flex-col gap-2">
|
|
1001
|
-
<div className="text-destructive font-semibold text-lg flex items-center gap-2">
|
|
1002
|
-
❌ Thư viện khác
|
|
1003
|
-
</div>
|
|
1004
|
-
<p className="text-destructive/80 text-sm leading-relaxed">
|
|
1005
|
-
Tooltip, Dialog "trắng lạc quẻ" — theme bị mất khi vượt Portal.
|
|
1006
|
-
</p>
|
|
1007
|
-
</div>
|
|
1008
|
-
</div>
|
|
1009
|
-
|
|
1010
|
-
<div className="relative z-10 mt-10">
|
|
1011
|
-
<Button
|
|
1012
|
-
render={<a href="/dialog" />}
|
|
1013
|
-
nativeButton={false}
|
|
1014
|
-
variant="outline"
|
|
1015
|
-
color="warning"
|
|
1016
|
-
className="gap-2 font-bold px-6 py-5 rounded-xl border-warning/30 bg-warning/10 hover:bg-warning/20 shadow-sm"
|
|
1017
|
-
>
|
|
1018
|
-
Xem demo thực tế
|
|
1019
|
-
<ArrowRightIcon className="size-4" />
|
|
1020
|
-
</Button>
|
|
1021
|
-
</div>
|
|
1022
|
-
</div>
|
|
1023
|
-
</section>
|
|
1024
|
-
|
|
1025
|
-
{/* 🎨 OKLCH COLOR TOKENS */}
|
|
1026
|
-
<section className="container max-w-6xl mx-auto px-4">
|
|
1027
|
-
<div className="rounded-[2.5rem] border border-border bg-card/30 p-10 md:p-16 shadow-xl relative overflow-hidden group">
|
|
1028
|
-
<div className="absolute -top-10 -right-10 p-8 opacity-5 pointer-events-none group-hover:rotate-12 group-hover:scale-125 transition-all duration-1000">
|
|
1029
|
-
<PaletteIcon className="size-64 md:size-[400px]" />
|
|
1030
|
-
</div>
|
|
1031
|
-
|
|
1032
|
-
<div className="relative z-10 max-w-3xl mb-14 space-y-5">
|
|
1033
|
-
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
1034
|
-
Không gian màu OKLCH
|
|
1035
|
-
</h3>
|
|
1036
|
-
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
1037
|
-
Mọi token màu sắc được tính trên không gian OKLCH — chuyển sắc
|
|
1038
|
-
mượt, tương phản đạt WCAG AA/AAA trên mọi theme mà không cần định
|
|
1039
|
-
nghĩa thủ công từng dải màu.
|
|
1040
|
-
</p>
|
|
1041
|
-
</div>
|
|
1042
|
-
|
|
1043
|
-
<div className="relative z-10 flex flex-wrap gap-6 md:gap-8 justify-center">
|
|
1044
|
-
{COLORS.map((c, i) => (
|
|
1045
|
-
<div
|
|
1046
|
-
key={c}
|
|
1047
|
-
className="animate-fade-up"
|
|
1048
|
-
style={{
|
|
1049
|
-
animationDelay: `${i * 50}ms`,
|
|
1050
|
-
animationFillMode: "both" }}
|
|
1051
|
-
>
|
|
1052
|
-
<ColorSwatch color={c} />
|
|
1053
|
-
</div>
|
|
1054
|
-
))}
|
|
1055
|
-
</div>
|
|
1056
|
-
</div>
|
|
1057
|
-
</section>
|
|
1058
|
-
|
|
1059
|
-
{/* 🤝 CONTRIBUTORS */}
|
|
1060
|
-
<section className="container max-w-6xl mx-auto px-4 mb-24">
|
|
1061
|
-
<div className="flex flex-col items-center text-center space-y-8">
|
|
1062
|
-
<div className="space-y-4 max-w-2xl">
|
|
1063
|
-
<h2 className="text-3xl font-extrabold tracking-tight">
|
|
1064
|
-
Contributors
|
|
1065
|
-
</h2>
|
|
1066
|
-
</div>
|
|
1067
|
-
|
|
1068
|
-
<div className="flex flex-wrap justify-center gap-6">
|
|
1069
|
-
{[
|
|
1070
|
-
{
|
|
1071
|
-
name: "Ý Le",
|
|
1072
|
-
role: "Creator & Maintainer",
|
|
1073
|
-
avatar: "https://github.com/duongacy.png",
|
|
1074
|
-
url: "https://github.com/duongacy" },
|
|
1075
|
-
].map((user) => (
|
|
1076
|
-
<a
|
|
1077
|
-
key={user.name}
|
|
1078
|
-
href={user.url}
|
|
1079
|
-
target="_blank"
|
|
1080
|
-
rel="noreferrer"
|
|
1081
|
-
className="group flex flex-col items-center gap-3 p-4 rounded-2xl hover:bg-muted/50 transition-colors"
|
|
1082
|
-
>
|
|
1083
|
-
<Avatar className="size-16 border-2 border-transparent group-hover:border-primary/20 transition-all duration-300 group-hover:scale-105">
|
|
1084
|
-
<AvatarImage src={user.avatar} alt={user.name} />
|
|
1085
|
-
<AvatarFallback className="text-lg bg-primary/5 text-primary">
|
|
1086
|
-
{user.name.substring(0, 2).toUpperCase()}
|
|
1087
|
-
</AvatarFallback>
|
|
1088
|
-
</Avatar>
|
|
1089
|
-
<div className="text-center">
|
|
1090
|
-
<div className="font-semibold text-sm group-hover:text-primary transition-colors">
|
|
1091
|
-
{user.name}
|
|
1092
|
-
</div>
|
|
1093
|
-
<div className="text-xs text-muted-foreground mt-0.5">
|
|
1094
|
-
{user.role}
|
|
1095
|
-
</div>
|
|
1096
|
-
</div>
|
|
1097
|
-
</a>
|
|
1098
|
-
))}
|
|
1099
|
-
</div>
|
|
1100
|
-
|
|
1101
|
-
<Button
|
|
1102
|
-
variant="outline"
|
|
1103
|
-
className="mt-4 rounded-full"
|
|
1104
|
-
render={
|
|
1105
|
-
<a
|
|
1106
|
-
href="https://github.com/duongacy/gladvn"
|
|
1107
|
-
target="_blank"
|
|
1108
|
-
rel="noreferrer"
|
|
1109
|
-
/>
|
|
1110
|
-
}
|
|
1111
|
-
nativeButton={false}
|
|
1112
|
-
>
|
|
1113
|
-
Đóng góp cùng chúng tôi
|
|
1114
|
-
</Button>
|
|
1115
|
-
</div>
|
|
1116
|
-
</section>
|
|
1117
|
-
|
|
1118
|
-
{/* 🚀 FINAL CTA */}
|
|
1119
|
-
<section className="container max-w-6xl mx-auto px-4">
|
|
1120
|
-
<div className="rounded-[2.5rem] border-2 border-primary/40 bg-gradient-to-br from-primary/10 via-background to-info/5 p-10 md:p-16 shadow-2xl shadow-primary/5 text-center relative overflow-hidden">
|
|
1121
|
-
<div className="absolute inset-0 bg-[radial-gradient(ellipse_60%_60%_at_50%_0%,rgba(var(--primary-rgb),0.15),transparent)] pointer-events-none" />
|
|
1122
|
-
<div className="relative z-10 space-y-6 max-w-2xl mx-auto">
|
|
1123
|
-
<h2 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
1124
|
-
30 giây là có đồ chơi.
|
|
1125
|
-
</h2>
|
|
1126
|
-
<p className="text-muted-foreground text-lg leading-relaxed">
|
|
1127
|
-
Quẳng hết code vào{" "}
|
|
1128
|
-
<code className="text-sm bg-primary/20 text-primary px-1.5 py-0.5 rounded">
|
|
1129
|
-
src/
|
|
1130
|
-
</code>{" "}
|
|
1131
|
-
rồi xài thôi. Không config rườm rà nhức đầu làm gì.
|
|
1132
|
-
</p>
|
|
1133
|
-
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 pt-2">
|
|
1134
|
-
<button
|
|
1135
|
-
onClick={handleCopy}
|
|
1136
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 px-8 py-4 rounded-2xl font-mono text-sm shadow-lg shadow-primary/20 flex items-center gap-4 cursor-pointer transition-all hover:scale-105 active:scale-95"
|
|
1137
|
-
>
|
|
1138
|
-
<span className="font-bold opacity-70">~</span>
|
|
1139
|
-
<span>npx gladvn init</span>
|
|
1140
|
-
<div className="ml-2">
|
|
1141
|
-
{copied ? (
|
|
1142
|
-
<CheckIcon className="size-4" />
|
|
1143
|
-
) : (
|
|
1144
|
-
<CopyIcon className="size-4" />
|
|
1145
|
-
)}
|
|
1146
|
-
</div>
|
|
1147
|
-
</button>
|
|
1148
|
-
<Button
|
|
1149
|
-
render={
|
|
1150
|
-
<a
|
|
1151
|
-
href="https://github.com/duongacy/gladvn"
|
|
1152
|
-
target="_blank"
|
|
1153
|
-
rel="noreferrer"
|
|
1154
|
-
/>
|
|
1155
|
-
}
|
|
1156
|
-
nativeButton={false}
|
|
1157
|
-
variant="ghost"
|
|
1158
|
-
className="text-muted-foreground hover:text-foreground"
|
|
1159
|
-
>
|
|
1160
|
-
Xem trên GitHub
|
|
1161
|
-
<ArrowRightIcon className="size-4 ml-1" />
|
|
1162
|
-
</Button>
|
|
1163
|
-
</div>
|
|
1164
|
-
<p className="text-xs text-muted-foreground pt-2">
|
|
1165
|
-
Tương thích với npm, yarn, pnpm và bun. Hỗ trợ React 18+.
|
|
1166
|
-
</p>
|
|
1167
|
-
</div>
|
|
1168
|
-
</div>
|
|
20
|
+
<ArchitectureSection />
|
|
21
|
+
|
|
22
|
+
<FeatureGridSection />
|
|
1169
23
|
</section>
|
|
24
|
+
|
|
25
|
+
<ColorPaletteSection />
|
|
26
|
+
|
|
27
|
+
<FooterCTA />
|
|
1170
28
|
</div>
|
|
1171
29
|
);
|
|
1172
30
|
}
|