@mandujs/mcp 0.9.19 → 0.9.21

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 (122) hide show
  1. package/README.md +320 -0
  2. package/package.json +1 -1
  3. package/src/activity-monitor.ts +847 -231
  4. package/src/resources/handlers.ts +244 -0
  5. package/src/resources/skills/guides.ts +1136 -0
  6. package/src/resources/skills/index.ts +12 -0
  7. package/src/resources/skills/loader.ts +218 -0
  8. package/src/resources/skills/mandu-composition/SKILL.md +91 -0
  9. package/src/resources/skills/mandu-composition/metadata.json +13 -0
  10. package/src/resources/skills/mandu-composition/rules/_sections.md +26 -0
  11. package/src/resources/skills/mandu-composition/rules/_template.md +77 -0
  12. package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +146 -0
  13. package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +164 -0
  14. package/src/resources/skills/mandu-composition/rules/comp-island-event.md +161 -0
  15. package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +167 -0
  16. package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +149 -0
  17. package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +148 -0
  18. package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +150 -0
  19. package/src/resources/skills/mandu-deployment/SKILL.md +92 -0
  20. package/src/resources/skills/mandu-deployment/_sections.md +41 -0
  21. package/src/resources/skills/mandu-deployment/_template.md +38 -0
  22. package/src/resources/skills/mandu-deployment/metadata.json +13 -0
  23. package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +109 -0
  24. package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +115 -0
  25. package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +219 -0
  26. package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +150 -0
  27. package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +223 -0
  28. package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +152 -0
  29. package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +179 -0
  30. package/src/resources/skills/mandu-deployment/rules/deploy-platform-supabase.md +323 -0
  31. package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +140 -0
  32. package/src/resources/skills/mandu-fs-routes/SKILL.md +82 -0
  33. package/src/resources/skills/mandu-fs-routes/metadata.json +12 -0
  34. package/src/resources/skills/mandu-fs-routes/rules/_sections.md +36 -0
  35. package/src/resources/skills/mandu-fs-routes/rules/_template.md +69 -0
  36. package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +65 -0
  37. package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +93 -0
  38. package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +55 -0
  39. package/src/resources/skills/mandu-guard/SKILL.md +129 -0
  40. package/src/resources/skills/mandu-guard/metadata.json +12 -0
  41. package/src/resources/skills/mandu-guard/rules/_sections.md +36 -0
  42. package/src/resources/skills/mandu-guard/rules/_template.md +82 -0
  43. package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +100 -0
  44. package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +76 -0
  45. package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +81 -0
  46. package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +80 -0
  47. package/src/resources/skills/mandu-hydration/SKILL.md +91 -0
  48. package/src/resources/skills/mandu-hydration/metadata.json +12 -0
  49. package/src/resources/skills/mandu-hydration/rules/_sections.md +31 -0
  50. package/src/resources/skills/mandu-hydration/rules/_template.md +72 -0
  51. package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +109 -0
  52. package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +55 -0
  53. package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +113 -0
  54. package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +68 -0
  55. package/src/resources/skills/mandu-performance/SKILL.md +85 -0
  56. package/src/resources/skills/mandu-performance/metadata.json +14 -0
  57. package/src/resources/skills/mandu-performance/rules/_sections.md +31 -0
  58. package/src/resources/skills/mandu-performance/rules/_template.md +64 -0
  59. package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +103 -0
  60. package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +95 -0
  61. package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +124 -0
  62. package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +125 -0
  63. package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +80 -0
  64. package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +145 -0
  65. package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +98 -0
  66. package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +154 -0
  67. package/src/resources/skills/mandu-security/SKILL.md +87 -0
  68. package/src/resources/skills/mandu-security/metadata.json +13 -0
  69. package/src/resources/skills/mandu-security/rules/_sections.md +31 -0
  70. package/src/resources/skills/mandu-security/rules/_template.md +74 -0
  71. package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +127 -0
  72. package/src/resources/skills/mandu-security/rules/sec-env-management.md +133 -0
  73. package/src/resources/skills/mandu-security/rules/sec-input-validate.md +148 -0
  74. package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +146 -0
  75. package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +138 -0
  76. package/src/resources/skills/mandu-slot/SKILL.md +85 -0
  77. package/src/resources/skills/mandu-slot/metadata.json +12 -0
  78. package/src/resources/skills/mandu-slot/rules/_sections.md +36 -0
  79. package/src/resources/skills/mandu-slot/rules/_template.md +63 -0
  80. package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +38 -0
  81. package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +56 -0
  82. package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +59 -0
  83. package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +64 -0
  84. package/src/resources/skills/mandu-styling/SKILL.md +118 -0
  85. package/src/resources/skills/mandu-styling/_sections.md +36 -0
  86. package/src/resources/skills/mandu-styling/_template.md +32 -0
  87. package/src/resources/skills/mandu-styling/metadata.json +13 -0
  88. package/src/resources/skills/mandu-styling/rules/style-component-compound.md +235 -0
  89. package/src/resources/skills/mandu-styling/rules/style-component-slots.md +255 -0
  90. package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +205 -0
  91. package/src/resources/skills/mandu-styling/rules/style-island-animations.md +272 -0
  92. package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +167 -0
  93. package/src/resources/skills/mandu-styling/rules/style-island-variants.md +221 -0
  94. package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +209 -0
  95. package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +192 -0
  96. package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +162 -0
  97. package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +164 -0
  98. package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +161 -0
  99. package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +229 -0
  100. package/src/resources/skills/mandu-testing/SKILL.md +99 -0
  101. package/src/resources/skills/mandu-testing/metadata.json +13 -0
  102. package/src/resources/skills/mandu-testing/rules/_sections.md +26 -0
  103. package/src/resources/skills/mandu-testing/rules/_template.md +65 -0
  104. package/src/resources/skills/mandu-testing/rules/test-component-island.md +195 -0
  105. package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +196 -0
  106. package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +219 -0
  107. package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +192 -0
  108. package/src/resources/skills/mandu-ui/SKILL.md +117 -0
  109. package/src/resources/skills/mandu-ui/_sections.md +23 -0
  110. package/src/resources/skills/mandu-ui/_template.md +32 -0
  111. package/src/resources/skills/mandu-ui/metadata.json +13 -0
  112. package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +232 -0
  113. package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +238 -0
  114. package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +259 -0
  115. package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +258 -0
  116. package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +213 -0
  117. package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +209 -0
  118. package/src/resources/skills/recipes.ts +932 -0
  119. package/src/server.ts +3 -0
  120. package/src/tools/hydration.ts +8 -8
  121. package/src/tools/index.ts +1 -0
  122. package/src/tools/seo.ts +417 -0
