@stratawp/cli 0.2.2
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/create.d.ts +2 -0
- package/dist/create.js +386 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +983 -0
- package/package.json +67 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk10 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/commands/dev.ts
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import { execa } from "execa";
|
|
11
|
+
async function devCommand(options) {
|
|
12
|
+
console.log(chalk.bold.cyan("\u2692\uFE0F StrataWP Development Server\n"));
|
|
13
|
+
const spinner = ora("Starting Vite dev server...").start();
|
|
14
|
+
try {
|
|
15
|
+
const viteProcess = execa("vite", ["--port", options.port, "--host", options.host], {
|
|
16
|
+
stdio: "inherit"
|
|
17
|
+
});
|
|
18
|
+
spinner.succeed("Development server started!");
|
|
19
|
+
console.log();
|
|
20
|
+
console.log(chalk.green(" \u279C") + " Local: " + chalk.cyan(`http://${options.host}:${options.port}`));
|
|
21
|
+
console.log(chalk.green(" \u279C") + " Hot reload enabled");
|
|
22
|
+
console.log(chalk.green(" \u279C") + " TypeScript checking in background");
|
|
23
|
+
console.log();
|
|
24
|
+
console.log(chalk.dim(" Press Ctrl+C to stop"));
|
|
25
|
+
console.log();
|
|
26
|
+
await viteProcess;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
spinner.fail("Failed to start development server");
|
|
29
|
+
console.error(error);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/commands/build.ts
|
|
35
|
+
import chalk2 from "chalk";
|
|
36
|
+
import ora2 from "ora";
|
|
37
|
+
import { execa as execa2 } from "execa";
|
|
38
|
+
async function buildCommand(options) {
|
|
39
|
+
console.log(chalk2.bold.cyan("\u2692\uFE0F Building for Production\n"));
|
|
40
|
+
const spinner = ora2("Building theme...").start();
|
|
41
|
+
try {
|
|
42
|
+
const args = ["build"];
|
|
43
|
+
if (options.analyze) {
|
|
44
|
+
args.push("--mode", "analyze");
|
|
45
|
+
}
|
|
46
|
+
await execa2("vite", args, { stdio: "inherit" });
|
|
47
|
+
spinner.succeed(chalk2.green("Build complete!"));
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(chalk2.cyan("\u{1F4E6} Output:") + " dist/");
|
|
50
|
+
console.log(chalk2.dim(" Ready for production deployment"));
|
|
51
|
+
console.log();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
spinner.fail("Build failed");
|
|
54
|
+
console.error(error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/commands/block.ts
|
|
60
|
+
import chalk3 from "chalk";
|
|
61
|
+
import ora3 from "ora";
|
|
62
|
+
import fs from "fs-extra";
|
|
63
|
+
import path from "path";
|
|
64
|
+
async function blockCommand(name, options) {
|
|
65
|
+
console.log(chalk3.bold.cyan("\u2692\uFE0F Creating Block\n"));
|
|
66
|
+
console.log(chalk3.dim(`Name: ${name}`));
|
|
67
|
+
console.log(chalk3.dim(`Type: ${options.type}`));
|
|
68
|
+
console.log(chalk3.dim(`Category: ${options.category}
|
|
69
|
+
`));
|
|
70
|
+
const spinner = ora3("Generating block...").start();
|
|
71
|
+
try {
|
|
72
|
+
const slug = name.toLowerCase().replace(/\s+/g, "-");
|
|
73
|
+
const blockDir = path.join(process.cwd(), "src/blocks", slug);
|
|
74
|
+
await fs.ensureDir(blockDir);
|
|
75
|
+
await generateBlockConfig(blockDir, name, slug, options);
|
|
76
|
+
await generateBlockEdit(blockDir, name, slug, options.styleFramework || "none");
|
|
77
|
+
await generateBlockRender(blockDir, name, slug, options.type, options.styleFramework || "none");
|
|
78
|
+
await generateBlockStyles(blockDir, slug, options.styleFramework || "none");
|
|
79
|
+
spinner.succeed(chalk3.green(`Block "${name}" created!`));
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(chalk3.cyan("\u{1F4C1} Files created:"));
|
|
82
|
+
console.log(chalk3.dim(` src/blocks/${slug}/block.json`));
|
|
83
|
+
console.log(chalk3.dim(` src/blocks/${slug}/edit.tsx`));
|
|
84
|
+
console.log(chalk3.dim(` src/blocks/${slug}/render.${options.type === "dynamic" ? "php" : "tsx"}`));
|
|
85
|
+
console.log(chalk3.dim(` src/blocks/${slug}/style.css`));
|
|
86
|
+
console.log();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
spinner.fail("Failed to create block");
|
|
89
|
+
console.error(error);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function generateBlockConfig(blockDir, name, slug, options) {
|
|
94
|
+
const config = {
|
|
95
|
+
$schema: "https://schemas.wp.org/trunk/block.json",
|
|
96
|
+
apiVersion: 3,
|
|
97
|
+
name: `stratawp/${slug}`,
|
|
98
|
+
title: name,
|
|
99
|
+
category: options.category,
|
|
100
|
+
icon: "smiley",
|
|
101
|
+
description: `${name} block`,
|
|
102
|
+
supports: {
|
|
103
|
+
html: false,
|
|
104
|
+
align: true
|
|
105
|
+
},
|
|
106
|
+
attributes: {},
|
|
107
|
+
editorScript: "file:./edit.tsx",
|
|
108
|
+
...options.type === "dynamic" && { render: "file:./render.php" },
|
|
109
|
+
style: "file:./style.css"
|
|
110
|
+
};
|
|
111
|
+
await fs.writeJson(path.join(blockDir, "block.json"), config, { spaces: 2 });
|
|
112
|
+
}
|
|
113
|
+
async function generateBlockEdit(blockDir, name, slug, framework) {
|
|
114
|
+
const useTailwind = framework === "tailwind";
|
|
115
|
+
const useUno = framework === "unocss";
|
|
116
|
+
const classes = useTailwind || useUno ? 'className="p-4 bg-gray-100 rounded-lg"' : "";
|
|
117
|
+
const headingClasses = useTailwind || useUno ? 'className="text-2xl font-bold mb-2"' : "";
|
|
118
|
+
const content = `import { useBlockProps } from '@wordpress/block-editor'
|
|
119
|
+
|
|
120
|
+
export default function Edit() {
|
|
121
|
+
const blockProps = useBlockProps(${useTailwind || useUno ? "{ className: 'p-4 bg-gray-100 rounded-lg' }" : ""})
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div {...blockProps}>
|
|
125
|
+
<h3 ${headingClasses}>${name}</h3>
|
|
126
|
+
<p>Edit your block here...</p>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
`;
|
|
131
|
+
await fs.writeFile(path.join(blockDir, "edit.tsx"), content);
|
|
132
|
+
}
|
|
133
|
+
async function generateBlockRender(blockDir, name, slug, type, framework) {
|
|
134
|
+
if (type === "dynamic") {
|
|
135
|
+
const useTailwind = framework === "tailwind";
|
|
136
|
+
const useUno = framework === "unocss";
|
|
137
|
+
const classes = useTailwind || useUno ? ' class="p-4 bg-gray-100 rounded-lg"' : "";
|
|
138
|
+
const headingClasses = useTailwind || useUno ? ' class="text-2xl font-bold mb-2"' : "";
|
|
139
|
+
const content = `<?php
|
|
140
|
+
/**
|
|
141
|
+
* ${name} Block Render
|
|
142
|
+
*
|
|
143
|
+
* @param array $attributes Block attributes
|
|
144
|
+
* @param string $content Block content
|
|
145
|
+
* @return string Rendered block
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
$block_wrapper_attributes = get_block_wrapper_attributes();
|
|
149
|
+
?>
|
|
150
|
+
|
|
151
|
+
<div <?php echo $block_wrapper_attributes; ?>${classes}>
|
|
152
|
+
<h3${headingClasses}><?php echo esc_html__( '${name}', 'stratawp' ); ?></h3>
|
|
153
|
+
<!-- Add your dynamic content here -->
|
|
154
|
+
</div>
|
|
155
|
+
`;
|
|
156
|
+
await fs.writeFile(path.join(blockDir, "render.php"), content);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async function generateBlockStyles(blockDir, slug, framework) {
|
|
160
|
+
let content;
|
|
161
|
+
if (framework === "tailwind" || framework === "unocss") {
|
|
162
|
+
content = `/*
|
|
163
|
+
* ${framework === "tailwind" ? "Tailwind CSS" : "UnoCSS"} utilities are used inline.
|
|
164
|
+
* Add custom styles here only if needed.
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
.wp-block-stratawp-${slug} {
|
|
168
|
+
/* Custom styles */
|
|
169
|
+
}
|
|
170
|
+
`;
|
|
171
|
+
} else {
|
|
172
|
+
content = `.wp-block-stratawp-${slug} {
|
|
173
|
+
padding: 1rem;
|
|
174
|
+
background-color: #f3f4f6;
|
|
175
|
+
border-radius: 0.5rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.wp-block-stratawp-${slug} h3 {
|
|
179
|
+
font-size: 1.5rem;
|
|
180
|
+
font-weight: bold;
|
|
181
|
+
margin-bottom: 0.5rem;
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
}
|
|
185
|
+
await fs.writeFile(path.join(blockDir, "style.css"), content);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/commands/component.ts
|
|
189
|
+
import path3 from "path";
|
|
190
|
+
import chalk5 from "chalk";
|
|
191
|
+
|
|
192
|
+
// src/utils/validation.ts
|
|
193
|
+
import validateNpmPackageName from "validate-npm-package-name";
|
|
194
|
+
function slugify(text) {
|
|
195
|
+
return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/^-+|-+$/g, "");
|
|
196
|
+
}
|
|
197
|
+
function toPascalCase(text) {
|
|
198
|
+
return text.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^(.)/, (char) => char.toUpperCase());
|
|
199
|
+
}
|
|
200
|
+
function validateComponentName(name) {
|
|
201
|
+
if (!name || name.trim().length === 0) {
|
|
202
|
+
return { valid: false, error: "Component name cannot be empty" };
|
|
203
|
+
}
|
|
204
|
+
const pascal = toPascalCase(name);
|
|
205
|
+
if (!/^[A-Z][a-zA-Z0-9]*$/.test(pascal)) {
|
|
206
|
+
return { valid: false, error: "Component name must be valid PascalCase" };
|
|
207
|
+
}
|
|
208
|
+
if (pascal.length > 50) {
|
|
209
|
+
return { valid: false, error: "Component name is too long (max 50 characters)" };
|
|
210
|
+
}
|
|
211
|
+
return { valid: true };
|
|
212
|
+
}
|
|
213
|
+
function validateTemplateName(name) {
|
|
214
|
+
if (!name || name.trim().length === 0) {
|
|
215
|
+
return { valid: false, error: "Template name cannot be empty" };
|
|
216
|
+
}
|
|
217
|
+
const slug = slugify(name);
|
|
218
|
+
if (slug.length === 0) {
|
|
219
|
+
return { valid: false, error: "Template name must contain valid characters" };
|
|
220
|
+
}
|
|
221
|
+
if (slug.length > 50) {
|
|
222
|
+
return { valid: false, error: "Template name is too long (max 50 characters)" };
|
|
223
|
+
}
|
|
224
|
+
return { valid: true };
|
|
225
|
+
}
|
|
226
|
+
function validatePartName(name) {
|
|
227
|
+
if (!name || name.trim().length === 0) {
|
|
228
|
+
return { valid: false, error: "Part name cannot be empty" };
|
|
229
|
+
}
|
|
230
|
+
const slug = slugify(name);
|
|
231
|
+
if (slug.length === 0) {
|
|
232
|
+
return { valid: false, error: "Part name must contain valid characters" };
|
|
233
|
+
}
|
|
234
|
+
if (slug.length > 50) {
|
|
235
|
+
return { valid: false, error: "Part name is too long (max 50 characters)" };
|
|
236
|
+
}
|
|
237
|
+
return { valid: true };
|
|
238
|
+
}
|
|
239
|
+
function validateNamespace(namespace) {
|
|
240
|
+
if (!namespace || namespace.trim().length === 0) {
|
|
241
|
+
return { valid: false, error: "Namespace cannot be empty" };
|
|
242
|
+
}
|
|
243
|
+
if (!/^[A-Z][a-zA-Z0-9]*(\\[A-Z][a-zA-Z0-9]*)*$/.test(namespace)) {
|
|
244
|
+
return { valid: false, error: "Invalid PHP namespace format (e.g., MyTheme\\Components)" };
|
|
245
|
+
}
|
|
246
|
+
return { valid: true };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/utils/templates.ts
|
|
250
|
+
function generateTemplateHTML(type, slug) {
|
|
251
|
+
const templates = {
|
|
252
|
+
page: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
253
|
+
|
|
254
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
255
|
+
<main class="wp-block-group">
|
|
256
|
+
<!-- wp:post-title /-->
|
|
257
|
+
<!-- wp:post-content /-->
|
|
258
|
+
</main>
|
|
259
|
+
<!-- /wp:group -->
|
|
260
|
+
|
|
261
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
262
|
+
single: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
263
|
+
|
|
264
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
265
|
+
<main class="wp-block-group">
|
|
266
|
+
<!-- wp:post-title /-->
|
|
267
|
+
|
|
268
|
+
<!-- wp:post-featured-image /-->
|
|
269
|
+
|
|
270
|
+
<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
|
|
271
|
+
<div class="wp-block-group">
|
|
272
|
+
<!-- wp:post-date /-->
|
|
273
|
+
<!-- wp:post-author /-->
|
|
274
|
+
</div>
|
|
275
|
+
<!-- /wp:group -->
|
|
276
|
+
|
|
277
|
+
<!-- wp:post-content /-->
|
|
278
|
+
|
|
279
|
+
<!-- wp:post-terms {"term":"category"} /-->
|
|
280
|
+
<!-- wp:post-terms {"term":"post_tag"} /-->
|
|
281
|
+
</main>
|
|
282
|
+
<!-- /wp:group -->
|
|
283
|
+
|
|
284
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
285
|
+
archive: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
286
|
+
|
|
287
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
288
|
+
<main class="wp-block-group">
|
|
289
|
+
<!-- wp:query-title {"type":"archive"} /-->
|
|
290
|
+
<!-- wp:term-description /-->
|
|
291
|
+
|
|
292
|
+
<!-- wp:query {"queryId":0,"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true}} -->
|
|
293
|
+
<div class="wp-block-query">
|
|
294
|
+
<!-- wp:post-template -->
|
|
295
|
+
<!-- wp:post-title {"isLink":true} /-->
|
|
296
|
+
<!-- wp:post-excerpt /-->
|
|
297
|
+
<!-- wp:post-date /-->
|
|
298
|
+
<!-- /wp:post-template -->
|
|
299
|
+
|
|
300
|
+
<!-- wp:query-pagination -->
|
|
301
|
+
<!-- wp:query-pagination-previous /-->
|
|
302
|
+
<!-- wp:query-pagination-numbers /-->
|
|
303
|
+
<!-- wp:query-pagination-next /-->
|
|
304
|
+
<!-- /wp:query-pagination -->
|
|
305
|
+
</div>
|
|
306
|
+
<!-- /wp:query -->
|
|
307
|
+
</main>
|
|
308
|
+
<!-- /wp:group -->
|
|
309
|
+
|
|
310
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
311
|
+
"404": `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
312
|
+
|
|
313
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
314
|
+
<main class="wp-block-group">
|
|
315
|
+
<!-- wp:heading {"level":1} -->
|
|
316
|
+
<h1>404 - Page Not Found</h1>
|
|
317
|
+
<!-- /wp:heading -->
|
|
318
|
+
|
|
319
|
+
<!-- wp:paragraph -->
|
|
320
|
+
<p>The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.</p>
|
|
321
|
+
<!-- /wp:paragraph -->
|
|
322
|
+
|
|
323
|
+
<!-- wp:search {"label":"Search","showLabel":false,"placeholder":"Search..."} /-->
|
|
324
|
+
</main>
|
|
325
|
+
<!-- /wp:group -->
|
|
326
|
+
|
|
327
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
328
|
+
home: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
329
|
+
|
|
330
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
331
|
+
<main class="wp-block-group">
|
|
332
|
+
<!-- wp:query {"queryId":0,"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true}} -->
|
|
333
|
+
<div class="wp-block-query">
|
|
334
|
+
<!-- wp:post-template -->
|
|
335
|
+
<!-- wp:post-featured-image {"isLink":true} /-->
|
|
336
|
+
<!-- wp:post-title {"isLink":true} /-->
|
|
337
|
+
<!-- wp:post-excerpt /-->
|
|
338
|
+
<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
|
|
339
|
+
<div class="wp-block-group">
|
|
340
|
+
<!-- wp:post-date /-->
|
|
341
|
+
<!-- wp:post-author /-->
|
|
342
|
+
</div>
|
|
343
|
+
<!-- /wp:group -->
|
|
344
|
+
<!-- /wp:post-template -->
|
|
345
|
+
|
|
346
|
+
<!-- wp:query-pagination -->
|
|
347
|
+
<!-- wp:query-pagination-previous /-->
|
|
348
|
+
<!-- wp:query-pagination-numbers /-->
|
|
349
|
+
<!-- wp:query-pagination-next /-->
|
|
350
|
+
<!-- /wp:query-pagination -->
|
|
351
|
+
</div>
|
|
352
|
+
<!-- /wp:query -->
|
|
353
|
+
</main>
|
|
354
|
+
<!-- /wp:group -->
|
|
355
|
+
|
|
356
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
357
|
+
search: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
358
|
+
|
|
359
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
360
|
+
<main class="wp-block-group">
|
|
361
|
+
<!-- wp:query-title {"type":"search"} /-->
|
|
362
|
+
|
|
363
|
+
<!-- wp:search {"label":"Search","showLabel":false} /-->
|
|
364
|
+
|
|
365
|
+
<!-- wp:query {"queryId":0,"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true}} -->
|
|
366
|
+
<div class="wp-block-query">
|
|
367
|
+
<!-- wp:post-template -->
|
|
368
|
+
<!-- wp:post-title {"isLink":true} /-->
|
|
369
|
+
<!-- wp:post-excerpt /-->
|
|
370
|
+
<!-- /wp:post-template -->
|
|
371
|
+
|
|
372
|
+
<!-- wp:query-pagination -->
|
|
373
|
+
<!-- wp:query-pagination-previous /-->
|
|
374
|
+
<!-- wp:query-pagination-numbers /-->
|
|
375
|
+
<!-- wp:query-pagination-next /-->
|
|
376
|
+
<!-- /wp:query-pagination -->
|
|
377
|
+
|
|
378
|
+
<!-- wp:query-no-results -->
|
|
379
|
+
<!-- wp:paragraph -->
|
|
380
|
+
<p>No results found. Try a different search.</p>
|
|
381
|
+
<!-- /wp:paragraph -->
|
|
382
|
+
<!-- /wp:query-no-results -->
|
|
383
|
+
</div>
|
|
384
|
+
<!-- /wp:query -->
|
|
385
|
+
</main>
|
|
386
|
+
<!-- /wp:group -->
|
|
387
|
+
|
|
388
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`,
|
|
389
|
+
custom: `<!-- wp:template-part {"slug":"header","theme":"${slug}","tagName":"header"} /-->
|
|
390
|
+
|
|
391
|
+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
|
|
392
|
+
<main class="wp-block-group">
|
|
393
|
+
<!-- Add your custom content here -->
|
|
394
|
+
</main>
|
|
395
|
+
<!-- /wp:group -->
|
|
396
|
+
|
|
397
|
+
<!-- wp:template-part {"slug":"footer","theme":"${slug}","tagName":"footer"} /-->`
|
|
398
|
+
};
|
|
399
|
+
return templates[type] || templates.custom;
|
|
400
|
+
}
|
|
401
|
+
function generatePartHTML(type) {
|
|
402
|
+
const parts = {
|
|
403
|
+
header: `<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
|
|
404
|
+
<div class="wp-block-group">
|
|
405
|
+
<!-- wp:site-logo /-->
|
|
406
|
+
<!-- wp:site-title /-->
|
|
407
|
+
<!-- wp:navigation /-->
|
|
408
|
+
</div>
|
|
409
|
+
<!-- /wp:group -->`,
|
|
410
|
+
footer: `<!-- wp:group {"layout":{"type":"constrained"}} -->
|
|
411
|
+
<div class="wp-block-group">
|
|
412
|
+
<!-- wp:paragraph {"align":"center"} -->
|
|
413
|
+
<p class="has-text-align-center">\xA9 <!-- wp:post-date {"format":"Y"} /--> All rights reserved.</p>
|
|
414
|
+
<!-- /wp:paragraph -->
|
|
415
|
+
|
|
416
|
+
<!-- wp:navigation {"layout":{"type":"flex","justifyContent":"center"}} /-->
|
|
417
|
+
</div>
|
|
418
|
+
<!-- /wp:group -->`,
|
|
419
|
+
sidebar: `<!-- wp:group {"layout":{"type":"default"}} -->
|
|
420
|
+
<div class="wp-block-group">
|
|
421
|
+
<!-- wp:heading -->
|
|
422
|
+
<h2>Sidebar</h2>
|
|
423
|
+
<!-- /wp:heading -->
|
|
424
|
+
|
|
425
|
+
<!-- wp:search {"label":"Search","showLabel":false} /-->
|
|
426
|
+
|
|
427
|
+
<!-- wp:latest-posts /-->
|
|
428
|
+
|
|
429
|
+
<!-- wp:categories /-->
|
|
430
|
+
</div>
|
|
431
|
+
<!-- /wp:group -->`,
|
|
432
|
+
content: `<!-- wp:post-title /-->
|
|
433
|
+
<!-- wp:post-content /-->`,
|
|
434
|
+
custom: `<!-- wp:group {"layout":{"type":"default"}} -->
|
|
435
|
+
<div class="wp-block-group">
|
|
436
|
+
<!-- Add your custom content here -->
|
|
437
|
+
</div>
|
|
438
|
+
<!-- /wp:group -->`
|
|
439
|
+
};
|
|
440
|
+
return parts[type] || parts.custom;
|
|
441
|
+
}
|
|
442
|
+
function generatePartPHP(type, slug) {
|
|
443
|
+
const parts = {
|
|
444
|
+
header: `<?php
|
|
445
|
+
/**
|
|
446
|
+
* Header Template Part
|
|
447
|
+
*
|
|
448
|
+
* @package ${slug}
|
|
449
|
+
*/
|
|
450
|
+
?>
|
|
451
|
+
<header class="site-header">
|
|
452
|
+
<div class="site-branding">
|
|
453
|
+
<?php
|
|
454
|
+
if ( has_custom_logo() ) {
|
|
455
|
+
the_custom_logo();
|
|
456
|
+
}
|
|
457
|
+
?>
|
|
458
|
+
<h1 class="site-title">
|
|
459
|
+
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
|
|
460
|
+
<?php bloginfo( 'name' ); ?>
|
|
461
|
+
</a>
|
|
462
|
+
</h1>
|
|
463
|
+
<?php
|
|
464
|
+
$description = get_bloginfo( 'description', 'display' );
|
|
465
|
+
if ( $description || is_customize_preview() ) :
|
|
466
|
+
?>
|
|
467
|
+
<p class="site-description"><?php echo esc_html( $description ); ?></p>
|
|
468
|
+
<?php endif; ?>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<nav class="main-navigation">
|
|
472
|
+
<?php
|
|
473
|
+
wp_nav_menu(
|
|
474
|
+
array(
|
|
475
|
+
'theme_location' => 'primary',
|
|
476
|
+
'menu_class' => 'primary-menu',
|
|
477
|
+
'fallback_cb' => false,
|
|
478
|
+
)
|
|
479
|
+
);
|
|
480
|
+
?>
|
|
481
|
+
</nav>
|
|
482
|
+
</header>`,
|
|
483
|
+
footer: `<?php
|
|
484
|
+
/**
|
|
485
|
+
* Footer Template Part
|
|
486
|
+
*
|
|
487
|
+
* @package ${slug}
|
|
488
|
+
*/
|
|
489
|
+
?>
|
|
490
|
+
<footer class="site-footer">
|
|
491
|
+
<div class="site-info">
|
|
492
|
+
<p>© <?php echo esc_html( date( 'Y' ) ); ?> <?php bloginfo( 'name' ); ?>. All rights reserved.</p>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<?php
|
|
496
|
+
if ( has_nav_menu( 'footer' ) ) {
|
|
497
|
+
wp_nav_menu(
|
|
498
|
+
array(
|
|
499
|
+
'theme_location' => 'footer',
|
|
500
|
+
'menu_class' => 'footer-menu',
|
|
501
|
+
'depth' => 1,
|
|
502
|
+
)
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
?>
|
|
506
|
+
</footer>`,
|
|
507
|
+
sidebar: `<?php
|
|
508
|
+
/**
|
|
509
|
+
* Sidebar Template Part
|
|
510
|
+
*
|
|
511
|
+
* @package ${slug}
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
if ( ! is_active_sidebar( 'sidebar-1' ) ) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
?>
|
|
518
|
+
<aside class="widget-area">
|
|
519
|
+
<?php dynamic_sidebar( 'sidebar-1' ); ?>
|
|
520
|
+
</aside>`,
|
|
521
|
+
content: `<?php
|
|
522
|
+
/**
|
|
523
|
+
* Content Template Part
|
|
524
|
+
*
|
|
525
|
+
* @package ${slug}
|
|
526
|
+
*/
|
|
527
|
+
?>
|
|
528
|
+
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
|
529
|
+
<header class="entry-header">
|
|
530
|
+
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
|
|
531
|
+
</header>
|
|
532
|
+
|
|
533
|
+
<div class="entry-content">
|
|
534
|
+
<?php
|
|
535
|
+
the_content();
|
|
536
|
+
|
|
537
|
+
wp_link_pages(
|
|
538
|
+
array(
|
|
539
|
+
'before' => '<div class="page-links">' . esc_html__( 'Pages:', '${slug}' ),
|
|
540
|
+
'after' => '</div>',
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
?>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<footer class="entry-footer">
|
|
547
|
+
<?php
|
|
548
|
+
// Post meta, tags, etc.
|
|
549
|
+
?>
|
|
550
|
+
</footer>
|
|
551
|
+
</article>`,
|
|
552
|
+
custom: `<?php
|
|
553
|
+
/**
|
|
554
|
+
* Custom Template Part
|
|
555
|
+
*
|
|
556
|
+
* @package ${slug}
|
|
557
|
+
*/
|
|
558
|
+
?>
|
|
559
|
+
<!-- Add your custom PHP code here -->`
|
|
560
|
+
};
|
|
561
|
+
return parts[type] || parts.custom;
|
|
562
|
+
}
|
|
563
|
+
function generateComponentClass(name, namespace, type) {
|
|
564
|
+
return `<?php
|
|
565
|
+
/**
|
|
566
|
+
* ${name} Component
|
|
567
|
+
*
|
|
568
|
+
* @package ${namespace}
|
|
569
|
+
*/
|
|
570
|
+
|
|
571
|
+
namespace ${namespace}\\Components;
|
|
572
|
+
|
|
573
|
+
use StrataWP\\ComponentInterface;
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Class ${name}
|
|
577
|
+
*/
|
|
578
|
+
class ${name} implements ComponentInterface {
|
|
579
|
+
/**
|
|
580
|
+
* Get component slug
|
|
581
|
+
*
|
|
582
|
+
* @return string
|
|
583
|
+
*/
|
|
584
|
+
public function get_slug(): string {
|
|
585
|
+
return '${name.toLowerCase()}';
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Initialize component
|
|
590
|
+
*
|
|
591
|
+
* @return void
|
|
592
|
+
*/
|
|
593
|
+
public function initialize(): void {
|
|
594
|
+
// Add your initialization code here
|
|
595
|
+
add_action( 'init', array( $this, 'register' ) );
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Register component functionality
|
|
600
|
+
*
|
|
601
|
+
* @return void
|
|
602
|
+
*/
|
|
603
|
+
public function register(): void {
|
|
604
|
+
// Add your registration code here
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
`;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/utils/filesystem.ts
|
|
611
|
+
import fs2 from "fs-extra";
|
|
612
|
+
import path2 from "path";
|
|
613
|
+
import chalk4 from "chalk";
|
|
614
|
+
import ora4 from "ora";
|
|
615
|
+
async function ensureDir(dirPath) {
|
|
616
|
+
await fs2.ensureDir(dirPath);
|
|
617
|
+
}
|
|
618
|
+
async function writeFile(filePath, content) {
|
|
619
|
+
await fs2.writeFile(filePath, content, "utf8");
|
|
620
|
+
}
|
|
621
|
+
async function readFile(filePath) {
|
|
622
|
+
return fs2.readFile(filePath, "utf8");
|
|
623
|
+
}
|
|
624
|
+
async function createFileWithSpinner(filePath, content, description) {
|
|
625
|
+
const spinner = ora4(description || `Creating ${path2.basename(filePath)}`).start();
|
|
626
|
+
try {
|
|
627
|
+
await ensureDir(path2.dirname(filePath));
|
|
628
|
+
await writeFile(filePath, content);
|
|
629
|
+
spinner.succeed(chalk4.green(`Created ${path2.relative(process.cwd(), filePath)}`));
|
|
630
|
+
} catch (error) {
|
|
631
|
+
spinner.fail(chalk4.red(`Failed to create ${path2.basename(filePath)}`));
|
|
632
|
+
throw error;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/commands/component.ts
|
|
637
|
+
async function componentCommand(name, options) {
|
|
638
|
+
console.log(chalk5.cyan("\n\u2692\uFE0F Creating PHP Component\n"));
|
|
639
|
+
const validation = validateComponentName(name);
|
|
640
|
+
if (!validation.valid) {
|
|
641
|
+
console.error(chalk5.red(`\u2716 ${validation.error}`));
|
|
642
|
+
process.exit(1);
|
|
643
|
+
}
|
|
644
|
+
const className = toPascalCase(name);
|
|
645
|
+
const cwd = process.cwd();
|
|
646
|
+
const componentsDir = path3.join(cwd, "inc", "Components");
|
|
647
|
+
const componentPath = path3.join(componentsDir, `${className}.php`);
|
|
648
|
+
const fs3 = await import("fs-extra");
|
|
649
|
+
if (await fs3.pathExists(componentPath)) {
|
|
650
|
+
console.error(chalk5.red(`\u2716 Component "${className}" already exists`));
|
|
651
|
+
process.exit(1);
|
|
652
|
+
}
|
|
653
|
+
let namespace = options.namespace;
|
|
654
|
+
if (!namespace) {
|
|
655
|
+
try {
|
|
656
|
+
const existingComponents = await fs3.readdir(componentsDir);
|
|
657
|
+
if (existingComponents.length > 0) {
|
|
658
|
+
const firstComponent = existingComponents.find((f) => f.endsWith(".php"));
|
|
659
|
+
if (firstComponent) {
|
|
660
|
+
const content = await fs3.readFile(path3.join(componentsDir, firstComponent), "utf8");
|
|
661
|
+
const namespaceMatch = content.match(/namespace\s+([^;\\]+)/);
|
|
662
|
+
if (namespaceMatch) {
|
|
663
|
+
namespace = namespaceMatch[1];
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
if (!namespace) {
|
|
670
|
+
const themeName = toPascalCase(path3.basename(cwd));
|
|
671
|
+
namespace = themeName;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const namespaceValidation = validateNamespace(namespace);
|
|
675
|
+
if (!namespaceValidation.valid) {
|
|
676
|
+
console.error(chalk5.red(`\u2716 ${namespaceValidation.error}`));
|
|
677
|
+
process.exit(1);
|
|
678
|
+
}
|
|
679
|
+
await ensureDir(componentsDir);
|
|
680
|
+
const componentContent = generateComponentClass(className, namespace, options.type);
|
|
681
|
+
await createFileWithSpinner(
|
|
682
|
+
componentPath,
|
|
683
|
+
componentContent,
|
|
684
|
+
`Creating ${className}.php component`
|
|
685
|
+
);
|
|
686
|
+
console.log(chalk5.green("\n\u2713 Component created successfully!\n"));
|
|
687
|
+
console.log(chalk5.dim(` Component: inc/Components/${className}.php`));
|
|
688
|
+
console.log(chalk5.dim(` Namespace: ${namespace}\\Components`));
|
|
689
|
+
console.log(chalk5.dim(` Type: ${options.type}`));
|
|
690
|
+
console.log(chalk5.cyan("\n Next steps:"));
|
|
691
|
+
console.log(chalk5.dim(" 1. Add your component logic to the class"));
|
|
692
|
+
console.log(chalk5.dim(" 2. Register in functions.php:"));
|
|
693
|
+
console.log(chalk5.dim(` new ${namespace}\\Components\\${className}(),
|
|
694
|
+
`));
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/commands/test.ts
|
|
698
|
+
import chalk6 from "chalk";
|
|
699
|
+
async function testCommand(options) {
|
|
700
|
+
console.log(chalk6.cyan("\u{1F9EA} Running tests..."));
|
|
701
|
+
console.log(chalk6.yellow("\u26A0\uFE0F Coming soon!"));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// src/commands/template.ts
|
|
705
|
+
import path4 from "path";
|
|
706
|
+
import chalk7 from "chalk";
|
|
707
|
+
async function templateCommand(name, options) {
|
|
708
|
+
console.log(chalk7.cyan("\n\u2692\uFE0F Creating WordPress Template\n"));
|
|
709
|
+
const validation = validateTemplateName(name);
|
|
710
|
+
if (!validation.valid) {
|
|
711
|
+
console.error(chalk7.red(`\u2716 ${validation.error}`));
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
const slug = slugify(name);
|
|
715
|
+
const cwd = process.cwd();
|
|
716
|
+
const templatesDir = path4.join(cwd, "templates");
|
|
717
|
+
const templatePath = path4.join(templatesDir, `${slug}.html`);
|
|
718
|
+
const fs3 = await import("fs-extra");
|
|
719
|
+
if (await fs3.pathExists(templatePath)) {
|
|
720
|
+
console.error(chalk7.red(`\u2716 Template "${slug}" already exists`));
|
|
721
|
+
process.exit(1);
|
|
722
|
+
}
|
|
723
|
+
await ensureDir(templatesDir);
|
|
724
|
+
let themeSlug = path4.basename(cwd);
|
|
725
|
+
try {
|
|
726
|
+
const packageJson = await fs3.readJson(path4.join(cwd, "package.json"));
|
|
727
|
+
if (packageJson.name) {
|
|
728
|
+
themeSlug = packageJson.name;
|
|
729
|
+
}
|
|
730
|
+
} catch {
|
|
731
|
+
}
|
|
732
|
+
const templateContent = generateTemplateHTML(options.type, themeSlug);
|
|
733
|
+
await createFileWithSpinner(
|
|
734
|
+
templatePath,
|
|
735
|
+
templateContent,
|
|
736
|
+
`Creating ${slug}.html template`
|
|
737
|
+
);
|
|
738
|
+
console.log(chalk7.green("\n\u2713 Template created successfully!\n"));
|
|
739
|
+
console.log(chalk7.dim(` Template: templates/${slug}.html`));
|
|
740
|
+
console.log(chalk7.dim(` Type: ${options.type}`));
|
|
741
|
+
if (options.description) {
|
|
742
|
+
console.log(chalk7.dim(` Description: ${options.description}`));
|
|
743
|
+
}
|
|
744
|
+
console.log(chalk7.cyan("\n Next steps:"));
|
|
745
|
+
console.log(chalk7.dim(" 1. Edit the template in templates/" + slug + ".html"));
|
|
746
|
+
console.log(chalk7.dim(" 2. Add your custom blocks and content"));
|
|
747
|
+
console.log(chalk7.dim(" 3. The template will be available in WordPress theme editor\n"));
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// src/commands/part.ts
|
|
751
|
+
import path5 from "path";
|
|
752
|
+
import chalk8 from "chalk";
|
|
753
|
+
async function partCommand(name, options) {
|
|
754
|
+
console.log(chalk8.cyan("\n\u2692\uFE0F Creating Template Part\n"));
|
|
755
|
+
const validation = validatePartName(name);
|
|
756
|
+
if (!validation.valid) {
|
|
757
|
+
console.error(chalk8.red(`\u2716 ${validation.error}`));
|
|
758
|
+
process.exit(1);
|
|
759
|
+
}
|
|
760
|
+
const slug = slugify(name);
|
|
761
|
+
const cwd = process.cwd();
|
|
762
|
+
const partsDir = path5.join(cwd, "parts");
|
|
763
|
+
const ext = options.markup === "html" ? "html" : "php";
|
|
764
|
+
const partPath = path5.join(partsDir, `${slug}.${ext}`);
|
|
765
|
+
const fs3 = await import("fs-extra");
|
|
766
|
+
if (await fs3.pathExists(partPath)) {
|
|
767
|
+
console.error(chalk8.red(`\u2716 Template part "${slug}.${ext}" already exists`));
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
await ensureDir(partsDir);
|
|
771
|
+
let themeSlug = path5.basename(cwd);
|
|
772
|
+
try {
|
|
773
|
+
const packageJson = await fs3.readJson(path5.join(cwd, "package.json"));
|
|
774
|
+
if (packageJson.name) {
|
|
775
|
+
themeSlug = packageJson.name;
|
|
776
|
+
}
|
|
777
|
+
} catch {
|
|
778
|
+
}
|
|
779
|
+
const partContent = options.markup === "html" ? generatePartHTML(options.type) : generatePartPHP(options.type, themeSlug);
|
|
780
|
+
await createFileWithSpinner(
|
|
781
|
+
partPath,
|
|
782
|
+
partContent,
|
|
783
|
+
`Creating ${slug}.${ext} template part`
|
|
784
|
+
);
|
|
785
|
+
console.log(chalk8.green("\n\u2713 Template part created successfully!\n"));
|
|
786
|
+
console.log(chalk8.dim(` Part: parts/${slug}.${ext}`));
|
|
787
|
+
console.log(chalk8.dim(` Type: ${options.type}`));
|
|
788
|
+
console.log(chalk8.dim(` Markup: ${options.markup}`));
|
|
789
|
+
console.log(chalk8.cyan("\n Next steps:"));
|
|
790
|
+
console.log(chalk8.dim(` 1. Edit the part in parts/${slug}.${ext}`));
|
|
791
|
+
console.log(chalk8.dim(' 2. Use in templates with <!-- wp:template-part {"slug":"' + slug + '"} /-->'));
|
|
792
|
+
console.log(chalk8.dim(" 3. Or in PHP with get_template_part('parts/" + slug + "')\n"));
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/commands/design-system.ts
|
|
796
|
+
import path6 from "path";
|
|
797
|
+
import chalk9 from "chalk";
|
|
798
|
+
import ora5 from "ora";
|
|
799
|
+
import { execa as execa3 } from "execa";
|
|
800
|
+
async function designSystemCommand(framework) {
|
|
801
|
+
console.log(chalk9.cyan("\n\u2692\uFE0F Setting up Design System\n"));
|
|
802
|
+
if (framework !== "tailwind" && framework !== "unocss") {
|
|
803
|
+
console.error(chalk9.red("\u2716 Invalid framework. Choose: tailwind or unocss"));
|
|
804
|
+
process.exit(1);
|
|
805
|
+
}
|
|
806
|
+
const cwd = process.cwd();
|
|
807
|
+
const packageManager = await detectPackageManager();
|
|
808
|
+
await installDependencies(framework, packageManager);
|
|
809
|
+
await createConfigFile(framework, cwd);
|
|
810
|
+
await updateViteConfig(framework, cwd);
|
|
811
|
+
await createCSSEntry(framework, cwd);
|
|
812
|
+
console.log(chalk9.green("\n\u2713 Design system setup complete!\n"));
|
|
813
|
+
console.log(chalk9.cyan(" Next steps:"));
|
|
814
|
+
console.log(chalk9.dim(` 1. Import the CSS in your main JS file:`));
|
|
815
|
+
console.log(chalk9.dim(` import '../css/design-system.css'`));
|
|
816
|
+
console.log(chalk9.dim(` 2. Start using utility classes in your blocks`));
|
|
817
|
+
console.log(chalk9.dim(` 3. Customize ${framework === "tailwind" ? "tailwind" : "uno"}.config.${framework === "tailwind" ? "js" : "ts"} as needed
|
|
818
|
+
`));
|
|
819
|
+
}
|
|
820
|
+
async function detectPackageManager() {
|
|
821
|
+
const fs3 = await import("fs-extra");
|
|
822
|
+
const cwd = process.cwd();
|
|
823
|
+
if (await fs3.pathExists(path6.join(cwd, "pnpm-lock.yaml"))) {
|
|
824
|
+
return "pnpm";
|
|
825
|
+
}
|
|
826
|
+
if (await fs3.pathExists(path6.join(cwd, "yarn.lock"))) {
|
|
827
|
+
return "yarn";
|
|
828
|
+
}
|
|
829
|
+
return "npm";
|
|
830
|
+
}
|
|
831
|
+
async function installDependencies(framework, pm) {
|
|
832
|
+
const spinner = ora5("Installing dependencies...").start();
|
|
833
|
+
try {
|
|
834
|
+
const packages = framework === "tailwind" ? ["tailwindcss", "postcss", "autoprefixer"] : ["@unocss/vite", "unocss"];
|
|
835
|
+
const installCmd = pm === "yarn" ? "add" : "install";
|
|
836
|
+
const devFlag = pm === "yarn" ? "--dev" : "--save-dev";
|
|
837
|
+
await execa3(pm, [installCmd, devFlag, ...packages], {
|
|
838
|
+
cwd: process.cwd(),
|
|
839
|
+
stdio: "pipe"
|
|
840
|
+
});
|
|
841
|
+
spinner.succeed(chalk9.green("Dependencies installed"));
|
|
842
|
+
} catch (error) {
|
|
843
|
+
spinner.fail("Failed to install dependencies");
|
|
844
|
+
console.error(error);
|
|
845
|
+
process.exit(1);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
async function createConfigFile(framework, cwd) {
|
|
849
|
+
if (framework === "tailwind") {
|
|
850
|
+
const configContent = `import { strataWPTailwindPreset } from '@stratawp/vite-plugin/integrations/tailwind-preset'
|
|
851
|
+
|
|
852
|
+
export default {
|
|
853
|
+
presets: [strataWPTailwindPreset],
|
|
854
|
+
theme: {
|
|
855
|
+
extend: {
|
|
856
|
+
// Add your custom theme extensions here
|
|
857
|
+
},
|
|
858
|
+
},
|
|
859
|
+
}
|
|
860
|
+
`;
|
|
861
|
+
await createFileWithSpinner(
|
|
862
|
+
path6.join(cwd, "tailwind.config.js"),
|
|
863
|
+
configContent,
|
|
864
|
+
"Creating tailwind.config.js"
|
|
865
|
+
);
|
|
866
|
+
} else {
|
|
867
|
+
const configContent = `import { defineConfig, presetUno } from 'unocss'
|
|
868
|
+
import { strataWPUnoPreset } from '@stratawp/vite-plugin/integrations/unocss-preset'
|
|
869
|
+
|
|
870
|
+
export default defineConfig({
|
|
871
|
+
presets: [
|
|
872
|
+
presetUno(),
|
|
873
|
+
strataWPUnoPreset,
|
|
874
|
+
],
|
|
875
|
+
theme: {
|
|
876
|
+
// Add your custom theme here
|
|
877
|
+
},
|
|
878
|
+
})
|
|
879
|
+
`;
|
|
880
|
+
await createFileWithSpinner(
|
|
881
|
+
path6.join(cwd, "uno.config.ts"),
|
|
882
|
+
configContent,
|
|
883
|
+
"Creating uno.config.ts"
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
async function updateViteConfig(framework, cwd) {
|
|
888
|
+
const spinner = ora5("Updating vite.config.ts...").start();
|
|
889
|
+
const viteConfigPath = path6.join(cwd, "vite.config.ts");
|
|
890
|
+
try {
|
|
891
|
+
let config = await readFile(viteConfigPath);
|
|
892
|
+
if (framework === "unocss" && !config.includes("unocss/vite")) {
|
|
893
|
+
config = `import UnoCSS from '@unocss/vite'
|
|
894
|
+
${config}`;
|
|
895
|
+
}
|
|
896
|
+
if (config.includes("strataWP({")) {
|
|
897
|
+
const designSystemConfig = `
|
|
898
|
+
designSystem: {
|
|
899
|
+
enabled: true,
|
|
900
|
+
framework: '${framework}',
|
|
901
|
+
wordpressPresets: true,
|
|
902
|
+
},`;
|
|
903
|
+
config = config.replace(/(\s+}[\s\n]*\)[\s\n]*,?[\s\n]*plugins:)/, `${designSystemConfig}$1`);
|
|
904
|
+
if (framework === "unocss" && !config.includes("UnoCSS()")) {
|
|
905
|
+
config = config.replace(/(plugins:\s*\[)/, "$1\n UnoCSS(),");
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
await writeFile(viteConfigPath, config);
|
|
909
|
+
spinner.succeed(chalk9.green("Updated vite.config.ts"));
|
|
910
|
+
} catch (error) {
|
|
911
|
+
spinner.fail("Failed to update vite.config.ts");
|
|
912
|
+
console.warn(chalk9.yellow(" Please manually update your vite.config.ts"));
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
async function createCSSEntry(framework, cwd) {
|
|
916
|
+
const cssDir = path6.join(cwd, "src", "css");
|
|
917
|
+
const cssPath = path6.join(cssDir, "design-system.css");
|
|
918
|
+
let content;
|
|
919
|
+
if (framework === "tailwind") {
|
|
920
|
+
content = `/**
|
|
921
|
+
* Tailwind CSS Entry
|
|
922
|
+
*/
|
|
923
|
+
@tailwind base;
|
|
924
|
+
@tailwind components;
|
|
925
|
+
@tailwind utilities;
|
|
926
|
+
|
|
927
|
+
/* Custom component styles */
|
|
928
|
+
@layer components {
|
|
929
|
+
.btn {
|
|
930
|
+
@apply px-4 py-2 rounded bg-wp-primary text-white hover:bg-wp-secondary transition;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
`;
|
|
934
|
+
} else {
|
|
935
|
+
content = `/**
|
|
936
|
+
* UnoCSS Entry
|
|
937
|
+
*
|
|
938
|
+
* UnoCSS generates styles on-demand, so this file mainly contains
|
|
939
|
+
* custom CSS that isn't covered by utility classes.
|
|
940
|
+
*/
|
|
941
|
+
|
|
942
|
+
/* Custom component styles */
|
|
943
|
+
.btn {
|
|
944
|
+
padding: 1rem 1.5rem;
|
|
945
|
+
border-radius: 0.25rem;
|
|
946
|
+
background-color: var(--wp--preset--color--primary);
|
|
947
|
+
color: white;
|
|
948
|
+
transition: background-color 0.2s;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.btn:hover {
|
|
952
|
+
background-color: var(--wp--preset--color--secondary);
|
|
953
|
+
}
|
|
954
|
+
`;
|
|
955
|
+
}
|
|
956
|
+
await createFileWithSpinner(cssPath, content, "Creating design-system.css");
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// src/index.ts
|
|
960
|
+
var program = new Command();
|
|
961
|
+
program.name("stratawp").description("\u26A1 A modern WordPress theme framework").version("0.2.2");
|
|
962
|
+
program.command("dev").description("Start development server with hot reload").option("-p, --port <port>", "Port number", "3000").option("-h, --host <host>", "Host address", "localhost").action(devCommand);
|
|
963
|
+
program.command("build").description("Build theme for production").option("--analyze", "Analyze bundle size").action(buildCommand);
|
|
964
|
+
program.command("block:new <name>").description("Create a new Gutenberg block").option("-t, --type <type>", "Block type (static|dynamic)", "dynamic").option("--category <category>", "Block category", "common").option("--styleFramework <framework>", "Style framework (none|tailwind|unocss)", "none").action(blockCommand);
|
|
965
|
+
program.command("component:new <name>").description("Create a new theme component").option("-t, --type <type>", "Component type (service|feature|integration|custom)", "custom").option("--namespace <namespace>", "PHP namespace").action(componentCommand);
|
|
966
|
+
program.command("template:new <name>").description("Create a new WordPress template").option("-t, --type <type>", "Template type (page|single|archive|404|home|search|custom)", "page").option("--description <text>", "Template description").action(templateCommand);
|
|
967
|
+
program.command("part:new <name>").description("Create a new template part").option("-t, --type <type>", "Part type (header|footer|sidebar|content|custom)", "custom").option("--markup <markup>", "Markup style (html|php)", "php").action(partCommand);
|
|
968
|
+
program.command("design-system:setup <framework>").description("Set up a design system (tailwind|unocss)").action(designSystemCommand);
|
|
969
|
+
program.command("test").description("Run tests").option("--unit", "Run unit tests only").option("--e2e", "Run E2E tests only").option("--watch", "Watch mode").action(testCommand);
|
|
970
|
+
program.command("storybook").description("Launch component explorer").action(() => {
|
|
971
|
+
console.log(chalk10.cyan("\u{1F3AD} Launching component explorer..."));
|
|
972
|
+
console.log(chalk10.dim("Coming soon!"));
|
|
973
|
+
});
|
|
974
|
+
program.command("ai:block <description>").description("Generate block from description using AI").action((description) => {
|
|
975
|
+
console.log(chalk10.magenta("\u{1F916} AI Block Generator"));
|
|
976
|
+
console.log(chalk10.dim(`Description: ${description}`));
|
|
977
|
+
console.log(chalk10.yellow("\u26A0\uFE0F Coming soon!"));
|
|
978
|
+
});
|
|
979
|
+
program.command("ai:optimize").description("AI-powered performance optimization").action(() => {
|
|
980
|
+
console.log(chalk10.magenta("\u{1F916} AI Optimizer"));
|
|
981
|
+
console.log(chalk10.yellow("\u26A0\uFE0F Coming soon!"));
|
|
982
|
+
});
|
|
983
|
+
program.parse();
|