@mandujs/mcp 0.13.0 → 0.16.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.
- package/README.md +6 -7
- package/package.json +3 -2
- package/src/adapters/index.ts +20 -20
- package/src/adapters/monitor-adapter.ts +100 -100
- package/src/adapters/tool-adapter.ts +88 -88
- package/src/executor/error-handler.ts +250 -250
- package/src/executor/index.ts +22 -22
- package/src/executor/tool-executor.ts +148 -148
- package/src/hooks/config-watcher.ts +174 -174
- package/src/hooks/index.ts +23 -23
- package/src/hooks/mcp-hooks.ts +227 -227
- package/src/logging/index.ts +15 -15
- package/src/logging/mcp-transport.ts +134 -134
- package/src/registry/index.ts +13 -13
- package/src/registry/mcp-tool-registry.ts +298 -298
- package/src/resources/skills/guides.ts +1136 -1136
- package/src/resources/skills/index.ts +12 -12
- package/src/resources/skills/loader.ts +218 -218
- package/src/resources/skills/mandu-composition/SKILL.md +91 -91
- package/src/resources/skills/mandu-composition/metadata.json +13 -13
- package/src/resources/skills/mandu-composition/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-composition/rules/_template.md +77 -77
- package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +146 -146
- package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +164 -164
- package/src/resources/skills/mandu-composition/rules/comp-island-event.md +161 -161
- package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +167 -167
- package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +149 -149
- package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +148 -148
- package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +150 -150
- package/src/resources/skills/mandu-deployment/SKILL.md +92 -92
- package/src/resources/skills/mandu-deployment/_sections.md +41 -41
- package/src/resources/skills/mandu-deployment/_template.md +38 -38
- package/src/resources/skills/mandu-deployment/metadata.json +13 -13
- package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +109 -109
- package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +115 -115
- package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +219 -219
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +150 -150
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +223 -223
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +152 -152
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +179 -179
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-supabase.md +323 -323
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +140 -140
- package/src/resources/skills/mandu-fs-routes/SKILL.md +82 -82
- package/src/resources/skills/mandu-fs-routes/metadata.json +12 -12
- package/src/resources/skills/mandu-fs-routes/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-fs-routes/rules/_template.md +69 -69
- package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +65 -65
- package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +93 -93
- package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +55 -55
- package/src/resources/skills/mandu-guard/SKILL.md +129 -129
- package/src/resources/skills/mandu-guard/metadata.json +12 -12
- package/src/resources/skills/mandu-guard/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-guard/rules/_template.md +82 -82
- package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +100 -100
- package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +76 -76
- package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +81 -81
- package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +80 -80
- package/src/resources/skills/mandu-hydration/SKILL.md +91 -91
- package/src/resources/skills/mandu-hydration/metadata.json +12 -12
- package/src/resources/skills/mandu-hydration/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-hydration/rules/_template.md +72 -72
- package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +109 -109
- package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +55 -55
- package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +113 -113
- package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +68 -68
- package/src/resources/skills/mandu-performance/SKILL.md +85 -85
- package/src/resources/skills/mandu-performance/metadata.json +14 -14
- package/src/resources/skills/mandu-performance/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-performance/rules/_template.md +64 -64
- package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +103 -103
- package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +95 -95
- package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +124 -124
- package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +125 -125
- package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +80 -80
- package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +145 -145
- package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +98 -98
- package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +154 -154
- package/src/resources/skills/mandu-security/SKILL.md +87 -87
- package/src/resources/skills/mandu-security/metadata.json +13 -13
- package/src/resources/skills/mandu-security/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-security/rules/_template.md +74 -74
- package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +127 -127
- package/src/resources/skills/mandu-security/rules/sec-env-management.md +133 -133
- package/src/resources/skills/mandu-security/rules/sec-input-validate.md +148 -148
- package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +146 -146
- package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +138 -138
- package/src/resources/skills/mandu-slot/SKILL.md +85 -85
- package/src/resources/skills/mandu-slot/metadata.json +12 -12
- package/src/resources/skills/mandu-slot/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-slot/rules/_template.md +63 -63
- package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +38 -38
- package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +56 -56
- package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +59 -59
- package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +64 -64
- package/src/resources/skills/mandu-styling/SKILL.md +154 -154
- package/src/resources/skills/mandu-styling/_sections.md +43 -43
- package/src/resources/skills/mandu-styling/_template.md +32 -32
- package/src/resources/skills/mandu-styling/metadata.json +15 -15
- package/src/resources/skills/mandu-styling/rules/style-component-compound.md +235 -235
- package/src/resources/skills/mandu-styling/rules/style-component-slots.md +255 -255
- package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +205 -205
- package/src/resources/skills/mandu-styling/rules/style-island-animations.md +272 -272
- package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +167 -167
- package/src/resources/skills/mandu-styling/rules/style-island-variants.md +221 -221
- package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +209 -209
- package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +192 -192
- package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +162 -162
- package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +164 -164
- package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +170 -170
- package/src/resources/skills/mandu-styling/rules/style-tailwind-v4-gotchas.md +179 -179
- package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +229 -229
- package/src/resources/skills/mandu-testing/SKILL.md +99 -99
- package/src/resources/skills/mandu-testing/metadata.json +13 -13
- package/src/resources/skills/mandu-testing/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-testing/rules/_template.md +65 -65
- package/src/resources/skills/mandu-testing/rules/test-component-island.md +195 -195
- package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +196 -196
- package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +219 -219
- package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +192 -192
- package/src/resources/skills/mandu-ui/SKILL.md +117 -117
- package/src/resources/skills/mandu-ui/_sections.md +23 -23
- package/src/resources/skills/mandu-ui/_template.md +32 -32
- package/src/resources/skills/mandu-ui/metadata.json +13 -13
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +232 -232
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +238 -238
- package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +259 -259
- package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +258 -258
- package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +213 -213
- package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +209 -209
- package/src/resources/skills/recipes.ts +932 -932
- package/src/tools/ate.ts +129 -0
- package/src/tools/index.ts +4 -1
- package/src/tools/project.ts +334 -334
- package/src/tools/runtime.ts +497 -497
- package/src/tools/seo.ts +417 -417
- package/src/utils/withWarnings.ts +83 -83
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: shadcn/ui Setup
|
|
3
|
-
impact: HIGH
|
|
4
|
-
impactDescription: Production-ready UI components with full customization
|
|
5
|
-
tags: ui, shadcn, setup, components
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## shadcn/ui Setup
|
|
9
|
-
|
|
10
|
-
**Impact: HIGH (Production-ready UI components with full customization)**
|
|
11
|
-
|
|
12
|
-
shadcn/ui를 Mandu 프로젝트에 설정하세요. 컴포넌트를 직접 소유하고 커스터마이징할 수 있습니다.
|
|
13
|
-
|
|
14
|
-
**초기화:**
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
bunx shadcn-ui@latest init
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**선택 옵션:**
|
|
21
|
-
```
|
|
22
|
-
✔ TypeScript: yes
|
|
23
|
-
✔ Style: Default (또는 New York)
|
|
24
|
-
✔ Base color: Slate
|
|
25
|
-
✔ Global CSS: app/globals.css
|
|
26
|
-
✔ CSS variables: yes
|
|
27
|
-
✔ tailwind.config: tailwind.config.ts
|
|
28
|
-
✔ Components alias: @/components
|
|
29
|
-
✔ Utils alias: @/lib/utils
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## 컴포넌트 추가
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
# 자주 사용하는 컴포넌트
|
|
36
|
-
bunx shadcn-ui@latest add button
|
|
37
|
-
bunx shadcn-ui@latest add input
|
|
38
|
-
bunx shadcn-ui@latest add card
|
|
39
|
-
bunx shadcn-ui@latest add dialog
|
|
40
|
-
bunx shadcn-ui@latest add dropdown-menu
|
|
41
|
-
bunx shadcn-ui@latest add form
|
|
42
|
-
bunx shadcn-ui@latest add toast
|
|
43
|
-
|
|
44
|
-
# 한 번에 여러 개
|
|
45
|
-
bunx shadcn-ui@latest add button input card dialog
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## 생성된 구조
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
components/
|
|
52
|
-
└── ui/
|
|
53
|
-
├── button.tsx # 직접 수정 가능
|
|
54
|
-
├── input.tsx
|
|
55
|
-
├── card.tsx
|
|
56
|
-
└── ...
|
|
57
|
-
|
|
58
|
-
lib/
|
|
59
|
-
└── utils.ts # cn() 함수
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## 컴포넌트 커스터마이징
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
// components/ui/button.tsx
|
|
66
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
67
|
-
|
|
68
|
-
const buttonVariants = cva(
|
|
69
|
-
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
|
|
70
|
-
{
|
|
71
|
-
variants: {
|
|
72
|
-
variant: {
|
|
73
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
74
|
-
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
75
|
-
outline: "border border-input bg-background hover:bg-accent",
|
|
76
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
77
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
78
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
79
|
-
// 커스텀 variant 추가
|
|
80
|
-
mandu: "bg-blue-500 text-white hover:bg-blue-600",
|
|
81
|
-
},
|
|
82
|
-
size: {
|
|
83
|
-
default: "h-10 px-4 py-2",
|
|
84
|
-
sm: "h-9 rounded-md px-3",
|
|
85
|
-
lg: "h-11 rounded-md px-8",
|
|
86
|
-
icon: "h-10 w-10",
|
|
87
|
-
// 커스텀 size 추가
|
|
88
|
-
xl: "h-14 rounded-lg px-10 text-lg",
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
defaultVariants: {
|
|
92
|
-
variant: "default",
|
|
93
|
-
size: "default",
|
|
94
|
-
},
|
|
95
|
-
}
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// ... 컴포넌트 코드
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Island에서 사용
|
|
102
|
-
|
|
103
|
-
```tsx
|
|
104
|
-
// app/actions/client.tsx
|
|
105
|
-
"use client";
|
|
106
|
-
|
|
107
|
-
import { Button } from "@/components/ui/button";
|
|
108
|
-
import { useState } from "react";
|
|
109
|
-
|
|
110
|
-
export function ActionButtonsIsland() {
|
|
111
|
-
const [loading, setLoading] = useState(false);
|
|
112
|
-
|
|
113
|
-
const handleAction = async () => {
|
|
114
|
-
setLoading(true);
|
|
115
|
-
try {
|
|
116
|
-
await doSomething();
|
|
117
|
-
} finally {
|
|
118
|
-
setLoading(false);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<div className="flex gap-2">
|
|
124
|
-
<Button onClick={handleAction} disabled={loading}>
|
|
125
|
-
{loading ? "Processing..." : "Submit"}
|
|
126
|
-
</Button>
|
|
127
|
-
<Button variant="outline">Cancel</Button>
|
|
128
|
-
</div>
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Form 통합
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
bunx shadcn-ui@latest add form
|
|
137
|
-
bun add react-hook-form @hookform/resolvers zod
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
```tsx
|
|
141
|
-
// app/contact/client.tsx
|
|
142
|
-
"use client";
|
|
143
|
-
|
|
144
|
-
import { useForm } from "react-hook-form";
|
|
145
|
-
import { zodResolver } from "@hookform/resolvers/zod";
|
|
146
|
-
import { z } from "zod";
|
|
147
|
-
import { Button } from "@/components/ui/button";
|
|
148
|
-
import {
|
|
149
|
-
Form,
|
|
150
|
-
FormControl,
|
|
151
|
-
FormField,
|
|
152
|
-
FormItem,
|
|
153
|
-
FormLabel,
|
|
154
|
-
FormMessage,
|
|
155
|
-
} from "@/components/ui/form";
|
|
156
|
-
import { Input } from "@/components/ui/input";
|
|
157
|
-
|
|
158
|
-
const formSchema = z.object({
|
|
159
|
-
email: z.string().email("Invalid email"),
|
|
160
|
-
message: z.string().min(10, "Minimum 10 characters"),
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
export function ContactFormIsland() {
|
|
164
|
-
const form = useForm<z.infer<typeof formSchema>>({
|
|
165
|
-
resolver: zodResolver(formSchema),
|
|
166
|
-
defaultValues: { email: "", message: "" },
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
|
170
|
-
await fetch("/api/contact", {
|
|
171
|
-
method: "POST",
|
|
172
|
-
body: JSON.stringify(values),
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<Form {...form}>
|
|
178
|
-
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
179
|
-
<FormField
|
|
180
|
-
control={form.control}
|
|
181
|
-
name="email"
|
|
182
|
-
render={({ field }) => (
|
|
183
|
-
<FormItem>
|
|
184
|
-
<FormLabel>Email</FormLabel>
|
|
185
|
-
<FormControl>
|
|
186
|
-
<Input placeholder="you@example.com" {...field} />
|
|
187
|
-
</FormControl>
|
|
188
|
-
<FormMessage />
|
|
189
|
-
</FormItem>
|
|
190
|
-
)}
|
|
191
|
-
/>
|
|
192
|
-
<Button type="submit">Send</Button>
|
|
193
|
-
</form>
|
|
194
|
-
</Form>
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## 업데이트
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
# 컴포넌트 업데이트 (덮어쓰기 주의!)
|
|
203
|
-
bunx shadcn-ui@latest add button --overwrite
|
|
204
|
-
|
|
205
|
-
# diff 확인 후 수동 병합 권장
|
|
206
|
-
bunx shadcn-ui@latest diff button
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Reference: [shadcn/ui Documentation](https://ui.shadcn.com/docs)
|
|
1
|
+
---
|
|
2
|
+
title: shadcn/ui Setup
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Production-ready UI components with full customization
|
|
5
|
+
tags: ui, shadcn, setup, components
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## shadcn/ui Setup
|
|
9
|
+
|
|
10
|
+
**Impact: HIGH (Production-ready UI components with full customization)**
|
|
11
|
+
|
|
12
|
+
shadcn/ui를 Mandu 프로젝트에 설정하세요. 컴포넌트를 직접 소유하고 커스터마이징할 수 있습니다.
|
|
13
|
+
|
|
14
|
+
**초기화:**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bunx shadcn-ui@latest init
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**선택 옵션:**
|
|
21
|
+
```
|
|
22
|
+
✔ TypeScript: yes
|
|
23
|
+
✔ Style: Default (또는 New York)
|
|
24
|
+
✔ Base color: Slate
|
|
25
|
+
✔ Global CSS: app/globals.css
|
|
26
|
+
✔ CSS variables: yes
|
|
27
|
+
✔ tailwind.config: tailwind.config.ts
|
|
28
|
+
✔ Components alias: @/components
|
|
29
|
+
✔ Utils alias: @/lib/utils
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 컴포넌트 추가
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 자주 사용하는 컴포넌트
|
|
36
|
+
bunx shadcn-ui@latest add button
|
|
37
|
+
bunx shadcn-ui@latest add input
|
|
38
|
+
bunx shadcn-ui@latest add card
|
|
39
|
+
bunx shadcn-ui@latest add dialog
|
|
40
|
+
bunx shadcn-ui@latest add dropdown-menu
|
|
41
|
+
bunx shadcn-ui@latest add form
|
|
42
|
+
bunx shadcn-ui@latest add toast
|
|
43
|
+
|
|
44
|
+
# 한 번에 여러 개
|
|
45
|
+
bunx shadcn-ui@latest add button input card dialog
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 생성된 구조
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
components/
|
|
52
|
+
└── ui/
|
|
53
|
+
├── button.tsx # 직접 수정 가능
|
|
54
|
+
├── input.tsx
|
|
55
|
+
├── card.tsx
|
|
56
|
+
└── ...
|
|
57
|
+
|
|
58
|
+
lib/
|
|
59
|
+
└── utils.ts # cn() 함수
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 컴포넌트 커스터마이징
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// components/ui/button.tsx
|
|
66
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
67
|
+
|
|
68
|
+
const buttonVariants = cva(
|
|
69
|
+
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
|
|
70
|
+
{
|
|
71
|
+
variants: {
|
|
72
|
+
variant: {
|
|
73
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
74
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
75
|
+
outline: "border border-input bg-background hover:bg-accent",
|
|
76
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
77
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
78
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
79
|
+
// 커스텀 variant 추가
|
|
80
|
+
mandu: "bg-blue-500 text-white hover:bg-blue-600",
|
|
81
|
+
},
|
|
82
|
+
size: {
|
|
83
|
+
default: "h-10 px-4 py-2",
|
|
84
|
+
sm: "h-9 rounded-md px-3",
|
|
85
|
+
lg: "h-11 rounded-md px-8",
|
|
86
|
+
icon: "h-10 w-10",
|
|
87
|
+
// 커스텀 size 추가
|
|
88
|
+
xl: "h-14 rounded-lg px-10 text-lg",
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: {
|
|
92
|
+
variant: "default",
|
|
93
|
+
size: "default",
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// ... 컴포넌트 코드
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Island에서 사용
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
// app/actions/client.tsx
|
|
105
|
+
"use client";
|
|
106
|
+
|
|
107
|
+
import { Button } from "@/components/ui/button";
|
|
108
|
+
import { useState } from "react";
|
|
109
|
+
|
|
110
|
+
export function ActionButtonsIsland() {
|
|
111
|
+
const [loading, setLoading] = useState(false);
|
|
112
|
+
|
|
113
|
+
const handleAction = async () => {
|
|
114
|
+
setLoading(true);
|
|
115
|
+
try {
|
|
116
|
+
await doSomething();
|
|
117
|
+
} finally {
|
|
118
|
+
setLoading(false);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div className="flex gap-2">
|
|
124
|
+
<Button onClick={handleAction} disabled={loading}>
|
|
125
|
+
{loading ? "Processing..." : "Submit"}
|
|
126
|
+
</Button>
|
|
127
|
+
<Button variant="outline">Cancel</Button>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Form 통합
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
bunx shadcn-ui@latest add form
|
|
137
|
+
bun add react-hook-form @hookform/resolvers zod
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
// app/contact/client.tsx
|
|
142
|
+
"use client";
|
|
143
|
+
|
|
144
|
+
import { useForm } from "react-hook-form";
|
|
145
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
146
|
+
import { z } from "zod";
|
|
147
|
+
import { Button } from "@/components/ui/button";
|
|
148
|
+
import {
|
|
149
|
+
Form,
|
|
150
|
+
FormControl,
|
|
151
|
+
FormField,
|
|
152
|
+
FormItem,
|
|
153
|
+
FormLabel,
|
|
154
|
+
FormMessage,
|
|
155
|
+
} from "@/components/ui/form";
|
|
156
|
+
import { Input } from "@/components/ui/input";
|
|
157
|
+
|
|
158
|
+
const formSchema = z.object({
|
|
159
|
+
email: z.string().email("Invalid email"),
|
|
160
|
+
message: z.string().min(10, "Minimum 10 characters"),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export function ContactFormIsland() {
|
|
164
|
+
const form = useForm<z.infer<typeof formSchema>>({
|
|
165
|
+
resolver: zodResolver(formSchema),
|
|
166
|
+
defaultValues: { email: "", message: "" },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
|
170
|
+
await fetch("/api/contact", {
|
|
171
|
+
method: "POST",
|
|
172
|
+
body: JSON.stringify(values),
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<Form {...form}>
|
|
178
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
179
|
+
<FormField
|
|
180
|
+
control={form.control}
|
|
181
|
+
name="email"
|
|
182
|
+
render={({ field }) => (
|
|
183
|
+
<FormItem>
|
|
184
|
+
<FormLabel>Email</FormLabel>
|
|
185
|
+
<FormControl>
|
|
186
|
+
<Input placeholder="you@example.com" {...field} />
|
|
187
|
+
</FormControl>
|
|
188
|
+
<FormMessage />
|
|
189
|
+
</FormItem>
|
|
190
|
+
)}
|
|
191
|
+
/>
|
|
192
|
+
<Button type="submit">Send</Button>
|
|
193
|
+
</form>
|
|
194
|
+
</Form>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 업데이트
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# 컴포넌트 업데이트 (덮어쓰기 주의!)
|
|
203
|
+
bunx shadcn-ui@latest add button --overwrite
|
|
204
|
+
|
|
205
|
+
# diff 확인 후 수동 병합 권장
|
|
206
|
+
bunx shadcn-ui@latest diff button
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Reference: [shadcn/ui Documentation](https://ui.shadcn.com/docs)
|