@@ -0,0 +1,209 @@
1
+ ---
2
+ title: Critical CSS Extraction
3
+ impact: MEDIUM
4
+ impactDescription: Improves First Contentful Paint
5
+ tags: styling, performance, critical, fcp
6
+ ---
7
+
8
+ ## Critical CSS Extraction
9
+
10
+ **Impact: MEDIUM (Improves First Contentful Paint)**
11
+
12
+ 초기 렌더링에 필요한 CSS만 인라인으로 포함하여 FCP를 개선하세요.
13
+
14
+ ## Tailwind의 자동 최적화
15
+
16
+ Tailwind CSS는 JIT 컴파일로 사용된 클래스만 생성합니다.
17
+
18
+ ```typescript
19
+ // tailwind.config.ts
20
+ export default {
21
+ content: [
22
+ "./app/**/*.{ts,tsx}", // 실제 사용되는 파일만 스캔
23
+ ],
24
+ // ...
25
+ };
26
+ ```
27
+
28
+ ## Above-the-fold CSS 분리
29
+
30
+ ```tsx
31
+ // app/layout.tsx
32
+ export default function RootLayout({ children }) {
33
+ return (
34
+ <html>
35
+ <head>
36
+ {/* Critical CSS: 인라인 */}
37
+ <style
38
+ dangerouslySetInnerHTML={{
39
+ __html: `
40
+ /* Above-the-fold 스타일만 */
41
+ body { margin: 0; font-family: system-ui; }
42
+ .header { height: 64px; background: white; }
43
+ .hero { min-height: 50vh; }
44
+ `,
45
+ }}
46
+ />
47
+
48
+ {/* Non-critical CSS: 비동기 로드 */}
49
+ <link
50
+ rel="preload"
51
+ href="/styles/main.css"
52
+ as="style"
53
+ onLoad="this.onload=null;this.rel='stylesheet'"
54
+ />
55
+ <noscript>
56
+ <link rel="stylesheet" href="/styles/main.css" />
57
+ </noscript>
58
+ </head>
59
+ <body>{children}</body>
60
+ </html>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ## Lightning CSS 통합
66
+
67
+ ```bash
68
+ bun add -d lightningcss
69
+ ```
70
+
71
+ ```typescript
72
+ // scripts/build-css.ts
73
+ import { transform, browserslistToTargets } from "lightningcss";
74
+ import browserslist from "browserslist";
75
+
76
+ const targets = browserslistToTargets(browserslist(">= 0.25%"));
77
+
78
+ const css = await Bun.file("app/globals.css").text();
79
+
80
+ const { code } = transform({
81
+ filename: "globals.css",
82
+ code: Buffer.from(css),
83
+ minify: true,
84
+ targets,
85
+ // Critical CSS 추출
86
+ analyzeDependencies: true,
87
+ });
88
+
89
+ await Bun.write("dist/styles.css", code);
90
+ ```
91
+
92
+ ## PostCSS 설정
93
+
94
+ ```javascript
95
+ // postcss.config.js
96
+ export default {
97
+ plugins: {
98
+ tailwindcss: {},
99
+ autoprefixer: {},
100
+ ...(process.env.NODE_ENV === "production"
101
+ ? {
102
+ cssnano: {
103
+ preset: [
104
+ "default",
105
+ {
106
+ discardComments: { removeAll: true },
107
+ },
108
+ ],
109
+ },
110
+ }
111
+ : {}),
112
+ },
113
+ };
114
+ ```
115
+
116
+ ## CSS Layer 우선순위
117
+
118
+ ```css
119
+ /* globals.css */
120
+ @layer reset, base, components, utilities;
121
+
122
+ /* Critical: reset과 base만 인라인 */
123
+ @layer reset {
124
+ *,
125
+ *::before,
126
+ *::after {
127
+ box-sizing: border-box;
128
+ }
129
+ }
130
+
131
+ @layer base {
132
+ body {
133
+ @apply bg-background text-foreground;
134
+ }
135
+ }
136
+
137
+ /* Non-critical: 별도 파일 */
138
+ @layer components {
139
+ /* ... */
140
+ }
141
+
142
+ @layer utilities {
143
+ /* ... */
144
+ }
145
+ ```
146
+
147
+ ## Font 최적화
148
+
149
+ ```tsx
150
+ // 폰트 preload로 FOIT/FOUT 방지
151
+ <link
152
+ rel="preload"
153
+ href="/fonts/inter-var.woff2"
154
+ as="font"
155
+ type="font/woff2"
156
+ crossOrigin="anonymous"
157
+ />
158
+
159
+ // 폰트 display 설정
160
+ <style>
161
+ {`
162
+ @font-face {
163
+ font-family: 'Inter';
164
+ src: url('/fonts/inter-var.woff2') format('woff2');
165
+ font-display: swap;
166
+ }
167
+ `}
168
+ </style>
169
+ ```
170
+
171
+ ## 성능 측정
172
+
173
+ ```typescript
174
+ // 빌드 후 CSS 크기 확인
175
+ import { gzipSync } from "bun";
176
+
177
+ const css = await Bun.file("dist/styles.css").text();
178
+ const gzipped = gzipSync(Buffer.from(css));
179
+
180
+ console.log("CSS size:", css.length, "bytes");
181
+ console.log("Gzipped:", gzipped.length, "bytes");
182
+
183
+ // 목표: < 14KB (TCP 첫 라운드트립)
184
+ ```
185
+
186
+ ## Inline Critical + Lazy Load 패턴
187
+
188
+ ```tsx
189
+ // components/StyleLoader.tsx
190
+ "use client";
191
+
192
+ import { useEffect } from "react";
193
+
194
+ export function StyleLoader({ href }: { href: string }) {
195
+ useEffect(() => {
196
+ const link = document.createElement("link");
197
+ link.rel = "stylesheet";
198
+ link.href = href;
199
+ document.head.appendChild(link);
200
+ }, [href]);
201
+
202
+ return null;
203
+ }
204
+
205
+ // 사용
206
+ <StyleLoader href="/styles/non-critical.css" />
207
+ ```
208
+
209
+ Reference: [web.dev Critical CSS](https://web.dev/articles/extract-critical-css)
@@ -0,0 +1,192 @@
1
+ ---
2
+ title: CSS Purge and Tree Shaking
3
+ impact: MEDIUM
4
+ impactDescription: Removes unused CSS for smaller bundles
5
+ tags: styling, performance, purge, tree-shaking
6
+ ---
7
+
8
+ ## CSS Purge and Tree Shaking
9
+
10
+ **Impact: MEDIUM (Removes unused CSS for smaller bundles)**
11
+
12
+ 미사용 CSS를 제거하여 번들 크기를 최소화하세요.
13
+
14
+ ## Tailwind 자동 Purge
15
+
16
+ Tailwind v3+는 JIT 컴파일로 사용된 클래스만 생성합니다.
17
+
18
+ ```typescript
19
+ // tailwind.config.ts
20
+ export default {
21
+ // content 경로가 정확해야 함
22
+ content: [
23
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
24
+ "./components/**/*.{js,ts,jsx,tsx,mdx}",
25
+ "./lib/**/*.{js,ts,jsx,tsx,mdx}",
26
+ ],
27
+ // ...
28
+ };
29
+ ```
30
+
31
+ ## Safelist 관리
32
+
33
+ ```typescript
34
+ // tailwind.config.ts
35
+ export default {
36
+ content: ["./app/**/*.{ts,tsx}"],
37
+
38
+ // 동적으로 생성되는 클래스는 safelist에 추가
39
+ safelist: [
40
+ // 정적 패턴
41
+ "bg-red-500",
42
+ "bg-green-500",
43
+ "bg-blue-500",
44
+
45
+ // 정규식 패턴
46
+ {
47
+ pattern: /bg-(red|green|blue)-(100|500|900)/,
48
+ },
49
+
50
+ // 변형 포함
51
+ {
52
+ pattern: /text-(red|green|blue)-500/,
53
+ variants: ["hover", "dark"],
54
+ },
55
+ ],
56
+ };
57
+ ```
58
+
59
+ ## 동적 클래스 문제 방지
60
+
61
+ ```tsx
62
+ // ❌ Tailwind가 감지 못함
63
+ const color = "blue";
64
+ <div className={`bg-${color}-500`} />
65
+
66
+ // ✅ 전체 클래스명 사용
67
+ const colorClasses = {
68
+ blue: "bg-blue-500",
69
+ red: "bg-red-500",
70
+ green: "bg-green-500",
71
+ };
72
+ <div className={colorClasses[color]} />
73
+
74
+ // ✅ cva 사용
75
+ const badge = cva("px-2 py-1 rounded", {
76
+ variants: {
77
+ color: {
78
+ blue: "bg-blue-500",
79
+ red: "bg-red-500",
80
+ green: "bg-green-500",
81
+ },
82
+ },
83
+ });
84
+ ```
85
+
86
+ ## PurgeCSS 수동 설정
87
+
88
+ Tailwind 외 CSS 파일용:
89
+
90
+ ```bash
91
+ bun add -d purgecss
92
+ ```
93
+
94
+ ```javascript
95
+ // purgecss.config.js
96
+ export default {
97
+ content: ["./app/**/*.tsx", "./components/**/*.tsx"],
98
+ css: ["./styles/legacy.css"],
99
+ output: "./dist/styles/",
100
+
101
+ // 유지할 선택자
102
+ safelist: {
103
+ standard: [/^data-/],
104
+ deep: [/^modal/],
105
+ greedy: [/tooltip/],
106
+ },
107
+
108
+ // 커스텀 추출기
109
+ extractors: [
110
+ {
111
+ extractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
112
+ extensions: ["tsx", "ts"],
113
+ },
114
+ ],
115
+ };
116
+ ```
117
+
118
+ ```bash
119
+ bunx purgecss --config purgecss.config.js
120
+ ```
121
+
122
+ ## CSS Modules 최적화
123
+
124
+ CSS Modules는 자동으로 스코프되지만, 미사용 클래스는 제거되지 않음:
125
+
126
+ ```bash
127
+ bun add -d postcss-modules
128
+ ```
129
+
130
+ ```javascript
131
+ // postcss.config.js
132
+ export default {
133
+ plugins: {
134
+ "postcss-modules": {
135
+ generateScopedName: "[name]__[local]___[hash:base64:5]",
136
+ // 미사용 export 경고
137
+ getJSON: (cssFileName, json) => {
138
+ // 사용되지 않은 클래스 로깅
139
+ console.log(`CSS Modules in ${cssFileName}:`, Object.keys(json));
140
+ },
141
+ },
142
+ },
143
+ };
144
+ ```
145
+
146
+ ## 번들 분석
147
+
148
+ ```bash
149
+ # CSS 번들 크기 분석
150
+ bun add -d source-map-explorer
151
+
152
+ # 분석 실행
153
+ bunx source-map-explorer dist/styles.css --html report.html
154
+ ```
155
+
156
+ ## 빌드 스크립트
157
+
158
+ ```typescript
159
+ // scripts/analyze-css.ts
160
+ import { Glob } from "bun";
161
+
162
+ const cssGlob = new Glob("dist/**/*.css");
163
+ let totalSize = 0;
164
+
165
+ for await (const file of cssGlob.scan()) {
166
+ const stat = await Bun.file(file).size;
167
+ console.log(`${file}: ${(stat / 1024).toFixed(2)} KB`);
168
+ totalSize += stat;
169
+ }
170
+
171
+ console.log(`\nTotal CSS: ${(totalSize / 1024).toFixed(2)} KB`);
172
+
173
+ // 경고 임계값
174
+ if (totalSize > 50 * 1024) {
175
+ console.warn("⚠️ CSS bundle exceeds 50KB");
176
+ }
177
+ ```
178
+
179
+ ## CI에서 크기 체크
180
+
181
+ ```yaml
182
+ # .github/workflows/ci.yml
183
+ - name: Check CSS size
184
+ run: |
185
+ SIZE=$(stat -f%z dist/styles.css 2>/dev/null || stat -c%s dist/styles.css)
186
+ if [ $SIZE -gt 51200 ]; then
187
+ echo "CSS size ($SIZE bytes) exceeds 50KB limit"
188
+ exit 1
189
+ fi
190
+ ```
191
+
192
+ Reference: [Tailwind Optimizing for Production](https://tailwindcss.com/docs/optimizing-for-production)
@@ -0,0 +1,162 @@
1
+ ---
2
+ title: CSS Modules Setup
3
+ impact: CRITICAL
4
+ impactDescription: Zero-dependency styling with native Bun support
5
+ tags: styling, css-modules, setup, native
6
+ ---
7
+
8
+ ## CSS Modules Setup
9
+
10
+ **Impact: CRITICAL (Zero-dependency styling with native Bun support)**
11
+
12
+ 외부 의존성 없이 스코프된 CSS가 필요할 때 CSS Modules를 사용하세요.
13
+
14
+ **Bun 설정:**
15
+
16
+ Bun은 CSS Modules를 네이티브로 지원합니다. 별도 설정 불필요.
17
+
18
+ ```typescript
19
+ // bunfig.toml (선택적 최적화)
20
+ [build]
21
+ target = "browser"
22
+ minify = true
23
+
24
+ [build.loader]
25
+ ".module.css" = "css"
26
+ ```
27
+
28
+ ## 사용 예시
29
+
30
+ ```css
31
+ /* app/button/button.module.css */
32
+ .button {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ border-radius: 0.5rem;
37
+ font-weight: 500;
38
+ transition: all 0.2s;
39
+ }
40
+
41
+ .default {
42
+ background-color: var(--mandu-primary);
43
+ color: white;
44
+ }
45
+
46
+ .default:hover {
47
+ background-color: var(--mandu-primary-dark);
48
+ }
49
+
50
+ .outline {
51
+ border: 1px solid var(--mandu-primary);
52
+ color: var(--mandu-primary);
53
+ }
54
+
55
+ .outline:hover {
56
+ background-color: var(--mandu-primary-light);
57
+ }
58
+
59
+ .sm { height: 2rem; padding: 0 0.75rem; font-size: 0.875rem; }
60
+ .md { height: 2.5rem; padding: 0 1rem; }
61
+ .lg { height: 3rem; padding: 0 1.5rem; font-size: 1.125rem; }
62
+ ```
63
+
64
+ ```tsx
65
+ // app/button/client.tsx
66
+ "use client";
67
+
68
+ import styles from "./button.module.css";
69
+
70
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
71
+ variant?: "default" | "outline";
72
+ size?: "sm" | "md" | "lg";
73
+ }
74
+
75
+ export function ButtonIsland({
76
+ variant = "default",
77
+ size = "md",
78
+ className,
79
+ ...props
80
+ }: ButtonProps) {
81
+ const classes = [
82
+ styles.button,
83
+ styles[variant],
84
+ styles[size],
85
+ className,
86
+ ].filter(Boolean).join(" ");
87
+
88
+ return <button className={classes} {...props} />;
89
+ }
90
+ ```
91
+
92
+ ## CSS Variables 활용
93
+
94
+ ```css
95
+ /* app/globals.css */
96
+ :root {
97
+ --mandu-primary: #3b82f6;
98
+ --mandu-primary-dark: #2563eb;
99
+ --mandu-primary-light: rgba(59, 130, 246, 0.1);
100
+ --mandu-secondary: #64748b;
101
+ --mandu-radius: 0.5rem;
102
+ }
103
+
104
+ .dark {
105
+ --mandu-primary: #60a5fa;
106
+ --mandu-primary-dark: #3b82f6;
107
+ --mandu-background: #0f172a;
108
+ --mandu-foreground: #f8fafc;
109
+ }
110
+ ```
111
+
112
+ ## clsx 조합
113
+
114
+ ```bash
115
+ bun add clsx
116
+ ```
117
+
118
+ ```tsx
119
+ import clsx from "clsx";
120
+ import styles from "./card.module.css";
121
+
122
+ export function CardIsland({ highlighted }: { highlighted?: boolean }) {
123
+ return (
124
+ <div
125
+ className={clsx(styles.card, {
126
+ [styles.highlighted]: highlighted,
127
+ })}
128
+ >
129
+ Content
130
+ </div>
131
+ );
132
+ }
133
+ ```
134
+
135
+ ## TypeScript 타입 정의
136
+
137
+ ```typescript
138
+ // types/css.d.ts
139
+ declare module "*.module.css" {
140
+ const classes: { [key: string]: string };
141
+ export default classes;
142
+ }
143
+ ```
144
+
145
+ ## 장단점
146
+
147
+ **장점:**
148
+ - 의존성 없음 (Bun 네이티브)
149
+ - 스코프 자동 격리
150
+ - 작은 번들 크기
151
+
152
+ **단점:**
153
+ - 유틸리티 클래스 없음
154
+ - 반복 코드 발생 가능
155
+ - Tailwind 생태계 미호환
156
+
157
+ **추천 사용 케이스:**
158
+ - 최소 의존성 프로젝트
159
+ - 레거시 CSS 마이그레이션
160
+ - 특정 컴포넌트 격리
161
+
162
+ Reference: [Bun CSS Support](https://bun.sh/docs/bundler/loaders#css)
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: Panda CSS Setup
3
+ impact: CRITICAL
4
+ impactDescription: Type-safe alternative CSS framework
5
+ tags: styling, panda, setup, type-safe
6
+ ---
7
+
8
+ ## Panda CSS Setup
9
+
10
+ **Impact: CRITICAL (Type-safe alternative CSS framework)**
11
+
12
+ Type-safe CSS-in-JS가 필요할 때 Panda CSS를 사용하세요. Zero-runtime으로 Island와 완벽 호환됩니다.
13
+
14
+ **설치:**
15
+
16
+ ```bash
17
+ bun add -d @pandacss/dev
18
+ bunx panda init
19
+ ```
20
+
21
+ **panda.config.ts:**
22
+
23
+ ```typescript
24
+ import { defineConfig } from "@pandacss/dev";
25
+
26
+ export default defineConfig({
27
+ preflight: true,
28
+ include: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
29
+ exclude: [],
30
+
31
+ theme: {
32
+ extend: {
33
+ tokens: {
34
+ colors: {
35
+ mandu: {
36
+ primary: { value: "#3b82f6" },
37
+ secondary: { value: "#64748b" },
38
+ accent: { value: "#f59e0b" },
39
+ },
40
+ },
41
+ radii: {
42
+ mandu: { value: "0.5rem" },
43
+ },
44
+ },
45
+ semanticTokens: {
46
+ colors: {
47
+ background: {
48
+ value: { base: "{colors.white}", _dark: "{colors.zinc.900}" },
49
+ },
50
+ foreground: {
51
+ value: { base: "{colors.zinc.900}", _dark: "{colors.white}" },
52
+ },
53
+ },
54
+ },
55
+ },
56
+ },
57
+
58
+ outdir: "styled-system",
59
+ });
60
+ ```
61
+
62
+ **package.json 스크립트:**
63
+
64
+ ```json
65
+ {
66
+ "scripts": {
67
+ "prepare": "panda codegen",
68
+ "dev": "panda --watch & bun run serve"
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## 사용 예시
74
+
75
+ ```tsx
76
+ // app/button/client.tsx
77
+ "use client";
78
+
79
+ import { css, cva } from "@/styled-system/css";
80
+
81
+ const button = cva({
82
+ base: {
83
+ display: "inline-flex",
84
+ alignItems: "center",
85
+ justifyContent: "center",
86
+ borderRadius: "mandu",
87
+ fontWeight: "medium",
88
+ transition: "colors",
89
+ cursor: "pointer",
90
+ },
91
+ variants: {
92
+ variant: {
93
+ default: {
94
+ bg: "mandu.primary",
95
+ color: "white",
96
+ _hover: { bg: "mandu.primary/90" },
97
+ },
98
+ outline: {
99
+ border: "1px solid",
100
+ borderColor: "mandu.primary",
101
+ color: "mandu.primary",
102
+ _hover: { bg: "mandu.primary/10" },
103
+ },
104
+ ghost: {
105
+ _hover: { bg: "mandu.secondary/20" },
106
+ },
107
+ },
108
+ size: {
109
+ sm: { h: "8", px: "3", fontSize: "sm" },
110
+ md: { h: "10", px: "4" },
111
+ lg: { h: "12", px: "6", fontSize: "lg" },
112
+ },
113
+ },
114
+ defaultVariants: {
115
+ variant: "default",
116
+ size: "md",
117
+ },
118
+ });
119
+
120
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
121
+ variant?: "default" | "outline" | "ghost";
122
+ size?: "sm" | "md" | "lg";
123
+ }
124
+
125
+ export function ButtonIsland({ variant, size, className, ...props }: ButtonProps) {
126
+ return (
127
+ <button className={button({ variant, size })} {...props} />
128
+ );
129
+ }
130
+ ```
131
+
132
+ ## Inline Styles
133
+
134
+ ```tsx
135
+ import { css } from "@/styled-system/css";
136
+
137
+ export function CardIsland() {
138
+ return (
139
+ <div
140
+ className={css({
141
+ p: "4",
142
+ rounded: "mandu",
143
+ bg: "background",
144
+ shadow: "md",
145
+ _hover: { shadow: "lg" },
146
+ })}
147
+ >
148
+ Content
149
+ </div>
150
+ );
151
+ }
152
+ ```
153
+
154
+ ## Tailwind와의 비교
155
+
156
+ | 기능 | Tailwind | Panda |
157
+ |------|----------|-------|
158
+ | Type-safe | ❌ | ✅ |
159
+ | Zero-runtime | ✅ | ✅ |
160
+ | 생태계 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
161
+ | DX | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
162
+ | 학습 곡선 | 낮음 | 중간 |
163
+
164
+ Reference: [Panda CSS Documentation](https://panda-css.com/docs)