@shivasankaran18/stackd 1.4.0 → 1.5.0
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/apps/cli/src/cli.js +217 -0
- package/dist/apps/cli/src/commands/create.js +148 -0
- package/dist/apps/cli/src/scripts/Auth/jwt.js +78 -0
- package/dist/apps/cli/src/scripts/Auth/nextAuth.js +131 -0
- package/dist/apps/cli/src/scripts/Auth/passport.js +218 -0
- package/dist/apps/cli/src/scripts/backend/django.js +20 -0
- package/dist/apps/cli/src/scripts/backend/expressjs.js +58 -0
- package/dist/apps/cli/src/scripts/backend/expressts.js +83 -0
- package/dist/apps/cli/src/scripts/frontend/angularjs.js +1 -0
- package/dist/apps/cli/src/scripts/frontend/angularts.js +22 -0
- package/dist/apps/cli/src/scripts/frontend/nextjs.js +62 -0
- package/dist/apps/cli/src/scripts/frontend/reactjs.js +31 -0
- package/dist/apps/cli/src/scripts/frontend/reactts.js +30 -0
- package/dist/apps/cli/src/scripts/frontend/vuejs.js +37 -0
- package/dist/apps/cli/src/scripts/frontend/vuets.js +43 -0
- package/dist/apps/cli/src/scripts/orms/drizzleSetup.js +85 -0
- package/dist/apps/cli/src/scripts/orms/mongoSetup.js +53 -0
- package/dist/apps/cli/src/scripts/orms/prismaSetup.js +12 -0
- package/dist/apps/cli/src/scripts/ui/shadcn.js +207 -0
- package/dist/apps/cli/src/scripts/ui/tailwindcss.js +102 -0
- package/dist/apps/web/app/api/auth/[...nextauth]/route.js +5 -0
- package/dist/apps/web/app/api/scaffold/route.js +251 -0
- package/dist/apps/web/app/home/page.js +19 -0
- package/dist/apps/web/app/layout.js +19 -0
- package/dist/apps/web/app/page.js +1 -0
- package/dist/apps/web/app/providers.js +7 -0
- package/dist/apps/web/app/scaffold/page.js +326 -0
- package/dist/apps/web/components/Sidebar.js +54 -0
- package/dist/apps/web/components/theme-provider.js +6 -0
- package/dist/apps/web/components/ui/button.js +32 -0
- package/dist/apps/web/components/ui/card.js +15 -0
- package/dist/apps/web/components/ui/dropdown-menu.js +54 -0
- package/dist/apps/web/components/ui/input.js +7 -0
- package/dist/apps/web/components/ui/label.js +9 -0
- package/dist/apps/web/components/ui/scroll-area.js +19 -0
- package/dist/apps/web/components/ui/sonner.js +15 -0
- package/dist/apps/web/components/ui/steps.js +14 -0
- package/dist/apps/web/components/ui/switch.js +9 -0
- package/dist/apps/web/lib/auth.js +32 -0
- package/dist/apps/web/lib/redis.js +9 -0
- package/dist/apps/web/lib/utils.js +5 -0
- package/dist/packages/scripts/Auth/jwt.js +78 -0
- package/dist/packages/scripts/Auth/nextAuth.js +131 -0
- package/dist/packages/scripts/Auth/passport.js +218 -0
- package/dist/packages/scripts/backend/django.js +20 -0
- package/dist/packages/scripts/backend/expressjs.js +58 -0
- package/dist/packages/scripts/backend/expressts.js +83 -0
- package/dist/packages/scripts/frontend/angularjs.js +1 -0
- package/dist/packages/scripts/frontend/angularts.js +22 -0
- package/dist/packages/scripts/frontend/nextjs.js +62 -0
- package/dist/packages/scripts/frontend/reactjs.js +31 -0
- package/dist/packages/scripts/frontend/reactts.js +30 -0
- package/dist/packages/scripts/frontend/vuejs.js +37 -0
- package/dist/packages/scripts/frontend/vuets.js +43 -0
- package/dist/packages/scripts/orms/drizzleSetup.js +85 -0
- package/dist/packages/scripts/orms/mongoSetup.js +53 -0
- package/dist/packages/scripts/orms/prismaSetup.js +12 -0
- package/dist/packages/scripts/ui/shadcn.js +207 -0
- package/dist/packages/scripts/ui/tailwindcss.js +102 -0
- package/dist/packages/ui/src/button.js +10 -0
- package/dist/packages/ui/src/card.js +11 -0
- package/dist/packages/ui/src/code.js +6 -0
- package/dist/packages/ui/turbo/generators/config.js +30 -0
- package/dist/stackd.js +114 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
@@ -0,0 +1,85 @@
|
|
1
|
+
import { join } from 'node:path';
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
3
|
+
import 'dotenv/config';
|
4
|
+
export async function setupDrizzle(config, projectDir, emitLog) {
|
5
|
+
try {
|
6
|
+
emitLog('Starting Drizzle ORM setup...');
|
7
|
+
const backendDir = join(projectDir, 'backend');
|
8
|
+
const dbDir = join(backendDir, 'src', 'db');
|
9
|
+
const schemasDir = join(dbDir, 'schema');
|
10
|
+
emitLog('Creating directory structure...');
|
11
|
+
await mkdir(schemasDir, { recursive: true });
|
12
|
+
emitLog('✅ Directory structure created');
|
13
|
+
emitLog('Generating environment configuration...');
|
14
|
+
const envContent = `
|
15
|
+
# Database Configuration
|
16
|
+
${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'}=postgres://user:password@localhost:5432/${config.databaseName || 'myapp'}
|
17
|
+
# Add other environment variables here
|
18
|
+
NODE_ENV=development
|
19
|
+
PORT=3000
|
20
|
+
`;
|
21
|
+
await writeFile(join(backendDir, '.env'), envContent.trim() + '\n');
|
22
|
+
emitLog('✅ Environment configuration created');
|
23
|
+
emitLog('Setting up database connection...');
|
24
|
+
const dbCode = `
|
25
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
26
|
+
import { Pool } from 'pg';
|
27
|
+
import 'dotenv/config';
|
28
|
+
|
29
|
+
const pool = new Pool({
|
30
|
+
connectionString: process.env.${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'},
|
31
|
+
});
|
32
|
+
|
33
|
+
export const db = drizzle(pool);
|
34
|
+
|
35
|
+
export async function connectDB() {
|
36
|
+
try {
|
37
|
+
await pool.connect();
|
38
|
+
console.log('Connected to PostgreSQL database');
|
39
|
+
} catch (error) {
|
40
|
+
console.error('Database connection error:', error);
|
41
|
+
process.exit(1);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
export async function disconnectDB() {
|
46
|
+
await pool.end();
|
47
|
+
console.log('Disconnected from PostgreSQL database');
|
48
|
+
}
|
49
|
+
`;
|
50
|
+
await writeFile(join(dbDir, 'index.ts'), dbCode);
|
51
|
+
emitLog('✅ Database connection setup complete');
|
52
|
+
emitLog('Creating example schema...');
|
53
|
+
const exampleSchemaCode = `
|
54
|
+
import { pgTable, serial, varchar, timestamp } from 'drizzle-orm/pg-core';
|
55
|
+
|
56
|
+
export const examples = pgTable('examples', {
|
57
|
+
id: serial('id').primaryKey(),
|
58
|
+
name: varchar('name', { length: 256 }).notNull(),
|
59
|
+
createdAt: timestamp('created_at').defaultNow(),
|
60
|
+
});
|
61
|
+
`;
|
62
|
+
await writeFile(join(schemasDir, 'example.ts'), exampleSchemaCode);
|
63
|
+
emitLog('✅ Example schema created');
|
64
|
+
emitLog('Configuring Drizzle migrations...');
|
65
|
+
const drizzleConfigCode = `
|
66
|
+
import type { Config } from 'drizzle-kit';
|
67
|
+
|
68
|
+
export default {
|
69
|
+
schema: './src/db/schema/*',
|
70
|
+
out: './src/db/migrations',
|
71
|
+
driver: 'pg',
|
72
|
+
dbCredentials: {
|
73
|
+
connectionString: process.env.${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'}!,
|
74
|
+
},
|
75
|
+
} satisfies Config;
|
76
|
+
`;
|
77
|
+
await writeFile(join(backendDir, 'drizzle.config.ts'), drizzleConfigCode);
|
78
|
+
emitLog('✅ Drizzle configuration complete');
|
79
|
+
emitLog('✅ Drizzle ORM setup completed successfully!');
|
80
|
+
}
|
81
|
+
catch (error) {
|
82
|
+
emitLog(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
83
|
+
throw error;
|
84
|
+
}
|
85
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { join } from 'node:path';
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
3
|
+
import 'dotenv/config';
|
4
|
+
export async function setupMongoose(config, projectDir, emitLog) {
|
5
|
+
const backendDir = join(projectDir, 'backend');
|
6
|
+
const modelsDir = join(backendDir, 'src', 'models');
|
7
|
+
await mkdir(modelsDir, { recursive: true });
|
8
|
+
emitLog('Generating environment configuration...');
|
9
|
+
const envContent = `
|
10
|
+
# MongoDB Configuration
|
11
|
+
${config.env?.MONGODB_URI_ENV || 'MONGODB_URI'}=mongodb://localhost:27017/${config.databaseName || 'myapp'}
|
12
|
+
|
13
|
+
# Add other environment variables here
|
14
|
+
NODE_ENV=development
|
15
|
+
PORT=3000
|
16
|
+
`;
|
17
|
+
await writeFile(join(backendDir, '.env'), envContent.trim() + '\n');
|
18
|
+
emitLog('✅ Environment configuration created');
|
19
|
+
emitLog('Setting up database connection...');
|
20
|
+
const dbCode = `
|
21
|
+
import mongoose from 'mongoose';
|
22
|
+
|
23
|
+
const MONGODB_URI = process.env.${config.env?.MONGODB_URI_ENV || 'MONGODB_URI'} || 'mongodb://localhost:27017/${config.databaseName || 'myapp'}';
|
24
|
+
|
25
|
+
export async function connectDB() {
|
26
|
+
try {
|
27
|
+
await mongoose.connect(MONGODB_URI);
|
28
|
+
console.log('Connected to MongoDB');
|
29
|
+
} catch (error) {
|
30
|
+
console.error('MongoDB connection error:', error);
|
31
|
+
process.exit(1);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
export async function disconnectDB() {
|
36
|
+
await mongoose.disconnect();
|
37
|
+
console.log('Disconnected from MongoDB');
|
38
|
+
}
|
39
|
+
`;
|
40
|
+
emitLog('✅ Database connection setup complete');
|
41
|
+
await writeFile(join(backendDir, 'db.ts'), dbCode);
|
42
|
+
const exampleModelCode = `
|
43
|
+
import mongoose from 'mongoose';
|
44
|
+
|
45
|
+
const exampleSchema = new mongoose.Schema({
|
46
|
+
name: { type: String, required: true },
|
47
|
+
createdAt: { type: Date, default: Date.now },
|
48
|
+
});
|
49
|
+
|
50
|
+
export const Example = mongoose.model('Example', exampleSchema);
|
51
|
+
`;
|
52
|
+
await writeFile(join(modelsDir, 'example.ts'), exampleModelCode);
|
53
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { join } from 'node:path';
|
2
|
+
import { execSync } from 'node:child_process';
|
3
|
+
import { writeFileSync } from 'node:fs';
|
4
|
+
export async function setupPrisma(config, projectDir, emitLog) {
|
5
|
+
emitLog('Setting up Prisma...');
|
6
|
+
const backendDir = join(projectDir, 'backend');
|
7
|
+
const envContent = `DATABASE_URL=${config.dbUrl}\n`;
|
8
|
+
writeFileSync(join(projectDir, 'backend', '.env'), envContent);
|
9
|
+
await execSync('npm install prisma', { cwd: backendDir });
|
10
|
+
await execSync('npx prisma init', { cwd: backendDir });
|
11
|
+
emitLog('✅ Prisma setup complete');
|
12
|
+
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
import { writeFile, mkdir } from 'fs/promises';
|
2
|
+
import { join } from 'path';
|
3
|
+
import { execSync } from 'child_process';
|
4
|
+
import { existsSync } from 'fs';
|
5
|
+
export async function setupShadcn(config, projectDir, emitLog) {
|
6
|
+
try {
|
7
|
+
const frontendDir = join(projectDir, 'frontend');
|
8
|
+
emitLog('📦 Setting up shadcn/ui...');
|
9
|
+
// Make sure Tailwind is set up first
|
10
|
+
emitLog('Ensuring Tailwind CSS is set up...');
|
11
|
+
// Install shadcn/ui dependencies
|
12
|
+
emitLog('Installing shadcn/ui dependencies...');
|
13
|
+
execSync('npm install @shadcn/ui class-variance-authority clsx tailwind-merge lucide-react', {
|
14
|
+
cwd: frontendDir,
|
15
|
+
stdio: 'inherit'
|
16
|
+
});
|
17
|
+
// Create components.json configuration
|
18
|
+
const componentsConfig = {
|
19
|
+
$schema: "https://ui.shadcn.com/schema.json",
|
20
|
+
style: "default",
|
21
|
+
rsc: false,
|
22
|
+
tailwind: {
|
23
|
+
config: "tailwind.config.js",
|
24
|
+
css: "src/index.css",
|
25
|
+
baseColor: "slate",
|
26
|
+
cssVariables: true,
|
27
|
+
},
|
28
|
+
aliases: {
|
29
|
+
components: "@/components",
|
30
|
+
utils: "@/lib/utils"
|
31
|
+
}
|
32
|
+
};
|
33
|
+
await writeFile(join(frontendDir, 'components.json'), JSON.stringify(componentsConfig, null, 2));
|
34
|
+
// Create utils file
|
35
|
+
const utilsDir = join(frontendDir, 'src', 'lib');
|
36
|
+
if (!existsSync(utilsDir)) {
|
37
|
+
await mkdir(utilsDir, { recursive: true });
|
38
|
+
}
|
39
|
+
const utilsContent = `
|
40
|
+
import { type ClassValue, clsx } from "clsx"
|
41
|
+
import { twMerge } from "tailwind-merge"
|
42
|
+
|
43
|
+
export function cn(...inputs: ClassValue[]) {
|
44
|
+
return twMerge(clsx(inputs))
|
45
|
+
}
|
46
|
+
`;
|
47
|
+
await writeFile(join(utilsDir, 'utils.ts'), utilsContent.trim() + '\n');
|
48
|
+
emitLog('✅ shadcn/ui setup completed successfully!');
|
49
|
+
}
|
50
|
+
catch (error) {
|
51
|
+
emitLog(`❌ Error setting up shadcn/ui: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
52
|
+
throw error;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
function generateShadcnTailwindConfig(frontend) {
|
56
|
+
const baseConfig = {
|
57
|
+
darkMode: ["class"],
|
58
|
+
content: frontend === 'django'
|
59
|
+
? ["./templates/**/*.html", "./static/**/*.{js,ts}"]
|
60
|
+
: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,vue}"],
|
61
|
+
theme: {
|
62
|
+
container: {
|
63
|
+
center: true,
|
64
|
+
padding: "2rem",
|
65
|
+
screens: {
|
66
|
+
"2xl": "1400px",
|
67
|
+
},
|
68
|
+
},
|
69
|
+
extend: {
|
70
|
+
colors: {
|
71
|
+
border: "hsl(var(--border))",
|
72
|
+
input: "hsl(var(--input))",
|
73
|
+
ring: "hsl(var(--ring))",
|
74
|
+
background: "hsl(var(--background))",
|
75
|
+
foreground: "hsl(var(--foreground))",
|
76
|
+
primary: {
|
77
|
+
DEFAULT: "hsl(var(--primary))",
|
78
|
+
foreground: "hsl(var(--primary-foreground))",
|
79
|
+
},
|
80
|
+
secondary: {
|
81
|
+
DEFAULT: "hsl(var(--secondary))",
|
82
|
+
foreground: "hsl(var(--secondary-foreground))",
|
83
|
+
},
|
84
|
+
destructive: {
|
85
|
+
DEFAULT: "hsl(var(--destructive))",
|
86
|
+
foreground: "hsl(var(--destructive-foreground))",
|
87
|
+
},
|
88
|
+
muted: {
|
89
|
+
DEFAULT: "hsl(var(--muted))",
|
90
|
+
foreground: "hsl(var(--muted-foreground))",
|
91
|
+
},
|
92
|
+
accent: {
|
93
|
+
DEFAULT: "hsl(var(--accent))",
|
94
|
+
foreground: "hsl(var(--accent-foreground))",
|
95
|
+
},
|
96
|
+
popover: {
|
97
|
+
DEFAULT: "hsl(var(--popover))",
|
98
|
+
foreground: "hsl(var(--popover-foreground))",
|
99
|
+
},
|
100
|
+
card: {
|
101
|
+
DEFAULT: "hsl(var(--card))",
|
102
|
+
foreground: "hsl(var(--card-foreground))",
|
103
|
+
},
|
104
|
+
},
|
105
|
+
borderRadius: {
|
106
|
+
lg: "var(--radius)",
|
107
|
+
md: "calc(var(--radius) - 2px)",
|
108
|
+
sm: "calc(var(--radius) - 4px)",
|
109
|
+
},
|
110
|
+
keyframes: {
|
111
|
+
"accordion-down": {
|
112
|
+
from: { height: "0" },
|
113
|
+
to: { height: "var(--radix-accordion-content-height)" },
|
114
|
+
},
|
115
|
+
"accordion-up": {
|
116
|
+
from: { height: "var(--radix-accordion-content-height)" },
|
117
|
+
to: { height: "0" },
|
118
|
+
},
|
119
|
+
},
|
120
|
+
animation: {
|
121
|
+
"accordion-down": "accordion-down 0.2s ease-out",
|
122
|
+
"accordion-up": "accordion-up 0.2s ease-out",
|
123
|
+
},
|
124
|
+
},
|
125
|
+
},
|
126
|
+
plugins: ["require('tailwindcss-animate')"],
|
127
|
+
};
|
128
|
+
return `/** @type {import('tailwindcss').Config} */
|
129
|
+
export default ${JSON.stringify(baseConfig, null, 2)}`;
|
130
|
+
}
|
131
|
+
function generateShadcnStyles(frontend) {
|
132
|
+
return `@tailwind base;
|
133
|
+
@tailwind components;
|
134
|
+
@tailwind utilities;
|
135
|
+
@layer base {
|
136
|
+
:root {
|
137
|
+
--background: 0 0% 100%;
|
138
|
+
--foreground: 222.2 84% 4.9%;
|
139
|
+
|
140
|
+
--card: 0 0% 100%;
|
141
|
+
--card-foreground: 222.2 84% 4.9%;
|
142
|
+
|
143
|
+
--popover: 0 0% 100%;
|
144
|
+
--popover-foreground: 222.2 84% 4.9%;
|
145
|
+
|
146
|
+
--primary: 222.2 47.4% 11.2%;
|
147
|
+
--primary-foreground: 210 40% 98%;
|
148
|
+
|
149
|
+
--secondary: 210 40% 96.1%;
|
150
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
151
|
+
|
152
|
+
--muted: 210 40% 96.1%;
|
153
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
154
|
+
|
155
|
+
--accent: 210 40% 96.1%;
|
156
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
157
|
+
|
158
|
+
--destructive: 0 84.2% 60.2%;
|
159
|
+
--destructive-foreground: 210 40% 98%;
|
160
|
+
|
161
|
+
--border: 214.3 31.8% 91.4%;
|
162
|
+
--input: 214.3 31.8% 91.4%;
|
163
|
+
--ring: 222.2 84% 4.9%;
|
164
|
+
|
165
|
+
--radius: 0.5rem;
|
166
|
+
}
|
167
|
+
|
168
|
+
.dark {
|
169
|
+
--background: 222.2 84% 4.9%;
|
170
|
+
--foreground: 210 40% 98%;
|
171
|
+
|
172
|
+
--card: 222.2 84% 4.9%;
|
173
|
+
--card-foreground: 210 40% 98%;
|
174
|
+
|
175
|
+
--popover: 222.2 84% 4.9%;
|
176
|
+
--popover-foreground: 210 40% 98%;
|
177
|
+
|
178
|
+
--primary: 210 40% 98%;
|
179
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
180
|
+
|
181
|
+
--secondary: 217.2 32.6% 17.5%;
|
182
|
+
--secondary-foreground: 210 40% 98%;
|
183
|
+
|
184
|
+
--muted: 217.2 32.6% 17.5%;
|
185
|
+
--muted-foreground: 215 20.2% 65.1%;
|
186
|
+
|
187
|
+
--accent: 217.2 32.6% 17.5%;
|
188
|
+
--accent-foreground: 210 40% 98%;
|
189
|
+
|
190
|
+
--destructive: 0 62.8% 30.6%;
|
191
|
+
--destructive-foreground: 210 40% 98%;
|
192
|
+
|
193
|
+
--border: 217.2 32.6% 17.5%;
|
194
|
+
--input: 217.2 32.6% 17.5%;
|
195
|
+
--ring: 212.7 26.8% 83.9%;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
@layer base {
|
200
|
+
* {
|
201
|
+
@apply border-border;
|
202
|
+
}
|
203
|
+
body {
|
204
|
+
@apply bg-background text-foreground;
|
205
|
+
}
|
206
|
+
}`;
|
207
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
2
|
+
import { join } from 'node:path';
|
3
|
+
import { execSync } from 'child_process';
|
4
|
+
import { existsSync } from 'fs';
|
5
|
+
import { mkdir } from 'fs/promises';
|
6
|
+
export async function setupTailwindCSS(config, projectDir, emitLog) {
|
7
|
+
try {
|
8
|
+
const frontendDir = join(projectDir, 'frontend');
|
9
|
+
const srcDir = join(frontendDir, 'src');
|
10
|
+
// Ensure directories exist
|
11
|
+
if (!existsSync(frontendDir)) {
|
12
|
+
emitLog('Creating frontend directory...');
|
13
|
+
await mkdir(frontendDir, { recursive: true });
|
14
|
+
}
|
15
|
+
if (!existsSync(srcDir)) {
|
16
|
+
emitLog('Creating src directory...');
|
17
|
+
await mkdir(srcDir, { recursive: true });
|
18
|
+
}
|
19
|
+
// Initialize package.json if it doesn't exist
|
20
|
+
if (!existsSync(join(frontendDir, 'package.json'))) {
|
21
|
+
emitLog('Initializing package.json...');
|
22
|
+
execSync('npm init -y', {
|
23
|
+
cwd: frontendDir,
|
24
|
+
stdio: 'inherit'
|
25
|
+
});
|
26
|
+
}
|
27
|
+
// Install dependencies using npm directly
|
28
|
+
emitLog('Installing Tailwind CSS dependencies...');
|
29
|
+
execSync('npm install tailwindcss@latest postcss@latest autoprefixer@latest --save-dev', {
|
30
|
+
cwd: frontendDir,
|
31
|
+
stdio: 'inherit'
|
32
|
+
});
|
33
|
+
// Create tailwind.config.js manually instead of using npx
|
34
|
+
emitLog('Creating Tailwind configuration...');
|
35
|
+
const tailwindConfig = generateTailwindConfig(config.frontend);
|
36
|
+
await writeFile(join(frontendDir, 'tailwind.config.js'), tailwindConfig);
|
37
|
+
// Create postcss.config.js
|
38
|
+
emitLog('Creating PostCSS configuration...');
|
39
|
+
const postcssConfig = `
|
40
|
+
module.exports = {
|
41
|
+
plugins: {
|
42
|
+
tailwindcss: {},
|
43
|
+
autoprefixer: {},
|
44
|
+
},
|
45
|
+
}`;
|
46
|
+
await writeFile(join(frontendDir, 'postcss.config.js'), postcssConfig);
|
47
|
+
// Add Tailwind directives to CSS
|
48
|
+
emitLog('Creating CSS file with Tailwind directives...');
|
49
|
+
const tailwindDirectives = `
|
50
|
+
@tailwind base;
|
51
|
+
@tailwind components;
|
52
|
+
@tailwind utilities;
|
53
|
+
`;
|
54
|
+
await writeFile(join(srcDir, 'index.css'), tailwindDirectives);
|
55
|
+
emitLog('✅ Tailwind CSS setup completed successfully!');
|
56
|
+
}
|
57
|
+
catch (error) {
|
58
|
+
emitLog(`❌ Error setting up Tailwind CSS: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
59
|
+
throw error;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
function generateTailwindConfig(framework) {
|
63
|
+
const baseConfig = {
|
64
|
+
content: [
|
65
|
+
"./index.html",
|
66
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
67
|
+
],
|
68
|
+
theme: {
|
69
|
+
extend: {
|
70
|
+
colors: {
|
71
|
+
background: 'hsl(var(--background))',
|
72
|
+
foreground: 'hsl(var(--foreground))',
|
73
|
+
},
|
74
|
+
},
|
75
|
+
},
|
76
|
+
plugins: [],
|
77
|
+
};
|
78
|
+
switch (framework) {
|
79
|
+
case 'react-ts':
|
80
|
+
case 'react':
|
81
|
+
baseConfig.content = [
|
82
|
+
"./index.html",
|
83
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
84
|
+
];
|
85
|
+
break;
|
86
|
+
case 'vue-ts':
|
87
|
+
case 'vue':
|
88
|
+
baseConfig.content = [
|
89
|
+
"./index.html",
|
90
|
+
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
91
|
+
];
|
92
|
+
break;
|
93
|
+
case 'django':
|
94
|
+
baseConfig.content = [
|
95
|
+
"./templates/**/*.html",
|
96
|
+
"./static/**/*.{js,ts}",
|
97
|
+
];
|
98
|
+
break;
|
99
|
+
}
|
100
|
+
return `/** @type {import('tailwindcss').Config} */
|
101
|
+
module.exports = ${JSON.stringify(baseConfig, null, 2)}`;
|
102
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"use client";
|
2
|
+
"use strict";
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
4
|
+
exports.Button = void 0;
|
5
|
+
const Button = ({ children, className, appName }) => {
|
6
|
+
return (<button className={className} onClick={() => alert(`Hello from your ${appName} app!`)}>
|
7
|
+
{children}
|
8
|
+
</button>);
|
9
|
+
};
|
10
|
+
exports.Button = Button;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Card = Card;
|
4
|
+
function Card({ className, title, children, href, }) {
|
5
|
+
return (<a className={className} href={`${href}?utm_source=create-turbo&utm_medium=basic&utm_campaign=create-turbo"`} rel="noopener noreferrer" target="_blank">
|
6
|
+
<h2>
|
7
|
+
{title} <span>-></span>
|
8
|
+
</h2>
|
9
|
+
<p>{children}</p>
|
10
|
+
</a>);
|
11
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = generator;
|
4
|
+
// Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation
|
5
|
+
function generator(plop) {
|
6
|
+
// A simple generator to add a new React component to the internal UI library
|
7
|
+
plop.setGenerator("react-component", {
|
8
|
+
description: "Adds a new react component",
|
9
|
+
prompts: [
|
10
|
+
{
|
11
|
+
type: "input",
|
12
|
+
name: "name",
|
13
|
+
message: "What is the name of the component?",
|
14
|
+
},
|
15
|
+
],
|
16
|
+
actions: [
|
17
|
+
{
|
18
|
+
type: "add",
|
19
|
+
path: "src/{{kebabCase name}}.tsx",
|
20
|
+
templateFile: "templates/component.hbs",
|
21
|
+
},
|
22
|
+
{
|
23
|
+
type: "append",
|
24
|
+
path: "package.json",
|
25
|
+
pattern: /"exports": {(?<insertion>)/g,
|
26
|
+
template: ' "./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",',
|
27
|
+
},
|
28
|
+
],
|
29
|
+
});
|
30
|
+
}
|
package/dist/stackd.js
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env tsx
|
2
|
+
import { program } from 'commander';
|
3
|
+
import inquirer from 'inquirer';
|
4
|
+
import chalk from 'chalk';
|
5
|
+
import { spawn } from 'child_process';
|
6
|
+
import { join, dirname } from 'path';
|
7
|
+
import { fileURLToPath } from 'url';
|
8
|
+
import fs from 'fs';
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
10
|
+
const __dirname = dirname(__filename);
|
11
|
+
const getPackageRoot = () => {
|
12
|
+
let currentDir = __dirname;
|
13
|
+
while (!fs.existsSync(join(currentDir, 'package.json'))) {
|
14
|
+
const parentDir = dirname(currentDir);
|
15
|
+
if (parentDir === currentDir) {
|
16
|
+
return process.cwd();
|
17
|
+
}
|
18
|
+
currentDir = parentDir;
|
19
|
+
}
|
20
|
+
return currentDir;
|
21
|
+
};
|
22
|
+
const packageRoot = getPackageRoot();
|
23
|
+
const showBanner = () => {
|
24
|
+
console.log(chalk.cyan(`
|
25
|
+
██████╗████████╗ █████╗ ██████╗██╗ ██╗'██████╗
|
26
|
+
██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝██╔══██╗
|
27
|
+
╚█████╗ ██║ ███████║██║ █████═╝ ██║ ██║
|
28
|
+
╚═══██╗ ██║ ██╔══██║██║ ██╔═██╗ ██║ ██║
|
29
|
+
██████╔╝ ██║ ██║ ██║╚██████╗██║ ██╗██████╔╝
|
30
|
+
╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═════╝
|
31
|
+
`));
|
32
|
+
console.log(chalk.yellow.bold(' 🚀 Full Stack Project Generator\n'));
|
33
|
+
};
|
34
|
+
const createBorder = () => chalk.cyan('='.repeat(60));
|
35
|
+
const executeCommand = (command, cwd) => {
|
36
|
+
const [cmd, ...args] = command.split(' ');
|
37
|
+
const process = spawn(cmd, args, { cwd, stdio: 'inherit', shell: true });
|
38
|
+
process.on('error', (error) => {
|
39
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
40
|
+
});
|
41
|
+
return process;
|
42
|
+
};
|
43
|
+
const getAppPath = (appName) => {
|
44
|
+
const devPath = join(packageRoot, 'apps', appName);
|
45
|
+
if (fs.existsSync(devPath)) {
|
46
|
+
return devPath;
|
47
|
+
}
|
48
|
+
const publishedPath = join(packageRoot, 'node_modules', '@shivasankaran', 'stackd', 'apps', appName);
|
49
|
+
if (fs.existsSync(publishedPath)) {
|
50
|
+
return publishedPath;
|
51
|
+
}
|
52
|
+
return join(packageRoot, appName);
|
53
|
+
};
|
54
|
+
const initializeProject = async () => {
|
55
|
+
showBanner();
|
56
|
+
console.log(createBorder());
|
57
|
+
const answer = await inquirer.prompt([
|
58
|
+
{
|
59
|
+
type: 'list',
|
60
|
+
name: 'interface',
|
61
|
+
message: chalk.magenta.bold('🎯 Choose your preferred interface:'),
|
62
|
+
choices: [
|
63
|
+
{ name: chalk.blue('CLI Interface'), value: 'cli' },
|
64
|
+
{ name: chalk.green('Web Interface'), value: 'web' }
|
65
|
+
]
|
66
|
+
}
|
67
|
+
]);
|
68
|
+
try {
|
69
|
+
if (answer.interface === 'cli') {
|
70
|
+
console.log(chalk.blue('\n📦 Starting CLI interface...\n'));
|
71
|
+
const cliAppPath = getAppPath('cli');
|
72
|
+
const cliScriptPath = join(cliAppPath, 'src', 'cli.ts');
|
73
|
+
console.log(cliScriptPath);
|
74
|
+
if (!fs.existsSync(cliScriptPath)) {
|
75
|
+
console.log(chalk.yellow(`\nCLI script not found at ${cliScriptPath}. Trying alternative paths...\n`));
|
76
|
+
const command = 'npx tsx @stackd/cli/src/cli.ts run';
|
77
|
+
executeCommand(command, process.cwd());
|
78
|
+
}
|
79
|
+
else {
|
80
|
+
console.log("hello");
|
81
|
+
executeCommand(`npx tsx ${cliScriptPath} run`, process.cwd());
|
82
|
+
}
|
83
|
+
}
|
84
|
+
else {
|
85
|
+
const webAppPath = getAppPath('web');
|
86
|
+
console.log(chalk.green(`\n🌐 Setting up Web Interface at ${webAppPath}...\n`));
|
87
|
+
if (!fs.existsSync(webAppPath)) {
|
88
|
+
console.error(chalk.red(`\n❌ Web app directory not found at: ${webAppPath}`));
|
89
|
+
process.exit(1);
|
90
|
+
}
|
91
|
+
await executeCommand('npm install', webAppPath);
|
92
|
+
console.log(chalk.green('\n🚀 Starting Web Interface...'));
|
93
|
+
console.log(chalk.green('\n🌐 Web interface available at http://localhost:3000\n'));
|
94
|
+
executeCommand('npm run dev', webAppPath);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
console.error(chalk.red(`\n❌ Failed to start the selected interface: ${error.message}`));
|
99
|
+
process.exit(1);
|
100
|
+
}
|
101
|
+
};
|
102
|
+
program
|
103
|
+
.name('stackd')
|
104
|
+
.description('CLI tool for creating full-stack applications')
|
105
|
+
.version('6.0.0');
|
106
|
+
program
|
107
|
+
.command('init')
|
108
|
+
.action(initializeProject);
|
109
|
+
program
|
110
|
+
.action(() => {
|
111
|
+
console.log(chalk.yellow('\nNo command specified. Using "init" by default.\n'));
|
112
|
+
initializeProject();
|
113
|
+
});
|
114
|
+
program.parse(process.argv);
|
@@ -0,0 +1 @@
|
|
1
|
+
{"root":["../stackd.ts","../apps/cli/src/cli.ts","../apps/cli/src/commands/create.ts","../apps/cli/src/scripts/auth/jwt.ts","../apps/cli/src/scripts/auth/nextauth.ts","../apps/cli/src/scripts/auth/passport.ts","../apps/cli/src/scripts/backend/django.ts","../apps/cli/src/scripts/backend/expressjs.ts","../apps/cli/src/scripts/backend/expressts.ts","../apps/cli/src/scripts/frontend/angularjs.ts","../apps/cli/src/scripts/frontend/angularts.ts","../apps/cli/src/scripts/frontend/nextjs.ts","../apps/cli/src/scripts/frontend/reactjs.ts","../apps/cli/src/scripts/frontend/reactts.ts","../apps/cli/src/scripts/frontend/vuejs.ts","../apps/cli/src/scripts/frontend/vuets.ts","../apps/cli/src/scripts/orms/drizzlesetup.ts","../apps/cli/src/scripts/orms/mongosetup.ts","../apps/cli/src/scripts/orms/prismasetup.ts","../apps/cli/src/scripts/ui/shadcn.ts","../apps/cli/src/scripts/ui/tailwindcss.ts","../apps/web/next-env.d.ts","../apps/web/app/layout.tsx","../apps/web/app/page.tsx","../apps/web/app/providers.tsx","../apps/web/app/api/auth/[...nextauth]/route.ts","../apps/web/app/api/scaffold/route.ts","../apps/web/app/home/page.tsx","../apps/web/app/scaffold/page.tsx","../apps/web/components/sidebar.tsx","../apps/web/components/theme-provider.tsx","../apps/web/components/ui/button.tsx","../apps/web/components/ui/card.tsx","../apps/web/components/ui/dropdown-menu.tsx","../apps/web/components/ui/input.tsx","../apps/web/components/ui/label.tsx","../apps/web/components/ui/scroll-area.tsx","../apps/web/components/ui/sonner.tsx","../apps/web/components/ui/steps.tsx","../apps/web/components/ui/switch.tsx","../apps/web/lib/auth.ts","../apps/web/lib/redis.ts","../apps/web/lib/utils.ts","../apps/web/types/global.d.ts","../packages/scripts/auth/jwt.ts","../packages/scripts/auth/nextauth.ts","../packages/scripts/auth/passport.ts","../packages/scripts/backend/django.ts","../packages/scripts/backend/expressjs.ts","../packages/scripts/backend/expressts.ts","../packages/scripts/frontend/angularjs.ts","../packages/scripts/frontend/angularts.ts","../packages/scripts/frontend/nextjs.ts","../packages/scripts/frontend/reactjs.ts","../packages/scripts/frontend/reactts.ts","../packages/scripts/frontend/vuejs.ts","../packages/scripts/frontend/vuets.ts","../packages/scripts/orms/drizzlesetup.ts","../packages/scripts/orms/mongosetup.ts","../packages/scripts/orms/prismasetup.ts","../packages/scripts/ui/shadcn.ts","../packages/scripts/ui/tailwindcss.ts","../packages/ui/src/button.tsx","../packages/ui/src/card.tsx","../packages/ui/src/code.tsx","../packages/ui/turbo/generators/config.ts"],"errors":true,"version":"5.7.3"}
|