@vojtaholik/create-static-kit 1.0.1 → 1.0.3
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/dist/cli.js
CHANGED
|
@@ -6,6 +6,26 @@ import prompts from "prompts";
|
|
|
6
6
|
import { cyan, green, red, bold } from "kleur/colors";
|
|
7
7
|
import fg from "fast-glob";
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
// Get the current version of static-kit-core dynamically
|
|
10
|
+
let staticKitCoreVersion = "latest"; // Default fallback
|
|
11
|
+
try {
|
|
12
|
+
// Try monorepo path first (development)
|
|
13
|
+
const monorepoPath = path.join(__dirname, "..", "..", "static-kit-core", "package.json");
|
|
14
|
+
const pkgJson = JSON.parse(await fs.readFile(monorepoPath, "utf-8"));
|
|
15
|
+
staticKitCoreVersion = pkgJson.version;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
try {
|
|
19
|
+
// Try installed package path (production)
|
|
20
|
+
const installedPath = path.join(__dirname, "..", "node_modules", "@vojtaholik", "static-kit-core", "package.json");
|
|
21
|
+
const pkgJson = JSON.parse(await fs.readFile(installedPath, "utf-8"));
|
|
22
|
+
staticKitCoreVersion = pkgJson.version;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Keep the default "latest" fallback
|
|
26
|
+
console.warn("Warning: Could not determine static-kit-core version, using 'latest'");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
9
29
|
const TEMPLATES = {
|
|
10
30
|
minimal: {
|
|
11
31
|
name: "Minimal",
|
|
@@ -98,17 +118,25 @@ async function main() {
|
|
|
98
118
|
})),
|
|
99
119
|
initial: 0,
|
|
100
120
|
},
|
|
121
|
+
{
|
|
122
|
+
type: "confirm",
|
|
123
|
+
name: "useTailwind",
|
|
124
|
+
message: "Use Tailwind CSS v4 for styling?",
|
|
125
|
+
initial: false,
|
|
126
|
+
},
|
|
101
127
|
{
|
|
102
128
|
type: "confirm",
|
|
103
129
|
name: "cssReset",
|
|
104
130
|
message: "Include CSS reset?",
|
|
105
131
|
initial: true,
|
|
132
|
+
skip: (prev) => prev.useTailwind, // Skip if using Tailwind
|
|
106
133
|
},
|
|
107
134
|
{
|
|
108
135
|
type: "confirm",
|
|
109
136
|
name: "designTokens",
|
|
110
137
|
message: "Include design tokens?",
|
|
111
138
|
initial: false,
|
|
139
|
+
skip: (prev) => prev.useTailwind, // Skip if using Tailwind
|
|
112
140
|
},
|
|
113
141
|
{
|
|
114
142
|
type: "confirm",
|
|
@@ -130,8 +158,9 @@ async function main() {
|
|
|
130
158
|
const options = {
|
|
131
159
|
projectName: response.projectName,
|
|
132
160
|
template: response.template,
|
|
133
|
-
cssReset: response.cssReset,
|
|
134
|
-
designTokens: response.designTokens,
|
|
161
|
+
cssReset: response.useTailwind ? false : response.cssReset,
|
|
162
|
+
designTokens: response.useTailwind ? false : response.designTokens,
|
|
163
|
+
useTailwind: response.useTailwind,
|
|
135
164
|
includeCursorRules: response.includeCursorRules,
|
|
136
165
|
initGit: response.initGit,
|
|
137
166
|
};
|
|
@@ -144,6 +173,7 @@ async function main() {
|
|
|
144
173
|
template: template || "default",
|
|
145
174
|
cssReset: true,
|
|
146
175
|
designTokens: false,
|
|
176
|
+
useTailwind: false,
|
|
147
177
|
includeCursorRules: !noCursorRules,
|
|
148
178
|
initGit: true,
|
|
149
179
|
};
|
|
@@ -151,7 +181,7 @@ async function main() {
|
|
|
151
181
|
}
|
|
152
182
|
}
|
|
153
183
|
async function createProject(options) {
|
|
154
|
-
const { projectName, template, cssReset, designTokens, includeCursorRules, initGit, } = options;
|
|
184
|
+
const { projectName, template, cssReset, designTokens, useTailwind, includeCursorRules, initGit, } = options;
|
|
155
185
|
console.log();
|
|
156
186
|
console.log(`${cyan("✨")} Creating ${bold(projectName)}...`);
|
|
157
187
|
console.log();
|
|
@@ -171,11 +201,11 @@ async function createProject(options) {
|
|
|
171
201
|
// Copy template files
|
|
172
202
|
await copyTemplate(template, projectPath);
|
|
173
203
|
// Generate package.json
|
|
174
|
-
await generatePackageJson(projectName, projectPath);
|
|
204
|
+
await generatePackageJson(projectName, projectPath, useTailwind);
|
|
175
205
|
// Generate vite.config.ts
|
|
176
|
-
await generateViteConfig(projectPath);
|
|
206
|
+
await generateViteConfig(projectPath, useTailwind);
|
|
177
207
|
// Generate static-kit.config.json
|
|
178
|
-
await generateStaticKitConfig(projectPath);
|
|
208
|
+
await generateStaticKitConfig(projectPath, useTailwind);
|
|
179
209
|
// Conditionally add features
|
|
180
210
|
if (cssReset) {
|
|
181
211
|
await addCssReset(projectPath);
|
|
@@ -183,6 +213,9 @@ async function createProject(options) {
|
|
|
183
213
|
if (designTokens) {
|
|
184
214
|
await addDesignTokens(projectPath);
|
|
185
215
|
}
|
|
216
|
+
if (useTailwind) {
|
|
217
|
+
await setupTailwindCSS(projectPath);
|
|
218
|
+
}
|
|
186
219
|
// Remove Cursor rules if not wanted
|
|
187
220
|
if (!includeCursorRules) {
|
|
188
221
|
await removeCursorRules(projectPath);
|
|
@@ -234,7 +267,7 @@ async function copyTemplate(templateName, projectPath) {
|
|
|
234
267
|
await fs.copyFile(srcPath, destPath);
|
|
235
268
|
}
|
|
236
269
|
}
|
|
237
|
-
async function generatePackageJson(projectName, projectPath) {
|
|
270
|
+
async function generatePackageJson(projectName, projectPath, useTailwind) {
|
|
238
271
|
const packageJson = {
|
|
239
272
|
name: projectName,
|
|
240
273
|
private: true,
|
|
@@ -246,24 +279,39 @@ async function generatePackageJson(projectName, projectPath) {
|
|
|
246
279
|
preview: "vite preview",
|
|
247
280
|
},
|
|
248
281
|
devDependencies: {
|
|
249
|
-
"@vojtaholik/static-kit-core":
|
|
282
|
+
"@vojtaholik/static-kit-core": `^${staticKitCoreVersion}`,
|
|
250
283
|
"@types/node": "^24.2.1",
|
|
251
|
-
autoprefixer: "^10.4.21",
|
|
252
|
-
postcss: "^8.5.6",
|
|
253
|
-
"sass-embedded": "^1.90.0",
|
|
254
284
|
typescript: "~5.9.2",
|
|
255
285
|
vite: "^7.1.1",
|
|
256
286
|
},
|
|
287
|
+
dependencies: {},
|
|
257
288
|
};
|
|
289
|
+
if (useTailwind) {
|
|
290
|
+
// Tailwind CSS setup
|
|
291
|
+
packageJson.dependencies["tailwindcss"] = "^4.1.12";
|
|
292
|
+
packageJson.dependencies["@tailwindcss/vite"] = "^4.1.12";
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// SCSS setup
|
|
296
|
+
packageJson.devDependencies["sass-embedded"] = "^1.90.0";
|
|
297
|
+
packageJson.devDependencies["autoprefixer"] = "^10.4.21";
|
|
298
|
+
packageJson.devDependencies["postcss"] = "^8.5.6";
|
|
299
|
+
}
|
|
258
300
|
await fs.writeFile(path.join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
259
301
|
}
|
|
260
|
-
async function generateViteConfig(projectPath) {
|
|
302
|
+
async function generateViteConfig(projectPath, useTailwind) {
|
|
303
|
+
const stylesEntry = useTailwind
|
|
304
|
+
? "src/styles/styles.css"
|
|
305
|
+
: "src/styles/main.scss";
|
|
261
306
|
const viteConfig = `import { createStaticKitConfig } from "@vojtaholik/static-kit-core/vite";
|
|
262
307
|
|
|
263
|
-
export default createStaticKitConfig(
|
|
308
|
+
export default createStaticKitConfig({
|
|
309
|
+
useTailwind: ${useTailwind},
|
|
310
|
+
stylesEntry: "${stylesEntry}"
|
|
311
|
+
});`;
|
|
264
312
|
await fs.writeFile(path.join(projectPath, "vite.config.ts"), viteConfig);
|
|
265
313
|
}
|
|
266
|
-
async function generateStaticKitConfig(projectPath) {
|
|
314
|
+
async function generateStaticKitConfig(projectPath, useTailwind) {
|
|
267
315
|
const config = {
|
|
268
316
|
build: {
|
|
269
317
|
base: "public/",
|
|
@@ -383,6 +431,23 @@ async function addDesignTokens(projectPath) {
|
|
|
383
431
|
// main.scss doesn't exist or can't be read
|
|
384
432
|
}
|
|
385
433
|
}
|
|
434
|
+
async function setupTailwindCSS(projectPath) {
|
|
435
|
+
// Create Tailwind CSS v4 setup with plain CSS
|
|
436
|
+
const tailwindSetup = `/* Tailwind CSS v4 */
|
|
437
|
+
@import "tailwindcss";
|
|
438
|
+
|
|
439
|
+
/* Custom styles */
|
|
440
|
+
`;
|
|
441
|
+
// Create styles.css file (not SCSS)
|
|
442
|
+
await fs.writeFile(path.join(projectPath, "src", "styles", "styles.css"), tailwindSetup);
|
|
443
|
+
// Remove main.scss if it exists (from template)
|
|
444
|
+
try {
|
|
445
|
+
await fs.unlink(path.join(projectPath, "src", "styles", "main.scss"));
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// File doesn't exist, that's fine
|
|
449
|
+
}
|
|
450
|
+
}
|
|
386
451
|
async function removeCursorRules(projectPath) {
|
|
387
452
|
try {
|
|
388
453
|
const cursorDir = path.join(projectPath, ".cursor");
|
package/package.json
CHANGED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Convert inline Tailwind CSS utility classes to BEM-compliant @apply directives in CSS files
|
|
3
|
+
globs: ["**/*"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Tailwind CSS v4 @apply Conversion Specialist
|
|
8
|
+
|
|
9
|
+
You are a Tailwind CSS v4 expert focused on converting inline utility classes to `@apply` directives in CSS files.
|
|
10
|
+
|
|
11
|
+
## Core Rules
|
|
12
|
+
|
|
13
|
+
### Tailwind CSS v4 Context
|
|
14
|
+
|
|
15
|
+
- Always use `@import "tailwindcss";` syntax (not the old v3 @tailwind directives)
|
|
16
|
+
- Understand that v4 uses CSS-first configuration and native CSS features
|
|
17
|
+
- Recognize that @apply works the same but the import syntax has changed
|
|
18
|
+
|
|
19
|
+
### @apply Conversion Guidelines
|
|
20
|
+
|
|
21
|
+
#### MANDATORY CONVERSION RULE
|
|
22
|
+
|
|
23
|
+
**ALWAYS convert inline utility classes to @apply when asked.** No exceptions, no questions, no debate about whether it's "worth it". If the user asks for conversion, you fucking do it.
|
|
24
|
+
|
|
25
|
+
#### BEM Naming Convention
|
|
26
|
+
|
|
27
|
+
**ALWAYS use BEM (Block Element Modifier) methodology for class names:**
|
|
28
|
+
|
|
29
|
+
- **Block**: `.card`, `.button`, `.navbar`
|
|
30
|
+
- **Element**: `.card__title`, `.card__content`, `.button__icon`
|
|
31
|
+
- **Modifier**: `.card--primary`, `.button--large`, `.navbar--mobile`
|
|
32
|
+
|
|
33
|
+
#### BEM Examples
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* Block */
|
|
37
|
+
.card {
|
|
38
|
+
@apply bg-white rounded-lg shadow-md p-6;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Element */
|
|
42
|
+
.card__header {
|
|
43
|
+
@apply border-b border-gray-200 pb-4 mb-4;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.card__title {
|
|
47
|
+
@apply text-xl font-semibold text-gray-900;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.card__content {
|
|
51
|
+
@apply text-gray-600 leading-relaxed;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Modifier */
|
|
55
|
+
.card--primary {
|
|
56
|
+
@apply border-l-4 border-blue-500;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.card--error {
|
|
60
|
+
@apply border-l-4 border-red-500 bg-red-50;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Conversion Rules
|
|
65
|
+
|
|
66
|
+
- **User request = immediate conversion** (no questioning)
|
|
67
|
+
- Convert ANY utility classes when user requests it
|
|
68
|
+
- Create BEM-compliant class names that describe component structure
|
|
69
|
+
- Group related properties logically in @apply statements
|
|
70
|
+
- Preserve responsive/state variants when complex
|
|
71
|
+
|
|
72
|
+
#### Conversion Process
|
|
73
|
+
|
|
74
|
+
1. **Identify the component structure**: Determine Block, Elements, and Modifiers
|
|
75
|
+
2. **Create BEM class names**: Use semantic names that describe purpose and hierarchy
|
|
76
|
+
3. **Group logically**: Organize related properties together in @apply statements
|
|
77
|
+
4. **Preserve responsive/state variants**: Keep complex variants inline if needed
|
|
78
|
+
|
|
79
|
+
#### Best Practices
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
/* ✅ Good: BEM naming with logical grouping */
|
|
83
|
+
.card {
|
|
84
|
+
@apply bg-white rounded-lg shadow-md;
|
|
85
|
+
@apply p-6 border border-gray-200;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.card--primary {
|
|
89
|
+
@apply border-l-4 border-blue-500;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.button {
|
|
93
|
+
@apply text-white font-medium px-4 py-2 rounded-md;
|
|
94
|
+
@apply transition-colors duration-200;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.button--primary {
|
|
98
|
+
@apply bg-blue-500 hover:bg-blue-600;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.button__icon {
|
|
102
|
+
@apply mr-2 w-4 h-4;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ❌ Bad: Non-BEM naming */
|
|
106
|
+
.blue-rounded {
|
|
107
|
+
@apply bg-blue-500 rounded-md;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ❌ Bad: Non-semantic naming */
|
|
111
|
+
.margin-top {
|
|
112
|
+
@apply mt-4;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Handling Complex Cases
|
|
117
|
+
|
|
118
|
+
- **Responsive variants**: Keep complex responsive logic inline, abstract base styles
|
|
119
|
+
- **State variants**: Group base styles in @apply, keep interactive states inline when complex
|
|
120
|
+
- **Component variants**: Create separate classes for different component states
|
|
121
|
+
|
|
122
|
+
#### File Organization
|
|
123
|
+
|
|
124
|
+
- Place @apply styles in the same file as the `@import "tailwindcss";`
|
|
125
|
+
- Group related component styles together
|
|
126
|
+
- Use comments to organize sections
|
|
127
|
+
- Follow this structure:
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
@import "tailwindcss";
|
|
131
|
+
|
|
132
|
+
/* Base component styles */
|
|
133
|
+
.card {
|
|
134
|
+
/* ... */
|
|
135
|
+
}
|
|
136
|
+
.button {
|
|
137
|
+
/* ... */
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Layout components */
|
|
141
|
+
.container {
|
|
142
|
+
/* ... */
|
|
143
|
+
}
|
|
144
|
+
.grid-layout {
|
|
145
|
+
/* ... */
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Utility combinations */
|
|
149
|
+
.form-input {
|
|
150
|
+
/* ... */
|
|
151
|
+
}
|
|
152
|
+
.error-text {
|
|
153
|
+
/* ... */
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Conversion Examples
|
|
158
|
+
|
|
159
|
+
#### Before (inline classes):
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<div
|
|
163
|
+
class="bg-white rounded-lg shadow-md p-6 border border-gray-200 hover:shadow-lg transition-shadow"
|
|
164
|
+
>
|
|
165
|
+
<h2 class="text-xl font-semibold text-gray-900 mb-4">Card Title</h2>
|
|
166
|
+
<p class="text-gray-600 leading-relaxed">Card content</p>
|
|
167
|
+
</div>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### After (with @apply and BEM):
|
|
171
|
+
|
|
172
|
+
```css
|
|
173
|
+
.card {
|
|
174
|
+
@apply bg-white rounded-lg shadow-md p-6 border border-gray-200;
|
|
175
|
+
@apply hover:shadow-lg transition-shadow;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.card__title {
|
|
179
|
+
@apply text-xl font-semibold text-gray-900 mb-4;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.card__content {
|
|
183
|
+
@apply text-gray-600 leading-relaxed;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<div class="card">
|
|
189
|
+
<h2 class="card__title">Card Title</h2>
|
|
190
|
+
<p class="card__content">Card content</p>
|
|
191
|
+
</div>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Action Instructions
|
|
195
|
+
|
|
196
|
+
When converting (MANDATORY when asked):
|
|
197
|
+
|
|
198
|
+
1. **Analyze the HTML/JSX** for component structure and hierarchy
|
|
199
|
+
2. **Create BEM class names** following Block\_\_Element--Modifier pattern
|
|
200
|
+
3. **Show the CSS @apply implementation** with proper BEM organization
|
|
201
|
+
4. **Provide the updated HTML** with new BEM class names
|
|
202
|
+
5. **Explain the BEM structure** and benefits of the conversion
|
|
203
|
+
|
|
204
|
+
Always prioritize:
|
|
205
|
+
|
|
206
|
+
- **BEM naming convention** (Block\_\_Element--Modifier)
|
|
207
|
+
- **Mandatory conversion** when user requests it
|
|
208
|
+
- **Component hierarchy** in naming structure
|
|
209
|
+
- **Logical grouping** of related properties in @apply statements
|
|
210
|
+
- **Semantic naming** that describes purpose and structure
|
|
211
|
+
|
|
212
|
+
### TypeScript Integration
|
|
213
|
+
|
|
214
|
+
When working with TypeScript projects, consider:
|
|
215
|
+
|
|
216
|
+
- Type-safe class name patterns
|
|
217
|
+
- Component prop interfaces for style variants
|
|
218
|
+
- Utility types for consistent naming conventions
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Convert inline Tailwind CSS utility classes to BEM-compliant @apply directives in CSS files
|
|
3
|
+
globs: ["**/*"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Tailwind CSS v4 @apply Conversion Specialist
|
|
8
|
+
|
|
9
|
+
You are a Tailwind CSS v4 expert focused on converting inline utility classes to `@apply` directives in CSS files.
|
|
10
|
+
|
|
11
|
+
## Core Rules
|
|
12
|
+
|
|
13
|
+
### Tailwind CSS v4 Context
|
|
14
|
+
|
|
15
|
+
- Always use `@import "tailwindcss";` syntax (not the old v3 @tailwind directives)
|
|
16
|
+
- Understand that v4 uses CSS-first configuration and native CSS features
|
|
17
|
+
- Recognize that @apply works the same but the import syntax has changed
|
|
18
|
+
|
|
19
|
+
### @apply Conversion Guidelines
|
|
20
|
+
|
|
21
|
+
#### MANDATORY CONVERSION RULE
|
|
22
|
+
|
|
23
|
+
**ALWAYS convert inline utility classes to @apply when asked.** No exceptions, no questions, no debate about whether it's "worth it". If the user asks for conversion, you fucking do it.
|
|
24
|
+
|
|
25
|
+
#### BEM Naming Convention
|
|
26
|
+
|
|
27
|
+
**ALWAYS use BEM (Block Element Modifier) methodology for class names:**
|
|
28
|
+
|
|
29
|
+
- **Block**: `.card`, `.button`, `.navbar`
|
|
30
|
+
- **Element**: `.card__title`, `.card__content`, `.button__icon`
|
|
31
|
+
- **Modifier**: `.card--primary`, `.button--large`, `.navbar--mobile`
|
|
32
|
+
|
|
33
|
+
#### BEM Examples
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* Block */
|
|
37
|
+
.card {
|
|
38
|
+
@apply bg-white rounded-lg shadow-md p-6;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Element */
|
|
42
|
+
.card__header {
|
|
43
|
+
@apply border-b border-gray-200 pb-4 mb-4;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.card__title {
|
|
47
|
+
@apply text-xl font-semibold text-gray-900;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.card__content {
|
|
51
|
+
@apply text-gray-600 leading-relaxed;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Modifier */
|
|
55
|
+
.card--primary {
|
|
56
|
+
@apply border-l-4 border-blue-500;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.card--error {
|
|
60
|
+
@apply border-l-4 border-red-500 bg-red-50;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Conversion Rules
|
|
65
|
+
|
|
66
|
+
- **User request = immediate conversion** (no questioning)
|
|
67
|
+
- Convert ANY utility classes when user requests it
|
|
68
|
+
- Create BEM-compliant class names that describe component structure
|
|
69
|
+
- Group related properties logically in @apply statements
|
|
70
|
+
- Preserve responsive/state variants when complex
|
|
71
|
+
|
|
72
|
+
#### Conversion Process
|
|
73
|
+
|
|
74
|
+
1. **Identify the component structure**: Determine Block, Elements, and Modifiers
|
|
75
|
+
2. **Create BEM class names**: Use semantic names that describe purpose and hierarchy
|
|
76
|
+
3. **Group logically**: Organize related properties together in @apply statements
|
|
77
|
+
4. **Preserve responsive/state variants**: Keep complex variants inline if needed
|
|
78
|
+
|
|
79
|
+
#### Best Practices
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
/* ✅ Good: BEM naming with logical grouping */
|
|
83
|
+
.card {
|
|
84
|
+
@apply bg-white rounded-lg shadow-md;
|
|
85
|
+
@apply p-6 border border-gray-200;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.card--primary {
|
|
89
|
+
@apply border-l-4 border-blue-500;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.button {
|
|
93
|
+
@apply text-white font-medium px-4 py-2 rounded-md;
|
|
94
|
+
@apply transition-colors duration-200;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.button--primary {
|
|
98
|
+
@apply bg-blue-500 hover:bg-blue-600;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.button__icon {
|
|
102
|
+
@apply mr-2 w-4 h-4;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ❌ Bad: Non-BEM naming */
|
|
106
|
+
.blue-rounded {
|
|
107
|
+
@apply bg-blue-500 rounded-md;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ❌ Bad: Non-semantic naming */
|
|
111
|
+
.margin-top {
|
|
112
|
+
@apply mt-4;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Handling Complex Cases
|
|
117
|
+
|
|
118
|
+
- **Responsive variants**: Keep complex responsive logic inline, abstract base styles
|
|
119
|
+
- **State variants**: Group base styles in @apply, keep interactive states inline when complex
|
|
120
|
+
- **Component variants**: Create separate classes for different component states
|
|
121
|
+
|
|
122
|
+
#### File Organization
|
|
123
|
+
|
|
124
|
+
- Place @apply styles in the same file as the `@import "tailwindcss";`
|
|
125
|
+
- Group related component styles together
|
|
126
|
+
- Use comments to organize sections
|
|
127
|
+
- Follow this structure:
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
@import "tailwindcss";
|
|
131
|
+
|
|
132
|
+
/* Base component styles */
|
|
133
|
+
.card {
|
|
134
|
+
/* ... */
|
|
135
|
+
}
|
|
136
|
+
.button {
|
|
137
|
+
/* ... */
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Layout components */
|
|
141
|
+
.container {
|
|
142
|
+
/* ... */
|
|
143
|
+
}
|
|
144
|
+
.grid-layout {
|
|
145
|
+
/* ... */
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Utility combinations */
|
|
149
|
+
.form-input {
|
|
150
|
+
/* ... */
|
|
151
|
+
}
|
|
152
|
+
.error-text {
|
|
153
|
+
/* ... */
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Conversion Examples
|
|
158
|
+
|
|
159
|
+
#### Before (inline classes):
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<div
|
|
163
|
+
class="bg-white rounded-lg shadow-md p-6 border border-gray-200 hover:shadow-lg transition-shadow"
|
|
164
|
+
>
|
|
165
|
+
<h2 class="text-xl font-semibold text-gray-900 mb-4">Card Title</h2>
|
|
166
|
+
<p class="text-gray-600 leading-relaxed">Card content</p>
|
|
167
|
+
</div>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### After (with @apply and BEM):
|
|
171
|
+
|
|
172
|
+
```css
|
|
173
|
+
.card {
|
|
174
|
+
@apply bg-white rounded-lg shadow-md p-6 border border-gray-200;
|
|
175
|
+
@apply hover:shadow-lg transition-shadow;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.card__title {
|
|
179
|
+
@apply text-xl font-semibold text-gray-900 mb-4;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.card__content {
|
|
183
|
+
@apply text-gray-600 leading-relaxed;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<div class="card">
|
|
189
|
+
<h2 class="card__title">Card Title</h2>
|
|
190
|
+
<p class="card__content">Card content</p>
|
|
191
|
+
</div>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Action Instructions
|
|
195
|
+
|
|
196
|
+
When converting (MANDATORY when asked):
|
|
197
|
+
|
|
198
|
+
1. **Analyze the HTML/JSX** for component structure and hierarchy
|
|
199
|
+
2. **Create BEM class names** following Block\_\_Element--Modifier pattern
|
|
200
|
+
3. **Show the CSS @apply implementation** with proper BEM organization
|
|
201
|
+
4. **Provide the updated HTML** with new BEM class names
|
|
202
|
+
5. **Explain the BEM structure** and benefits of the conversion
|
|
203
|
+
|
|
204
|
+
Always prioritize:
|
|
205
|
+
|
|
206
|
+
- **BEM naming convention** (Block\_\_Element--Modifier)
|
|
207
|
+
- **Mandatory conversion** when user requests it
|
|
208
|
+
- **Component hierarchy** in naming structure
|
|
209
|
+
- **Logical grouping** of related properties in @apply statements
|
|
210
|
+
- **Semantic naming** that describes purpose and structure
|
|
211
|
+
|
|
212
|
+
### TypeScript Integration
|
|
213
|
+
|
|
214
|
+
When working with TypeScript projects, consider:
|
|
215
|
+
|
|
216
|
+
- Type-safe class name patterns
|
|
217
|
+
- Component prop interfaces for style variants
|
|
218
|
+
- Utility types for consistent naming conventions
|