create-ng-tailwind 1.0.0 → 2.0.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.
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ defaultTemplate: "starter",
3
+ defaultProjectName: "my-angular-app",
4
+ skipInstall: false,
5
+ angularVersion: "latest",
6
+ tailwindVersion: "^4.0.0",
7
+ };
@@ -0,0 +1,97 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+ const execa = require("execa");
4
+ const TailwindManager = require("./TailwindManager");
5
+ const TemplateManager = require("./TemplateManager");
6
+ const { createAIConfigs } = require("../utils/ai-config");
7
+
8
+ class ProjectManager {
9
+ constructor(config, logger) {
10
+ this.config = config;
11
+ this.logger = logger;
12
+ this.tailwindManager = new TailwindManager(config, logger);
13
+ this.templateManager = new TemplateManager(config, logger);
14
+ }
15
+
16
+ async create() {
17
+ // Check if directory exists
18
+ if (await fs.pathExists(this.config.fullPath)) {
19
+ const { overwrite } = await this.logger.prompt([
20
+ {
21
+ type: "confirm",
22
+ name: "overwrite",
23
+ message: `Directory ${this.config.projectName} already exists. Overwrite?`,
24
+ default: false,
25
+ },
26
+ ]);
27
+
28
+ if (!overwrite) {
29
+ this.logger.warn("Operation cancelled");
30
+ process.exit(0);
31
+ }
32
+
33
+ await fs.remove(this.config.fullPath);
34
+ }
35
+
36
+ // Create Angular project
37
+ await this.createAngularProject();
38
+
39
+ // Configure Tailwind CSS
40
+ await this.tailwindManager.configure();
41
+
42
+ // Apply template
43
+ await this.templateManager.apply();
44
+
45
+ // Create AI configuration files (CLAUDE.md + tool-specific)
46
+ await createAIConfigs(
47
+ this.config.fullPath,
48
+ this.config.projectName,
49
+ this.config.aiConfig,
50
+ );
51
+ }
52
+
53
+ async createAngularProject() {
54
+ const spinner = this.logger.spinner("Creating Angular project...");
55
+
56
+ try {
57
+ // Build ng new command with user's choices
58
+ const routing = this.config.routing !== false;
59
+ const ssr = this.config.ssr || false;
60
+ const zoneless = this.config.zoneless || false;
61
+ const aiConfig = this.config.aiConfig || ["none"];
62
+
63
+ let cmd = `npx @angular/cli@latest new ${this.config.projectName}`;
64
+ cmd += ` --routing=${routing}`;
65
+ cmd += ` --style=css`; // Always use CSS (Tailwind v4 official approach)
66
+ cmd += ` --ssr=${ssr}`;
67
+
68
+ if (zoneless) {
69
+ cmd += ` --zoneless`;
70
+ }
71
+
72
+ // Add AI config - Angular CLI supports multiple --ai-config flags
73
+ if (aiConfig.length > 0 && !aiConfig.includes("none")) {
74
+ // Add each AI tool as a separate --ai-config flag
75
+ aiConfig.forEach((tool) => {
76
+ if (tool !== "none") {
77
+ cmd += ` --ai-config=${tool}`;
78
+ }
79
+ });
80
+ }
81
+
82
+ cmd += ` --skip-git --package-manager=npm --interactive=false`;
83
+
84
+ await execa.command(cmd, {
85
+ cwd: process.cwd(),
86
+ stdio: "pipe",
87
+ });
88
+
89
+ spinner.succeed("Angular project created");
90
+ } catch (error) {
91
+ spinner.fail("Failed to create Angular project");
92
+ throw error;
93
+ }
94
+ }
95
+ }
96
+
97
+ module.exports = ProjectManager;
@@ -0,0 +1,100 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+ const execa = require("execa");
4
+
5
+ class TailwindManager {
6
+ constructor(config, logger) {
7
+ this.config = config;
8
+ this.logger = logger;
9
+ }
10
+
11
+ async configure() {
12
+ const chalk = require("chalk");
13
+ const spinner = this.logger.spinner("Configuring Tailwind CSS...");
14
+
15
+ try {
16
+ // Install Tailwind v4 with @tailwindcss/postcss
17
+ if (!this.config.skipInstall) {
18
+ spinner.update("Installing Tailwind CSS packages...");
19
+ await execa.command(
20
+ "npm install tailwindcss @tailwindcss/postcss postcss --force",
21
+ {
22
+ cwd: this.config.fullPath,
23
+ stdio: "pipe",
24
+ },
25
+ );
26
+ spinner.stop();
27
+ console.log(chalk.green(" ✔ Tailwind CSS v4 packages installed (tailwindcss, @tailwindcss/postcss, postcss)"));
28
+ spinner.start();
29
+ } else {
30
+ await this.addTailwindToPackageJson();
31
+ spinner.stop();
32
+ console.log(chalk.green(" ✔ Tailwind CSS packages added to package.json"));
33
+ spinner.start();
34
+ }
35
+
36
+ // Create PostCSS config (v4 approach)
37
+ spinner.update("Creating PostCSS configuration...");
38
+ await this.createPostCSSConfig();
39
+ spinner.stop();
40
+ console.log(chalk.green(" ✔ PostCSS configuration created (.postcssrc.json)"));
41
+ spinner.start();
42
+
43
+ // Update styles (v4 approach)
44
+ spinner.update("Setting up Tailwind CSS imports...");
45
+ await this.updateStyles();
46
+ spinner.stop();
47
+ console.log(chalk.green(" ✔ Tailwind CSS imported in styles.css"));
48
+
49
+ spinner.succeed("Tailwind CSS configured");
50
+ } catch (error) {
51
+ spinner.fail("Failed to configure Tailwind CSS");
52
+ throw error;
53
+ }
54
+ }
55
+
56
+ async addTailwindToPackageJson() {
57
+ const packageJsonPath = path.join(this.config.fullPath, "package.json");
58
+ const packageJson = await fs.readJson(packageJsonPath);
59
+
60
+ if (!packageJson.dependencies) {
61
+ packageJson.dependencies = {};
62
+ }
63
+
64
+ // Tailwind CSS v4 goes in dependencies, not devDependencies
65
+ packageJson.dependencies["tailwindcss"] = "^4.0.0";
66
+ packageJson.dependencies["@tailwindcss/postcss"] = "^4.0.0";
67
+ packageJson.dependencies["postcss"] = "^8.4.0";
68
+
69
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
70
+ }
71
+
72
+ async createPostCSSConfig() {
73
+ // Tailwind CSS v4 uses PostCSS plugin approach
74
+ const postcssConfig = {
75
+ plugins: {
76
+ "@tailwindcss/postcss": {},
77
+ },
78
+ };
79
+
80
+ await fs.writeFile(
81
+ path.join(this.config.fullPath, ".postcssrc.json"),
82
+ JSON.stringify(postcssConfig, null, 2),
83
+ );
84
+ }
85
+
86
+ async updateStyles() {
87
+ // Tailwind CSS v4 uses CSS only (official approach)
88
+ const stylesPath = path.join(this.config.fullPath, "src/styles.css");
89
+
90
+ // Tailwind CSS v4 import syntax
91
+ const stylesContent = `@import "tailwindcss";
92
+
93
+ /* Your custom styles here */
94
+ `;
95
+
96
+ await fs.writeFile(stylesPath, stylesContent);
97
+ }
98
+ }
99
+
100
+ module.exports = TailwindManager;
@@ -0,0 +1,39 @@
1
+ const templates = require("../templates");
2
+
3
+ class TemplateManager {
4
+ constructor(config, logger) {
5
+ this.config = config;
6
+ this.logger = logger;
7
+ }
8
+
9
+ async apply() {
10
+ const templateName = this.config.template || "minimal";
11
+ const template = templates[templateName];
12
+
13
+ if (!template) {
14
+ throw new Error(`Template '${templateName}' not found`);
15
+ }
16
+
17
+ // Start spinner - it will keep spinning throughout the process
18
+ const spinner = this.logger.spinner(`Applying ${templateName} template...`);
19
+
20
+ try {
21
+ // For starter template, show detailed progress with spinner updates
22
+ if (templateName === 'starter') {
23
+ // Pass spinner to template so it can update progress
24
+ await template.apply(this.config, spinner);
25
+ } else {
26
+ // For minimal template, just apply
27
+ await template.apply(this.config);
28
+ }
29
+
30
+ // Stop spinner with success message
31
+ spinner.succeed(`${templateName} template applied`);
32
+ } catch (error) {
33
+ spinner.fail(`Failed to apply ${templateName} template`);
34
+ throw error;
35
+ }
36
+ }
37
+ }
38
+
39
+ module.exports = TemplateManager;
@@ -0,0 +1,7 @@
1
+ const minimal = require("./minimal");
2
+ const starter = require("./starter");
3
+
4
+ module.exports = {
5
+ minimal,
6
+ starter,
7
+ };
@@ -0,0 +1,24 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+
4
+ const minimal = {
5
+ info: {
6
+ name: "Minimal",
7
+ description:
8
+ "Clean Angular + Tailwind CSS starter with zero additional features",
9
+ features: [
10
+ "Latest Angular standalone architecture",
11
+ "Tailwind CSS v4 with PostCSS",
12
+ "Clean project structure",
13
+ "Ready to build your own way",
14
+ ],
15
+ },
16
+
17
+ async apply(config) {
18
+ // Minimal template keeps only the basic Angular + Tailwind setup
19
+ // No additional features, components, or services added
20
+ // (No console output needed - TemplateManager shows final checkmark)
21
+ },
22
+ };
23
+
24
+ module.exports = minimal;