omgkit 2.2.0 → 2.3.1
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 +3 -3
- package/package.json +1 -1
- package/plugin/skills/databases/database-management/SKILL.md +288 -0
- package/plugin/skills/databases/database-migration/SKILL.md +285 -0
- package/plugin/skills/databases/database-schema-design/SKILL.md +195 -0
- package/plugin/skills/databases/mongodb/SKILL.md +60 -776
- package/plugin/skills/databases/prisma/SKILL.md +53 -744
- package/plugin/skills/databases/redis/SKILL.md +53 -860
- package/plugin/skills/databases/supabase/SKILL.md +283 -0
- package/plugin/skills/devops/aws/SKILL.md +68 -672
- package/plugin/skills/devops/github-actions/SKILL.md +54 -657
- package/plugin/skills/devops/kubernetes/SKILL.md +67 -602
- package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
- package/plugin/skills/frameworks/django/SKILL.md +87 -853
- package/plugin/skills/frameworks/express/SKILL.md +95 -1301
- package/plugin/skills/frameworks/fastapi/SKILL.md +90 -1198
- package/plugin/skills/frameworks/laravel/SKILL.md +87 -1187
- package/plugin/skills/frameworks/nestjs/SKILL.md +106 -973
- package/plugin/skills/frameworks/react/SKILL.md +94 -962
- package/plugin/skills/frameworks/vue/SKILL.md +95 -1242
- package/plugin/skills/frontend/accessibility/SKILL.md +91 -1056
- package/plugin/skills/frontend/frontend-design/SKILL.md +69 -1262
- package/plugin/skills/frontend/responsive/SKILL.md +76 -799
- package/plugin/skills/frontend/shadcn-ui/SKILL.md +73 -921
- package/plugin/skills/frontend/tailwindcss/SKILL.md +60 -788
- package/plugin/skills/frontend/threejs/SKILL.md +72 -1266
- package/plugin/skills/languages/javascript/SKILL.md +106 -849
- package/plugin/skills/methodology/brainstorming/SKILL.md +70 -576
- package/plugin/skills/methodology/defense-in-depth/SKILL.md +79 -831
- package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +81 -654
- package/plugin/skills/methodology/executing-plans/SKILL.md +86 -529
- package/plugin/skills/methodology/finishing-development-branch/SKILL.md +95 -586
- package/plugin/skills/methodology/problem-solving/SKILL.md +67 -681
- package/plugin/skills/methodology/receiving-code-review/SKILL.md +70 -533
- package/plugin/skills/methodology/requesting-code-review/SKILL.md +70 -610
- package/plugin/skills/methodology/root-cause-tracing/SKILL.md +70 -646
- package/plugin/skills/methodology/sequential-thinking/SKILL.md +70 -478
- package/plugin/skills/methodology/systematic-debugging/SKILL.md +66 -559
- package/plugin/skills/methodology/test-driven-development/SKILL.md +91 -752
- package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +78 -687
- package/plugin/skills/methodology/token-optimization/SKILL.md +72 -602
- package/plugin/skills/methodology/verification-before-completion/SKILL.md +108 -529
- package/plugin/skills/methodology/writing-plans/SKILL.md +79 -566
- package/plugin/skills/omega/omega-architecture/SKILL.md +91 -752
- package/plugin/skills/omega/omega-coding/SKILL.md +161 -552
- package/plugin/skills/omega/omega-sprint/SKILL.md +132 -777
- package/plugin/skills/omega/omega-testing/SKILL.md +157 -845
- package/plugin/skills/omega/omega-thinking/SKILL.md +165 -606
- package/plugin/skills/security/better-auth/SKILL.md +46 -1034
- package/plugin/skills/security/oauth/SKILL.md +80 -934
- package/plugin/skills/security/owasp/SKILL.md +78 -862
- package/plugin/skills/testing/playwright/SKILL.md +77 -700
- package/plugin/skills/testing/pytest/SKILL.md +73 -811
- package/plugin/skills/testing/vitest/SKILL.md +60 -920
- package/plugin/skills/tools/document-processing/SKILL.md +111 -838
- package/plugin/skills/tools/image-processing/SKILL.md +126 -659
- package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
- package/plugin/skills/tools/media-processing/SKILL.md +118 -735
- package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
- package/plugin/skills/SKILL_STANDARDS.md +0 -743
|
@@ -1,374 +1,48 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: Tailwind CSS utility
|
|
4
|
-
category: frontend
|
|
5
|
-
triggers:
|
|
6
|
-
- tailwind
|
|
7
|
-
- tailwindcss
|
|
8
|
-
- utility classes
|
|
9
|
-
- css framework
|
|
10
|
-
- styling
|
|
2
|
+
name: styling-with-tailwind
|
|
3
|
+
description: Claude styles UIs with Tailwind CSS utility classes, responsive design, and dark mode support. Use when creating component styles, theming systems, or responsive layouts.
|
|
11
4
|
---
|
|
12
5
|
|
|
13
|
-
# Tailwind CSS
|
|
6
|
+
# Styling with Tailwind CSS
|
|
14
7
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## Purpose
|
|
18
|
-
|
|
19
|
-
Build beautiful, responsive UIs efficiently:
|
|
20
|
-
|
|
21
|
-
- Write utility-first CSS
|
|
22
|
-
- Implement responsive designs
|
|
23
|
-
- Configure dark mode theming
|
|
24
|
-
- Create reusable component patterns
|
|
25
|
-
- Customize design tokens
|
|
26
|
-
- Optimize for production
|
|
27
|
-
- Build accessible interfaces
|
|
28
|
-
|
|
29
|
-
## Features
|
|
30
|
-
|
|
31
|
-
### 1. Configuration Setup
|
|
32
|
-
|
|
33
|
-
```javascript
|
|
34
|
-
// tailwind.config.js
|
|
35
|
-
/** @type {import('tailwindcss').Config} */
|
|
36
|
-
module.exports = {
|
|
37
|
-
content: [
|
|
38
|
-
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
|
39
|
-
"./components/**/*.{js,ts,jsx,tsx}",
|
|
40
|
-
"./app/**/*.{js,ts,jsx,tsx}",
|
|
41
|
-
],
|
|
42
|
-
darkMode: "class", // or 'media'
|
|
43
|
-
theme: {
|
|
44
|
-
extend: {
|
|
45
|
-
// Custom colors
|
|
46
|
-
colors: {
|
|
47
|
-
primary: {
|
|
48
|
-
50: "#eff6ff",
|
|
49
|
-
100: "#dbeafe",
|
|
50
|
-
200: "#bfdbfe",
|
|
51
|
-
300: "#93c5fd",
|
|
52
|
-
400: "#60a5fa",
|
|
53
|
-
500: "#3b82f6",
|
|
54
|
-
600: "#2563eb",
|
|
55
|
-
700: "#1d4ed8",
|
|
56
|
-
800: "#1e40af",
|
|
57
|
-
900: "#1e3a8a",
|
|
58
|
-
950: "#172554",
|
|
59
|
-
},
|
|
60
|
-
secondary: {
|
|
61
|
-
50: "#f8fafc",
|
|
62
|
-
// ... other shades
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
// Custom spacing
|
|
66
|
-
spacing: {
|
|
67
|
-
"18": "4.5rem",
|
|
68
|
-
"88": "22rem",
|
|
69
|
-
"128": "32rem",
|
|
70
|
-
},
|
|
71
|
-
// Custom fonts
|
|
72
|
-
fontFamily: {
|
|
73
|
-
sans: ["Inter", "system-ui", "sans-serif"],
|
|
74
|
-
mono: ["JetBrains Mono", "monospace"],
|
|
75
|
-
},
|
|
76
|
-
// Custom font sizes
|
|
77
|
-
fontSize: {
|
|
78
|
-
"2xs": ["0.625rem", { lineHeight: "0.75rem" }],
|
|
79
|
-
},
|
|
80
|
-
// Custom border radius
|
|
81
|
-
borderRadius: {
|
|
82
|
-
"4xl": "2rem",
|
|
83
|
-
},
|
|
84
|
-
// Custom animations
|
|
85
|
-
animation: {
|
|
86
|
-
"fade-in": "fadeIn 0.3s ease-in-out",
|
|
87
|
-
"slide-up": "slideUp 0.3s ease-out",
|
|
88
|
-
"spin-slow": "spin 3s linear infinite",
|
|
89
|
-
"pulse-slow": "pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite",
|
|
90
|
-
},
|
|
91
|
-
keyframes: {
|
|
92
|
-
fadeIn: {
|
|
93
|
-
"0%": { opacity: "0" },
|
|
94
|
-
"100%": { opacity: "1" },
|
|
95
|
-
},
|
|
96
|
-
slideUp: {
|
|
97
|
-
"0%": { transform: "translateY(10px)", opacity: "0" },
|
|
98
|
-
"100%": { transform: "translateY(0)", opacity: "1" },
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
// Custom box shadows
|
|
102
|
-
boxShadow: {
|
|
103
|
-
"soft": "0 2px 15px -3px rgba(0, 0, 0, 0.07), 0 10px 20px -2px rgba(0, 0, 0, 0.04)",
|
|
104
|
-
"inner-soft": "inset 0 2px 4px 0 rgba(0, 0, 0, 0.05)",
|
|
105
|
-
},
|
|
106
|
-
// Custom breakpoints
|
|
107
|
-
screens: {
|
|
108
|
-
"xs": "475px",
|
|
109
|
-
"3xl": "1920px",
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
plugins: [
|
|
114
|
-
require("@tailwindcss/forms"),
|
|
115
|
-
require("@tailwindcss/typography"),
|
|
116
|
-
require("@tailwindcss/aspect-ratio"),
|
|
117
|
-
require("@tailwindcss/container-queries"),
|
|
118
|
-
],
|
|
119
|
-
};
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
```css
|
|
123
|
-
/* globals.css */
|
|
124
|
-
@tailwind base;
|
|
125
|
-
@tailwind components;
|
|
126
|
-
@tailwind utilities;
|
|
127
|
-
|
|
128
|
-
@layer base {
|
|
129
|
-
:root {
|
|
130
|
-
--background: 0 0% 100%;
|
|
131
|
-
--foreground: 222.2 84% 4.9%;
|
|
132
|
-
--primary: 221.2 83.2% 53.3%;
|
|
133
|
-
--primary-foreground: 210 40% 98%;
|
|
134
|
-
--secondary: 210 40% 96.1%;
|
|
135
|
-
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
136
|
-
--muted: 210 40% 96.1%;
|
|
137
|
-
--muted-foreground: 215.4 16.3% 46.9%;
|
|
138
|
-
--accent: 210 40% 96.1%;
|
|
139
|
-
--accent-foreground: 222.2 47.4% 11.2%;
|
|
140
|
-
--destructive: 0 84.2% 60.2%;
|
|
141
|
-
--destructive-foreground: 210 40% 98%;
|
|
142
|
-
--border: 214.3 31.8% 91.4%;
|
|
143
|
-
--input: 214.3 31.8% 91.4%;
|
|
144
|
-
--ring: 221.2 83.2% 53.3%;
|
|
145
|
-
--radius: 0.5rem;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.dark {
|
|
149
|
-
--background: 222.2 84% 4.9%;
|
|
150
|
-
--foreground: 210 40% 98%;
|
|
151
|
-
--primary: 217.2 91.2% 59.8%;
|
|
152
|
-
--primary-foreground: 222.2 47.4% 11.2%;
|
|
153
|
-
--secondary: 217.2 32.6% 17.5%;
|
|
154
|
-
--secondary-foreground: 210 40% 98%;
|
|
155
|
-
--muted: 217.2 32.6% 17.5%;
|
|
156
|
-
--muted-foreground: 215 20.2% 65.1%;
|
|
157
|
-
--accent: 217.2 32.6% 17.5%;
|
|
158
|
-
--accent-foreground: 210 40% 98%;
|
|
159
|
-
--destructive: 0 62.8% 30.6%;
|
|
160
|
-
--destructive-foreground: 210 40% 98%;
|
|
161
|
-
--border: 217.2 32.6% 17.5%;
|
|
162
|
-
--input: 217.2 32.6% 17.5%;
|
|
163
|
-
--ring: 224.3 76.3% 48%;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@layer base {
|
|
168
|
-
* {
|
|
169
|
-
@apply border-border;
|
|
170
|
-
}
|
|
171
|
-
body {
|
|
172
|
-
@apply bg-background text-foreground;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### 2. Component Patterns
|
|
8
|
+
## Quick Start
|
|
178
9
|
|
|
179
10
|
```tsx
|
|
180
|
-
// Button
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
size?: "sm" | "md" | "lg";
|
|
184
|
-
loading?: boolean;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function Button({
|
|
188
|
-
variant = "primary",
|
|
189
|
-
size = "md",
|
|
190
|
-
loading,
|
|
191
|
-
className,
|
|
192
|
-
children,
|
|
193
|
-
disabled,
|
|
194
|
-
...props
|
|
195
|
-
}: ButtonProps) {
|
|
196
|
-
const baseStyles = `
|
|
197
|
-
inline-flex items-center justify-center
|
|
198
|
-
font-medium rounded-lg
|
|
199
|
-
transition-colors duration-200
|
|
200
|
-
focus:outline-none focus:ring-2 focus:ring-offset-2
|
|
201
|
-
disabled:opacity-50 disabled:cursor-not-allowed
|
|
202
|
-
`;
|
|
203
|
-
|
|
11
|
+
// Button with variants using utility classes
|
|
12
|
+
export function Button({ variant = 'primary', size = 'md', children }: ButtonProps) {
|
|
13
|
+
const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50';
|
|
204
14
|
const variants = {
|
|
205
|
-
primary:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
focus:ring-primary-500
|
|
209
|
-
`,
|
|
210
|
-
secondary: `
|
|
211
|
-
bg-secondary-100 text-secondary-900
|
|
212
|
-
hover:bg-secondary-200
|
|
213
|
-
focus:ring-secondary-500
|
|
214
|
-
dark:bg-secondary-800 dark:text-secondary-100
|
|
215
|
-
`,
|
|
216
|
-
outline: `
|
|
217
|
-
border-2 border-primary-600 text-primary-600
|
|
218
|
-
hover:bg-primary-50
|
|
219
|
-
focus:ring-primary-500
|
|
220
|
-
dark:border-primary-400 dark:text-primary-400
|
|
221
|
-
`,
|
|
222
|
-
ghost: `
|
|
223
|
-
text-gray-700 hover:bg-gray-100
|
|
224
|
-
focus:ring-gray-500
|
|
225
|
-
dark:text-gray-300 dark:hover:bg-gray-800
|
|
226
|
-
`,
|
|
227
|
-
destructive: `
|
|
228
|
-
bg-red-600 text-white
|
|
229
|
-
hover:bg-red-700
|
|
230
|
-
focus:ring-red-500
|
|
231
|
-
`,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const sizes = {
|
|
235
|
-
sm: "px-3 py-1.5 text-sm gap-1.5",
|
|
236
|
-
md: "px-4 py-2 text-base gap-2",
|
|
237
|
-
lg: "px-6 py-3 text-lg gap-2.5",
|
|
15
|
+
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
|
|
16
|
+
outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50 focus:ring-blue-500',
|
|
17
|
+
ghost: 'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800',
|
|
238
18
|
};
|
|
19
|
+
const sizes = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2', lg: 'px-6 py-3 text-lg' };
|
|
239
20
|
|
|
240
21
|
return (
|
|
241
|
-
<button
|
|
242
|
-
className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
|
|
243
|
-
disabled={disabled || loading}
|
|
244
|
-
{...props}
|
|
245
|
-
>
|
|
246
|
-
{loading && (
|
|
247
|
-
<svg
|
|
248
|
-
className="animate-spin h-4 w-4"
|
|
249
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
250
|
-
fill="none"
|
|
251
|
-
viewBox="0 0 24 24"
|
|
252
|
-
>
|
|
253
|
-
<circle
|
|
254
|
-
className="opacity-25"
|
|
255
|
-
cx="12"
|
|
256
|
-
cy="12"
|
|
257
|
-
r="10"
|
|
258
|
-
stroke="currentColor"
|
|
259
|
-
strokeWidth="4"
|
|
260
|
-
/>
|
|
261
|
-
<path
|
|
262
|
-
className="opacity-75"
|
|
263
|
-
fill="currentColor"
|
|
264
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
265
|
-
/>
|
|
266
|
-
</svg>
|
|
267
|
-
)}
|
|
22
|
+
<button className={`${base} ${variants[variant]} ${sizes[size]}`}>
|
|
268
23
|
{children}
|
|
269
24
|
</button>
|
|
270
25
|
);
|
|
271
26
|
}
|
|
27
|
+
```
|
|
272
28
|
|
|
273
|
-
|
|
274
|
-
interface CardProps {
|
|
275
|
-
children: React.ReactNode;
|
|
276
|
-
className?: string;
|
|
277
|
-
hoverable?: boolean;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export function Card({ children, className, hoverable }: CardProps) {
|
|
281
|
-
return (
|
|
282
|
-
<div
|
|
283
|
-
className={`
|
|
284
|
-
bg-white dark:bg-gray-800
|
|
285
|
-
rounded-xl shadow-soft
|
|
286
|
-
border border-gray-200 dark:border-gray-700
|
|
287
|
-
${hoverable ? "hover:shadow-lg hover:-translate-y-1 transition-all duration-200" : ""}
|
|
288
|
-
${className}
|
|
289
|
-
`}
|
|
290
|
-
>
|
|
291
|
-
{children}
|
|
292
|
-
</div>
|
|
293
|
-
);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export function CardHeader({ children, className }: { children: React.ReactNode; className?: string }) {
|
|
297
|
-
return (
|
|
298
|
-
<div className={`px-6 py-4 border-b border-gray-200 dark:border-gray-700 ${className}`}>
|
|
299
|
-
{children}
|
|
300
|
-
</div>
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
export function CardContent({ children, className }: { children: React.ReactNode; className?: string }) {
|
|
305
|
-
return <div className={`px-6 py-4 ${className}`}>{children}</div>;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
export function CardFooter({ children, className }: { children: React.ReactNode; className?: string }) {
|
|
309
|
-
return (
|
|
310
|
-
<div className={`px-6 py-4 border-t border-gray-200 dark:border-gray-700 ${className}`}>
|
|
311
|
-
{children}
|
|
312
|
-
</div>
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Input component
|
|
317
|
-
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
318
|
-
label?: string;
|
|
319
|
-
error?: string;
|
|
320
|
-
hint?: string;
|
|
321
|
-
}
|
|
29
|
+
## Features
|
|
322
30
|
|
|
323
|
-
|
|
324
|
-
|
|
31
|
+
| Feature | Description | Guide |
|
|
32
|
+
|---------|-------------|-------|
|
|
33
|
+
| Configuration | Extend colors, fonts, spacing, animations | `ref/config.md` |
|
|
34
|
+
| Responsive Design | Mobile-first breakpoints: sm, md, lg, xl, 2xl | `ref/responsive.md` |
|
|
35
|
+
| Dark Mode | Class-based dark mode with `dark:` prefix | `ref/dark-mode.md` |
|
|
36
|
+
| Custom Animations | Define keyframes and animation utilities | `ref/animations.md` |
|
|
37
|
+
| CSS Variables | Theme with CSS custom properties | `ref/theming.md` |
|
|
38
|
+
| Plugins | @tailwindcss/forms, typography, container-queries | `ref/plugins.md` |
|
|
325
39
|
|
|
326
|
-
|
|
327
|
-
<div className="space-y-1">
|
|
328
|
-
{label && (
|
|
329
|
-
<label
|
|
330
|
-
htmlFor={inputId}
|
|
331
|
-
className="block text-sm font-medium text-gray-700 dark:text-gray-300"
|
|
332
|
-
>
|
|
333
|
-
{label}
|
|
334
|
-
{props.required && <span className="text-red-500 ml-1">*</span>}
|
|
335
|
-
</label>
|
|
336
|
-
)}
|
|
337
|
-
<input
|
|
338
|
-
id={inputId}
|
|
339
|
-
className={`
|
|
340
|
-
w-full px-4 py-2
|
|
341
|
-
border rounded-lg
|
|
342
|
-
bg-white dark:bg-gray-800
|
|
343
|
-
text-gray-900 dark:text-gray-100
|
|
344
|
-
placeholder-gray-400 dark:placeholder-gray-500
|
|
345
|
-
transition-colors duration-200
|
|
346
|
-
focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent
|
|
347
|
-
disabled:bg-gray-100 disabled:cursor-not-allowed
|
|
348
|
-
${error
|
|
349
|
-
? "border-red-500 focus:ring-red-500"
|
|
350
|
-
: "border-gray-300 dark:border-gray-600"
|
|
351
|
-
}
|
|
352
|
-
${className}
|
|
353
|
-
`}
|
|
354
|
-
{...props}
|
|
355
|
-
/>
|
|
356
|
-
{hint && !error && (
|
|
357
|
-
<p className="text-sm text-gray-500 dark:text-gray-400">{hint}</p>
|
|
358
|
-
)}
|
|
359
|
-
{error && (
|
|
360
|
-
<p className="text-sm text-red-500 dark:text-red-400">{error}</p>
|
|
361
|
-
)}
|
|
362
|
-
</div>
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
```
|
|
40
|
+
## Common Patterns
|
|
366
41
|
|
|
367
|
-
###
|
|
42
|
+
### Responsive Card Grid
|
|
368
43
|
|
|
369
44
|
```tsx
|
|
370
|
-
|
|
371
|
-
export function ResponsiveGrid({ children }: { children: React.ReactNode }) {
|
|
45
|
+
export function CardGrid({ children }: { children: React.ReactNode }) {
|
|
372
46
|
return (
|
|
373
47
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
|
|
374
48
|
{children}
|
|
@@ -376,473 +50,71 @@ export function ResponsiveGrid({ children }: { children: React.ReactNode }) {
|
|
|
376
50
|
);
|
|
377
51
|
}
|
|
378
52
|
|
|
379
|
-
|
|
380
|
-
export function Navigation() {
|
|
381
|
-
return (
|
|
382
|
-
<nav className="bg-white dark:bg-gray-900 shadow-sm">
|
|
383
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
384
|
-
<div className="flex justify-between h-16">
|
|
385
|
-
{/* Logo */}
|
|
386
|
-
<div className="flex-shrink-0 flex items-center">
|
|
387
|
-
<Logo className="h-8 w-auto" />
|
|
388
|
-
</div>
|
|
389
|
-
|
|
390
|
-
{/* Desktop navigation */}
|
|
391
|
-
<div className="hidden md:flex md:items-center md:space-x-8">
|
|
392
|
-
<NavLink href="/">Home</NavLink>
|
|
393
|
-
<NavLink href="/products">Products</NavLink>
|
|
394
|
-
<NavLink href="/about">About</NavLink>
|
|
395
|
-
<NavLink href="/contact">Contact</NavLink>
|
|
396
|
-
</div>
|
|
397
|
-
|
|
398
|
-
{/* Mobile menu button */}
|
|
399
|
-
<div className="flex items-center md:hidden">
|
|
400
|
-
<button
|
|
401
|
-
className="
|
|
402
|
-
inline-flex items-center justify-center
|
|
403
|
-
p-2 rounded-md
|
|
404
|
-
text-gray-400 hover:text-gray-500 hover:bg-gray-100
|
|
405
|
-
focus:outline-none focus:ring-2 focus:ring-inset focus:ring-primary-500
|
|
406
|
-
"
|
|
407
|
-
>
|
|
408
|
-
<span className="sr-only">Open main menu</span>
|
|
409
|
-
<MenuIcon className="h-6 w-6" />
|
|
410
|
-
</button>
|
|
411
|
-
</div>
|
|
412
|
-
</div>
|
|
413
|
-
</div>
|
|
414
|
-
|
|
415
|
-
{/* Mobile menu */}
|
|
416
|
-
<div className="md:hidden">
|
|
417
|
-
<div className="px-2 pt-2 pb-3 space-y-1">
|
|
418
|
-
<MobileNavLink href="/">Home</MobileNavLink>
|
|
419
|
-
<MobileNavLink href="/products">Products</MobileNavLink>
|
|
420
|
-
<MobileNavLink href="/about">About</MobileNavLink>
|
|
421
|
-
<MobileNavLink href="/contact">Contact</MobileNavLink>
|
|
422
|
-
</div>
|
|
423
|
-
</div>
|
|
424
|
-
</nav>
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Responsive hero section
|
|
429
|
-
export function Hero() {
|
|
53
|
+
export function Card({ children, hoverable }: { children: React.ReactNode; hoverable?: boolean }) {
|
|
430
54
|
return (
|
|
431
|
-
<
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
{/* Responsive typography */}
|
|
438
|
-
<h1 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-white tracking-tight">
|
|
439
|
-
Build amazing products
|
|
440
|
-
<span className="block text-primary-300 mt-2">with confidence</span>
|
|
441
|
-
</h1>
|
|
442
|
-
|
|
443
|
-
<p className="mt-6 text-lg sm:text-xl text-gray-300 max-w-xl mx-auto lg:mx-0">
|
|
444
|
-
Start building your next project with our comprehensive component
|
|
445
|
-
library and design system.
|
|
446
|
-
</p>
|
|
447
|
-
|
|
448
|
-
{/* Responsive button layout */}
|
|
449
|
-
<div className="mt-10 flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
|
|
450
|
-
<Button size="lg" className="w-full sm:w-auto">
|
|
451
|
-
Get Started
|
|
452
|
-
</Button>
|
|
453
|
-
<Button variant="outline" size="lg" className="w-full sm:w-auto">
|
|
454
|
-
Learn More
|
|
455
|
-
</Button>
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
459
|
-
</section>
|
|
55
|
+
<div className={cn(
|
|
56
|
+
'bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-6',
|
|
57
|
+
hoverable && 'hover:shadow-lg hover:-translate-y-1 transition-all duration-200'
|
|
58
|
+
)}>
|
|
59
|
+
{children}
|
|
60
|
+
</div>
|
|
460
61
|
);
|
|
461
62
|
}
|
|
462
63
|
```
|
|
463
64
|
|
|
464
|
-
###
|
|
65
|
+
### Dark Mode Toggle
|
|
465
66
|
|
|
466
67
|
```tsx
|
|
467
|
-
// Dark mode toggle
|
|
468
|
-
import { useEffect, useState } from "react";
|
|
469
|
-
|
|
470
68
|
export function DarkModeToggle() {
|
|
471
69
|
const [isDark, setIsDark] = useState(false);
|
|
472
70
|
|
|
473
71
|
useEffect(() => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
window.matchMedia("(prefers-color-scheme: dark)").matches);
|
|
479
|
-
setIsDark(isDarkMode);
|
|
480
|
-
document.documentElement.classList.toggle("dark", isDarkMode);
|
|
72
|
+
const dark = localStorage.theme === 'dark' ||
|
|
73
|
+
(!localStorage.theme && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
74
|
+
setIsDark(dark);
|
|
75
|
+
document.documentElement.classList.toggle('dark', dark);
|
|
481
76
|
}, []);
|
|
482
77
|
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
localStorage.setItem("theme", newIsDark ? "dark" : "light");
|
|
78
|
+
const toggle = () => {
|
|
79
|
+
setIsDark(!isDark);
|
|
80
|
+
document.documentElement.classList.toggle('dark', !isDark);
|
|
81
|
+
localStorage.theme = !isDark ? 'dark' : 'light';
|
|
488
82
|
};
|
|
489
83
|
|
|
490
84
|
return (
|
|
491
|
-
<button
|
|
492
|
-
|
|
493
|
-
className="
|
|
494
|
-
p-2 rounded-lg
|
|
495
|
-
text-gray-500 hover:text-gray-700
|
|
496
|
-
dark:text-gray-400 dark:hover:text-gray-200
|
|
497
|
-
hover:bg-gray-100 dark:hover:bg-gray-800
|
|
498
|
-
transition-colors duration-200
|
|
499
|
-
"
|
|
500
|
-
aria-label={isDark ? "Switch to light mode" : "Switch to dark mode"}
|
|
501
|
-
>
|
|
502
|
-
{isDark ? (
|
|
503
|
-
<SunIcon className="h-5 w-5" />
|
|
504
|
-
) : (
|
|
505
|
-
<MoonIcon className="h-5 w-5" />
|
|
506
|
-
)}
|
|
85
|
+
<button onClick={toggle} className="p-2 rounded-lg text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800">
|
|
86
|
+
{isDark ? <SunIcon className="h-5 w-5" /> : <MoonIcon className="h-5 w-5" />}
|
|
507
87
|
</button>
|
|
508
88
|
);
|
|
509
89
|
}
|
|
510
|
-
|
|
511
|
-
// Dark mode aware components
|
|
512
|
-
export function DarkModeCard({ title, description }: { title: string; description: string }) {
|
|
513
|
-
return (
|
|
514
|
-
<div
|
|
515
|
-
className="
|
|
516
|
-
p-6 rounded-xl
|
|
517
|
-
bg-white dark:bg-gray-800
|
|
518
|
-
border border-gray-200 dark:border-gray-700
|
|
519
|
-
shadow-sm hover:shadow-md
|
|
520
|
-
transition-shadow duration-200
|
|
521
|
-
"
|
|
522
|
-
>
|
|
523
|
-
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
524
|
-
{title}
|
|
525
|
-
</h3>
|
|
526
|
-
<p className="mt-2 text-gray-600 dark:text-gray-300">
|
|
527
|
-
{description}
|
|
528
|
-
</p>
|
|
529
|
-
</div>
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
90
|
```
|
|
533
91
|
|
|
534
|
-
###
|
|
92
|
+
### Conditional Classes with cn()
|
|
535
93
|
|
|
536
94
|
```tsx
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return (
|
|
540
|
-
<div
|
|
541
|
-
className="animate-slide-up opacity-0"
|
|
542
|
-
style={{
|
|
543
|
-
animationDelay: `${delay}ms`,
|
|
544
|
-
animationFillMode: "forwards",
|
|
545
|
-
}}
|
|
546
|
-
>
|
|
547
|
-
{children}
|
|
548
|
-
</div>
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Hover animations
|
|
553
|
-
export function HoverCard({ children }: { children: React.ReactNode }) {
|
|
554
|
-
return (
|
|
555
|
-
<div
|
|
556
|
-
className="
|
|
557
|
-
group
|
|
558
|
-
relative
|
|
559
|
-
bg-white dark:bg-gray-800
|
|
560
|
-
rounded-xl shadow-sm
|
|
561
|
-
transition-all duration-300
|
|
562
|
-
hover:shadow-xl hover:-translate-y-2
|
|
563
|
-
cursor-pointer
|
|
564
|
-
"
|
|
565
|
-
>
|
|
566
|
-
{/* Gradient overlay on hover */}
|
|
567
|
-
<div
|
|
568
|
-
className="
|
|
569
|
-
absolute inset-0 rounded-xl
|
|
570
|
-
bg-gradient-to-br from-primary-500/0 to-primary-500/0
|
|
571
|
-
group-hover:from-primary-500/5 group-hover:to-primary-500/10
|
|
572
|
-
transition-all duration-300
|
|
573
|
-
"
|
|
574
|
-
/>
|
|
575
|
-
<div className="relative z-10">{children}</div>
|
|
576
|
-
</div>
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
// Loading skeleton
|
|
581
|
-
export function Skeleton({ className }: { className?: string }) {
|
|
582
|
-
return (
|
|
583
|
-
<div
|
|
584
|
-
className={`
|
|
585
|
-
animate-pulse
|
|
586
|
-
bg-gray-200 dark:bg-gray-700
|
|
587
|
-
rounded
|
|
588
|
-
${className}
|
|
589
|
-
`}
|
|
590
|
-
/>
|
|
591
|
-
);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
export function CardSkeleton() {
|
|
595
|
-
return (
|
|
596
|
-
<div className="p-6 bg-white dark:bg-gray-800 rounded-xl">
|
|
597
|
-
<Skeleton className="h-6 w-3/4 mb-4" />
|
|
598
|
-
<Skeleton className="h-4 w-full mb-2" />
|
|
599
|
-
<Skeleton className="h-4 w-5/6 mb-2" />
|
|
600
|
-
<Skeleton className="h-4 w-4/6" />
|
|
601
|
-
<div className="mt-6 flex gap-2">
|
|
602
|
-
<Skeleton className="h-10 w-24" />
|
|
603
|
-
<Skeleton className="h-10 w-24" />
|
|
604
|
-
</div>
|
|
605
|
-
</div>
|
|
606
|
-
);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// Transition group
|
|
610
|
-
export function FadeTransition({ show, children }: { show: boolean; children: React.ReactNode }) {
|
|
611
|
-
return (
|
|
612
|
-
<div
|
|
613
|
-
className={`
|
|
614
|
-
transition-all duration-300 ease-in-out
|
|
615
|
-
${show ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-4 pointer-events-none"}
|
|
616
|
-
`}
|
|
617
|
-
>
|
|
618
|
-
{children}
|
|
619
|
-
</div>
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
### 6. Utility Class Patterns
|
|
625
|
-
|
|
626
|
-
```tsx
|
|
627
|
-
// Using clsx/cn for conditional classes
|
|
628
|
-
import { clsx, type ClassValue } from "clsx";
|
|
629
|
-
import { twMerge } from "tailwind-merge";
|
|
95
|
+
import { clsx, type ClassValue } from 'clsx';
|
|
96
|
+
import { twMerge } from 'tailwind-merge';
|
|
630
97
|
|
|
631
98
|
export function cn(...inputs: ClassValue[]) {
|
|
632
99
|
return twMerge(clsx(inputs));
|
|
633
100
|
}
|
|
634
101
|
|
|
635
102
|
// Usage
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
export function Badge({ variant = "default", children, className }: BadgeProps) {
|
|
643
|
-
return (
|
|
644
|
-
<span
|
|
645
|
-
className={cn(
|
|
646
|
-
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium",
|
|
647
|
-
{
|
|
648
|
-
"bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200":
|
|
649
|
-
variant === "default",
|
|
650
|
-
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":
|
|
651
|
-
variant === "success",
|
|
652
|
-
"bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200":
|
|
653
|
-
variant === "warning",
|
|
654
|
-
"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200":
|
|
655
|
-
variant === "error",
|
|
656
|
-
},
|
|
657
|
-
className
|
|
658
|
-
)}
|
|
659
|
-
>
|
|
660
|
-
{children}
|
|
661
|
-
</span>
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Responsive spacing utility
|
|
666
|
-
export function Stack({
|
|
667
|
-
children,
|
|
668
|
-
spacing = "md",
|
|
669
|
-
direction = "vertical",
|
|
670
|
-
}: {
|
|
671
|
-
children: React.ReactNode;
|
|
672
|
-
spacing?: "sm" | "md" | "lg";
|
|
673
|
-
direction?: "vertical" | "horizontal";
|
|
674
|
-
}) {
|
|
675
|
-
const spacingClasses = {
|
|
676
|
-
sm: direction === "vertical" ? "space-y-2" : "space-x-2",
|
|
677
|
-
md: direction === "vertical" ? "space-y-4" : "space-x-4",
|
|
678
|
-
lg: direction === "vertical" ? "space-y-6" : "space-x-6",
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
return (
|
|
682
|
-
<div
|
|
683
|
-
className={cn(
|
|
684
|
-
direction === "horizontal" && "flex items-center",
|
|
685
|
-
spacingClasses[spacing]
|
|
686
|
-
)}
|
|
687
|
-
>
|
|
688
|
-
{children}
|
|
689
|
-
</div>
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
### 7. Form Patterns
|
|
695
|
-
|
|
696
|
-
```tsx
|
|
697
|
-
// Complete form example
|
|
698
|
-
export function ContactForm() {
|
|
699
|
-
return (
|
|
700
|
-
<form className="space-y-6">
|
|
701
|
-
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
|
702
|
-
<Input
|
|
703
|
-
label="First Name"
|
|
704
|
-
name="firstName"
|
|
705
|
-
placeholder="John"
|
|
706
|
-
required
|
|
707
|
-
/>
|
|
708
|
-
<Input
|
|
709
|
-
label="Last Name"
|
|
710
|
-
name="lastName"
|
|
711
|
-
placeholder="Doe"
|
|
712
|
-
required
|
|
713
|
-
/>
|
|
714
|
-
</div>
|
|
715
|
-
|
|
716
|
-
<Input
|
|
717
|
-
label="Email"
|
|
718
|
-
name="email"
|
|
719
|
-
type="email"
|
|
720
|
-
placeholder="john@example.com"
|
|
721
|
-
required
|
|
722
|
-
/>
|
|
723
|
-
|
|
724
|
-
<div className="space-y-1">
|
|
725
|
-
<label
|
|
726
|
-
htmlFor="message"
|
|
727
|
-
className="block text-sm font-medium text-gray-700 dark:text-gray-300"
|
|
728
|
-
>
|
|
729
|
-
Message
|
|
730
|
-
</label>
|
|
731
|
-
<textarea
|
|
732
|
-
id="message"
|
|
733
|
-
name="message"
|
|
734
|
-
rows={4}
|
|
735
|
-
className="
|
|
736
|
-
w-full px-4 py-2
|
|
737
|
-
border border-gray-300 dark:border-gray-600
|
|
738
|
-
rounded-lg
|
|
739
|
-
bg-white dark:bg-gray-800
|
|
740
|
-
text-gray-900 dark:text-gray-100
|
|
741
|
-
placeholder-gray-400 dark:placeholder-gray-500
|
|
742
|
-
focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent
|
|
743
|
-
resize-none
|
|
744
|
-
"
|
|
745
|
-
placeholder="Your message..."
|
|
746
|
-
/>
|
|
747
|
-
</div>
|
|
748
|
-
|
|
749
|
-
<div className="flex items-center">
|
|
750
|
-
<input
|
|
751
|
-
id="terms"
|
|
752
|
-
name="terms"
|
|
753
|
-
type="checkbox"
|
|
754
|
-
className="
|
|
755
|
-
h-4 w-4
|
|
756
|
-
rounded
|
|
757
|
-
border-gray-300
|
|
758
|
-
text-primary-600
|
|
759
|
-
focus:ring-primary-500
|
|
760
|
-
"
|
|
761
|
-
/>
|
|
762
|
-
<label
|
|
763
|
-
htmlFor="terms"
|
|
764
|
-
className="ml-2 text-sm text-gray-600 dark:text-gray-400"
|
|
765
|
-
>
|
|
766
|
-
I agree to the{" "}
|
|
767
|
-
<a href="/terms" className="text-primary-600 hover:underline">
|
|
768
|
-
terms and conditions
|
|
769
|
-
</a>
|
|
770
|
-
</label>
|
|
771
|
-
</div>
|
|
772
|
-
|
|
773
|
-
<Button type="submit" className="w-full sm:w-auto">
|
|
774
|
-
Send Message
|
|
775
|
-
</Button>
|
|
776
|
-
</form>
|
|
777
|
-
);
|
|
778
|
-
}
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
## Use Cases
|
|
782
|
-
|
|
783
|
-
### Responsive Dashboard Layout
|
|
784
|
-
|
|
785
|
-
```tsx
|
|
786
|
-
export function DashboardLayout({ children }: { children: React.ReactNode }) {
|
|
787
|
-
return (
|
|
788
|
-
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
789
|
-
{/* Sidebar */}
|
|
790
|
-
<aside
|
|
791
|
-
className="
|
|
792
|
-
fixed inset-y-0 left-0
|
|
793
|
-
z-50 w-64
|
|
794
|
-
bg-white dark:bg-gray-800
|
|
795
|
-
border-r border-gray-200 dark:border-gray-700
|
|
796
|
-
transform -translate-x-full lg:translate-x-0
|
|
797
|
-
transition-transform duration-300
|
|
798
|
-
"
|
|
799
|
-
>
|
|
800
|
-
{/* Sidebar content */}
|
|
801
|
-
</aside>
|
|
802
|
-
|
|
803
|
-
{/* Main content */}
|
|
804
|
-
<main className="lg:pl-64">
|
|
805
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
806
|
-
{children}
|
|
807
|
-
</div>
|
|
808
|
-
</main>
|
|
809
|
-
</div>
|
|
810
|
-
);
|
|
811
|
-
}
|
|
103
|
+
<div className={cn(
|
|
104
|
+
'px-4 py-2 rounded-lg',
|
|
105
|
+
isActive && 'bg-blue-500 text-white',
|
|
106
|
+
isDisabled && 'opacity-50 cursor-not-allowed',
|
|
107
|
+
className
|
|
108
|
+
)} />
|
|
812
109
|
```
|
|
813
110
|
|
|
814
111
|
## Best Practices
|
|
815
112
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
- Configure purge/content correctly
|
|
825
|
-
- Use semantic class grouping
|
|
826
|
-
- Optimize for production build
|
|
827
|
-
- Follow consistent spacing scales
|
|
828
|
-
|
|
829
|
-
### Don'ts
|
|
830
|
-
|
|
831
|
-
- Don't overuse @apply
|
|
832
|
-
- Don't create overly specific utilities
|
|
833
|
-
- Don't ignore accessibility
|
|
834
|
-
- Don't repeat complex class combinations
|
|
835
|
-
- Don't hardcode colors outside theme
|
|
836
|
-
- Don't skip responsive testing
|
|
837
|
-
- Don't forget dark mode variants
|
|
838
|
-
- Don't use arbitrary values excessively
|
|
839
|
-
- Don't ignore the configuration file
|
|
840
|
-
- Don't mix styling paradigms
|
|
841
|
-
|
|
842
|
-
## References
|
|
843
|
-
|
|
844
|
-
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
|
|
845
|
-
- [Tailwind UI](https://tailwindui.com/)
|
|
846
|
-
- [Headless UI](https://headlessui.com/)
|
|
847
|
-
- [Tailwind CSS Best Practices](https://tailwindcss.com/docs/reusing-styles)
|
|
848
|
-
- [Tailwind CSS Plugins](https://tailwindcss.com/docs/plugins)
|
|
113
|
+
| Do | Avoid |
|
|
114
|
+
|----|-------|
|
|
115
|
+
| Use mobile-first responsive design | Overusing @apply (prefer utilities) |
|
|
116
|
+
| Leverage `cn()` for conditional classes | Hardcoding colors outside theme |
|
|
117
|
+
| Configure content paths for purging | Using arbitrary values excessively |
|
|
118
|
+
| Use CSS variables for theming | Mixing styling paradigms |
|
|
119
|
+
| Group related utilities semantically | Skipping dark mode variants |
|
|
120
|
+
| Use consistent spacing scales | Ignoring responsive testing |
|