@shivasankaran18/stackd 1.1.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.
Files changed (109) hide show
  1. package/.github/workflows/ci.yml +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +115 -0
  4. package/apps/cli/package.json +32 -0
  5. package/apps/cli/src/cli.ts +271 -0
  6. package/apps/cli/src/commands/create.ts +162 -0
  7. package/apps/cli/src/scripts/Auth/jwt.ts +83 -0
  8. package/apps/cli/src/scripts/Auth/nextAuth.ts +146 -0
  9. package/apps/cli/src/scripts/Auth/passport.ts +234 -0
  10. package/apps/cli/src/scripts/backend/django.ts +30 -0
  11. package/apps/cli/src/scripts/backend/expressjs.ts +72 -0
  12. package/apps/cli/src/scripts/backend/expressts.ts +95 -0
  13. package/apps/cli/src/scripts/frontend/angularjs.ts +0 -0
  14. package/apps/cli/src/scripts/frontend/angularts.ts +29 -0
  15. package/apps/cli/src/scripts/frontend/nextjs.ts +72 -0
  16. package/apps/cli/src/scripts/frontend/reactjs.ts +36 -0
  17. package/apps/cli/src/scripts/frontend/reactts.ts +34 -0
  18. package/apps/cli/src/scripts/frontend/vuejs.ts +43 -0
  19. package/apps/cli/src/scripts/frontend/vuets.ts +53 -0
  20. package/apps/cli/src/scripts/orms/drizzleSetup.ts +102 -0
  21. package/apps/cli/src/scripts/orms/mongoSetup.ts +68 -0
  22. package/apps/cli/src/scripts/orms/prismaSetup.ts +14 -0
  23. package/apps/cli/src/scripts/ui/shadcn.ts +228 -0
  24. package/apps/cli/src/scripts/ui/tailwindcss.ts +126 -0
  25. package/apps/cli/tsconfig.json +111 -0
  26. package/apps/web/app/api/auth/[...nextauth]/route.ts +7 -0
  27. package/apps/web/app/api/scaffold/route.ts +274 -0
  28. package/apps/web/app/favicon.ico +0 -0
  29. package/apps/web/app/fonts/GeistMonoVF.woff +0 -0
  30. package/apps/web/app/fonts/GeistVF.woff +0 -0
  31. package/apps/web/app/globals.css +158 -0
  32. package/apps/web/app/home/page.tsx +22 -0
  33. package/apps/web/app/layout.tsx +35 -0
  34. package/apps/web/app/page.module.css +188 -0
  35. package/apps/web/app/page.tsx +1 -0
  36. package/apps/web/app/providers.tsx +9 -0
  37. package/apps/web/app/scaffold/page.tsx +472 -0
  38. package/apps/web/components/Sidebar.tsx +108 -0
  39. package/apps/web/components/theme-provider.tsx +9 -0
  40. package/apps/web/components/ui/button.tsx +57 -0
  41. package/apps/web/components/ui/card.tsx +76 -0
  42. package/apps/web/components/ui/dropdown-menu.tsx +200 -0
  43. package/apps/web/components/ui/input.tsx +22 -0
  44. package/apps/web/components/ui/label.tsx +26 -0
  45. package/apps/web/components/ui/scroll-area.tsx +48 -0
  46. package/apps/web/components/ui/sonner.tsx +31 -0
  47. package/apps/web/components/ui/steps.tsx +36 -0
  48. package/apps/web/components/ui/switch.tsx +29 -0
  49. package/apps/web/components.json +21 -0
  50. package/apps/web/eslint.config.js +4 -0
  51. package/apps/web/lib/auth.ts +35 -0
  52. package/apps/web/lib/redis.ts +13 -0
  53. package/apps/web/lib/utils.ts +8 -0
  54. package/apps/web/next-env.d.ts +5 -0
  55. package/apps/web/next.config.js +4 -0
  56. package/apps/web/package.json +52 -0
  57. package/apps/web/postcss.config.js +6 -0
  58. package/apps/web/public/file-text.svg +3 -0
  59. package/apps/web/public/globe.svg +10 -0
  60. package/apps/web/public/next.svg +1 -0
  61. package/apps/web/public/turborepo-dark.svg +19 -0
  62. package/apps/web/public/turborepo-light.svg +19 -0
  63. package/apps/web/public/vercel.svg +10 -0
  64. package/apps/web/public/window.svg +3 -0
  65. package/apps/web/tailwind.config.js +65 -0
  66. package/apps/web/tsconfig.json +23 -0
  67. package/apps/web/types/global.d.ts +4 -0
  68. package/docker-compose.yml +14 -0
  69. package/package.json +55 -0
  70. package/packages/eslint-config/README.md +3 -0
  71. package/packages/eslint-config/base.js +32 -0
  72. package/packages/eslint-config/next.js +49 -0
  73. package/packages/eslint-config/package.json +24 -0
  74. package/packages/eslint-config/react-internal.js +39 -0
  75. package/packages/scripts/Auth/jwt.ts +83 -0
  76. package/packages/scripts/Auth/nextAuth.ts +146 -0
  77. package/packages/scripts/Auth/passport.ts +234 -0
  78. package/packages/scripts/backend/django.ts +30 -0
  79. package/packages/scripts/backend/expressjs.ts +72 -0
  80. package/packages/scripts/backend/expressts.ts +95 -0
  81. package/packages/scripts/frontend/angularjs.ts +0 -0
  82. package/packages/scripts/frontend/angularts.ts +29 -0
  83. package/packages/scripts/frontend/nextjs.ts +72 -0
  84. package/packages/scripts/frontend/reactjs.ts +36 -0
  85. package/packages/scripts/frontend/reactts.ts +34 -0
  86. package/packages/scripts/frontend/vuejs.ts +43 -0
  87. package/packages/scripts/frontend/vuets.ts +53 -0
  88. package/packages/scripts/orms/drizzleSetup.ts +102 -0
  89. package/packages/scripts/orms/mongoSetup.ts +68 -0
  90. package/packages/scripts/orms/prismaSetup.ts +14 -0
  91. package/packages/scripts/ui/shadcn.ts +228 -0
  92. package/packages/scripts/ui/tailwindcss.ts +126 -0
  93. package/packages/typescript-config/base.json +19 -0
  94. package/packages/typescript-config/nextjs.json +12 -0
  95. package/packages/typescript-config/package.json +9 -0
  96. package/packages/typescript-config/react-library.json +7 -0
  97. package/packages/ui/eslint.config.mjs +4 -0
  98. package/packages/ui/package.json +27 -0
  99. package/packages/ui/src/button.tsx +20 -0
  100. package/packages/ui/src/card.tsx +27 -0
  101. package/packages/ui/src/code.tsx +11 -0
  102. package/packages/ui/tsconfig.json +8 -0
  103. package/packages/ui/turbo/generators/config.ts +30 -0
  104. package/packages/ui/turbo/generators/templates/component.hbs +8 -0
  105. package/stackd.ts +134 -0
  106. package/start-web.sh +5 -0
  107. package/tsconfig.json +111 -0
  108. package/tsconfig.tsbuildinfo +1 -0
  109. package/turbo.json +21 -0
@@ -0,0 +1,72 @@
1
+ // import { join } from 'node:path'
2
+ // import { execSync, ExecSyncOptions } from 'child_process'
3
+ // import { writeFile, mkdir } from 'node:fs/promises'
4
+ // import { existsSync } from 'fs'
5
+
6
+ // export async function createNextJS(config: any, projectDir: string, emitLog: (log: string) => void) {
7
+ // try {
8
+ // const frontendDir = join(projectDir, 'frontend');
9
+ // if (!existsSync(frontendDir)) {
10
+ // emitLog('Creating frontend directory...');
11
+ // await mkdir(frontendDir, { recursive: true });
12
+ // }
13
+ // emitLog('Creating Next.js project...');
14
+ // const execOptions: ExecSyncOptions = {
15
+ // cwd: frontendDir,
16
+ // stdio: 'inherit',
17
+ // encoding: 'utf-8'
18
+ // };
19
+
20
+ // execSync('npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --no-git', execOptions);
21
+
22
+ // emitLog('Updating package.json...');
23
+ // const packageJsonPath = join(frontendDir, 'package.json');
24
+ // const packageJson = require(packageJsonPath);
25
+
26
+ // packageJson.scripts.dev = `next dev -p ${config.frontendPort}`;
27
+
28
+ // await writeFile(
29
+ // packageJsonPath,
30
+ // JSON.stringify(packageJson, null, 2)
31
+ // );
32
+
33
+ // emitLog('Creating environment file...');
34
+ // const envContent = `
35
+ // NEXT_PUBLIC_API_URL=http://localhost:${config.backendPort}
36
+ // NEXTAUTH_URL=http://localhost:${config.frontendPort}
37
+ // NEXTAUTH_SECRET=your-secret-key-here
38
+ // `;
39
+
40
+ // await writeFile(
41
+ // join(frontendDir, '.env'),
42
+ // envContent.trim() + '\n'
43
+ // );
44
+
45
+ // emitLog('Setting up API proxy...');
46
+ // const nextConfigContent = `
47
+ // /** @type {import('next').NextConfig} */
48
+ // const nextConfig = {
49
+ // async rewrites() {
50
+ // return [
51
+ // {
52
+ // source: '/api/:path*',
53
+ // destination: 'http://localhost:${config.backendPort}/api/:path*'
54
+ // }
55
+ // ]
56
+ // }
57
+ // }
58
+
59
+ // module.exports = nextConfig
60
+ // `;
61
+
62
+ // await writeFile(
63
+ // join(frontendDir, 'next.config.js'),
64
+ // nextConfigContent.trim() + '\n'
65
+ // );
66
+
67
+ // emitLog('✅ Next.js setup completed successfully!');
68
+ // } catch (error) {
69
+ // emitLog(`❌ Error setting up Next.js: ${error instanceof Error ? error.message : 'Unknown error'}`);
70
+ // throw error;
71
+ // }
72
+ // }
@@ -0,0 +1,36 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+
5
+ export async function createReactJS(config: any, projectDir: string,emitLog: (log: string) => void) {
6
+ emitLog('Creating ReactJS project...');
7
+ await execSync(`npm create vite@latest frontend -- --template react`, {
8
+ cwd: projectDir,
9
+ stdio: 'inherit'
10
+ })
11
+ emitLog('Installing the dependencies for the frontend...');
12
+ await execSync("npm install",{cwd:projectDir + "/frontend",stdio:"inherit"});
13
+ emitLog('Writing Vite configuration...');
14
+ const viteConfig = `
15
+ import { defineConfig } from 'vite'
16
+ import react from '@vitejs/plugin-react'
17
+
18
+ export default defineConfig({
19
+ plugins: [react()],
20
+ server: {
21
+ port: ${config.frontendPort},
22
+ proxy: {
23
+ '/api': {
24
+ target: 'http://localhost:${config.backendPort}',
25
+ changeOrigin: true
26
+ }
27
+ }
28
+ }
29
+ })`
30
+
31
+ await writeFile(
32
+ join(projectDir, 'frontend', 'vite.config.js'),
33
+ viteConfig.trim()
34
+ )
35
+ emitLog('✅ ReactJS project created successfully!');
36
+ }
@@ -0,0 +1,34 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+
5
+ export async function createReactTS(config: any, projectDir: string,emitLog: (log: string) => void) {
6
+ emitLog('Creating ReactTS project...');
7
+ await execSync(`npm create vite@latest frontend -- --template react-ts`, {
8
+ cwd: projectDir,
9
+ stdio: 'inherit'
10
+ });
11
+ emitLog('Installing the dependencies...');
12
+ await execSync('npm install',{cwd : projectDir + '/frontend',stdio : 'inherit'});
13
+ emitLog('Writing Vite configuration...');
14
+ const viteConfig = `
15
+ import { defineConfig } from 'vite'
16
+ import react from '@vitejs/plugin-react'
17
+ export default defineConfig({
18
+ plugins: [react()],
19
+ server: {
20
+ port: ${config.frontendPort},
21
+ proxy: {
22
+ '/api': {
23
+ target: 'http://localhost:${config.backendPort}',
24
+ changeOrigin: true
25
+ }
26
+ }
27
+ }
28
+ })`
29
+ await writeFile(
30
+ join(projectDir, 'frontend', 'vite.config.ts'),
31
+ viteConfig.trim()
32
+ )
33
+ emitLog('✅ ReactTS project created successfully!');
34
+ }
@@ -0,0 +1,43 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+
5
+ export async function createVueJS(config: any, projectDir: string,emitLog: (log: string) => void) {
6
+ emitLog('Creating VueJS project...');
7
+ await execSync(`npm create vite@latest frontend -- --template vue`, {
8
+ cwd: projectDir,
9
+ stdio: 'inherit'
10
+ })
11
+
12
+ emitLog('Installing Vite...');
13
+ console.log(projectDir)
14
+ console.log(config)
15
+ const viteConfig = `
16
+ import { defineConfig } from 'vite'
17
+ import vue from '@vitejs/plugin-vue'
18
+
19
+ export default defineConfig({
20
+ plugins: [vue()],
21
+ server: {
22
+ port: ${config.frontendPort},
23
+ proxy: {
24
+ '/api': {
25
+ target: 'http://localhost:${config.backendPort}',
26
+ changeOrigin: true
27
+ }
28
+ }
29
+ }
30
+ })`
31
+
32
+ emitLog('Writing Vite configuration...');
33
+ await writeFile(
34
+ join(projectDir, 'frontend', `vite.config.js`),
35
+ viteConfig.trim()
36
+ )
37
+ emitLog('Installing Vue Router and Pinia...');
38
+ await execSync('npm install vue-router@4 pinia@2', {
39
+ cwd: join(projectDir, 'frontend'),
40
+ stdio: 'inherit'
41
+ })
42
+ emitLog('✅ VueJS project created successfully!');
43
+ }
@@ -0,0 +1,53 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+
5
+ export async function createVueTS(config: any, projectDir: string,emitLog: (log: string) => void) {
6
+ emitLog('Creating VueTS project...');
7
+
8
+ emitLog('Installing Vite...');
9
+ await execSync(`npm create vite@latest frontend -- --template vue-ts`, {
10
+ cwd: projectDir,
11
+ stdio: 'inherit'
12
+ })
13
+
14
+ emitLog('Configuring Vite...');
15
+ const viteConfig = `
16
+ import { defineConfig } from 'vite'
17
+ import vue from '@vitejs/plugin-vue'
18
+
19
+ export default defineConfig({
20
+ plugins: [vue()],
21
+ server: {
22
+ port: ${config.frontendPort},
23
+ proxy: {
24
+ '/api': {
25
+ target: 'http://localhost:${config.backendPort}',
26
+ changeOrigin: true
27
+ }
28
+ }
29
+ }
30
+ })`
31
+
32
+ emitLog('Writing Vite configuration...');
33
+ await writeFile(
34
+ join(projectDir, 'frontend', `vite.config.ts`),
35
+ viteConfig.trim()
36
+ )
37
+
38
+ emitLog('Installing Vue Router and Pinia...');
39
+ await execSync('npm install vue-router@4 pinia@2', {
40
+ cwd: join(projectDir, 'frontend'),
41
+ stdio: 'inherit'
42
+ })
43
+
44
+ emitLog('Installing TypeScript and other dependencies...');
45
+ if (config.frontend === 'vue-ts') {
46
+ await execSync('npm install -D @types/node', {
47
+ cwd: join(projectDir, 'frontend'),
48
+ stdio: 'inherit'
49
+ })
50
+ }
51
+
52
+ emitLog('✅ VueTS project created successfully!');
53
+ }
@@ -0,0 +1,102 @@
1
+ import { join } from 'node:path'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import 'dotenv/config'
4
+
5
+ export async function setupDrizzle(config: any, projectDir: string, emitLog: (log: string) => void) {
6
+ try {
7
+ emitLog('Starting Drizzle ORM setup...');
8
+ const backendDir = join(projectDir, 'backend');
9
+ const dbDir = join(backendDir, 'src', 'db');
10
+ const schemasDir = join(dbDir, 'schema');
11
+ emitLog('Creating directory structure...');
12
+ await mkdir(schemasDir, { recursive: true });
13
+ emitLog('✅ Directory structure created');
14
+
15
+ emitLog('Generating environment configuration...');
16
+ const envContent = `
17
+ # Database Configuration
18
+ ${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'}=postgres://user:password@localhost:5432/${config.databaseName || 'myapp'}
19
+ # Add other environment variables here
20
+ NODE_ENV=development
21
+ PORT=3000
22
+ `;
23
+ await writeFile(
24
+ join(backendDir, '.env'),
25
+ envContent.trim() + '\n'
26
+ );
27
+ emitLog('✅ Environment configuration created');
28
+
29
+ emitLog('Setting up database connection...');
30
+ const dbCode = `
31
+ import { drizzle } from 'drizzle-orm/node-postgres';
32
+ import { Pool } from 'pg';
33
+ import 'dotenv/config';
34
+
35
+ const pool = new Pool({
36
+ connectionString: process.env.${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'},
37
+ });
38
+
39
+ export const db = drizzle(pool);
40
+
41
+ export async function connectDB() {
42
+ try {
43
+ await pool.connect();
44
+ console.log('Connected to PostgreSQL database');
45
+ } catch (error) {
46
+ console.error('Database connection error:', error);
47
+ process.exit(1);
48
+ }
49
+ }
50
+
51
+ export async function disconnectDB() {
52
+ await pool.end();
53
+ console.log('Disconnected from PostgreSQL database');
54
+ }
55
+ `;
56
+ await writeFile(
57
+ join(dbDir, 'index.ts'),
58
+ dbCode
59
+ );
60
+ emitLog('✅ Database connection setup complete');
61
+
62
+ emitLog('Creating example schema...');
63
+ const exampleSchemaCode = `
64
+ import { pgTable, serial, varchar, timestamp } from 'drizzle-orm/pg-core';
65
+
66
+ export const examples = pgTable('examples', {
67
+ id: serial('id').primaryKey(),
68
+ name: varchar('name', { length: 256 }).notNull(),
69
+ createdAt: timestamp('created_at').defaultNow(),
70
+ });
71
+ `;
72
+ await writeFile(
73
+ join(schemasDir, 'example.ts'),
74
+ exampleSchemaCode
75
+ );
76
+ emitLog('✅ Example schema created');
77
+
78
+ emitLog('Configuring Drizzle migrations...');
79
+ const drizzleConfigCode = `
80
+ import type { Config } from 'drizzle-kit';
81
+
82
+ export default {
83
+ schema: './src/db/schema/*',
84
+ out: './src/db/migrations',
85
+ driver: 'pg',
86
+ dbCredentials: {
87
+ connectionString: process.env.${config.env?.DATABASE_URL_ENV || 'DATABASE_URL'}!,
88
+ },
89
+ } satisfies Config;
90
+ `;
91
+ await writeFile(
92
+ join(backendDir, 'drizzle.config.ts'),
93
+ drizzleConfigCode
94
+ );
95
+ emitLog('✅ Drizzle configuration complete');
96
+
97
+ emitLog('✅ Drizzle ORM setup completed successfully!');
98
+ } catch (error) {
99
+ emitLog(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
100
+ throw error;
101
+ }
102
+ }
@@ -0,0 +1,68 @@
1
+ import { join } from 'node:path'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import 'dotenv/config'
4
+
5
+ export async function setupMongoose(config: any, projectDir: string,emitLog: (log: string) => void) {
6
+ const backendDir = join(projectDir, 'backend');
7
+ const modelsDir = join(backendDir, 'src', 'models');
8
+ await mkdir(modelsDir, { recursive: true });
9
+
10
+ emitLog('Generating environment configuration...');
11
+ const envContent = `
12
+ # MongoDB Configuration
13
+ ${config.env?.MONGODB_URI_ENV || 'MONGODB_URI'}=mongodb://localhost:27017/${config.databaseName || 'myapp'}
14
+
15
+ # Add other environment variables here
16
+ NODE_ENV=development
17
+ PORT=3000
18
+ `;
19
+
20
+ await writeFile(
21
+ join(backendDir, '.env'),
22
+ envContent.trim() + '\n'
23
+ );
24
+ emitLog('✅ Environment configuration created');
25
+
26
+ emitLog('Setting up database connection...');
27
+ const dbCode = `
28
+ import mongoose from 'mongoose';
29
+
30
+ const MONGODB_URI = process.env.${config.env?.MONGODB_URI_ENV || 'MONGODB_URI'} || 'mongodb://localhost:27017/${config.databaseName || 'myapp'}';
31
+
32
+ export async function connectDB() {
33
+ try {
34
+ await mongoose.connect(MONGODB_URI);
35
+ console.log('Connected to MongoDB');
36
+ } catch (error) {
37
+ console.error('MongoDB connection error:', error);
38
+ process.exit(1);
39
+ }
40
+ }
41
+
42
+ export async function disconnectDB() {
43
+ await mongoose.disconnect();
44
+ console.log('Disconnected from MongoDB');
45
+ }
46
+ `;
47
+ emitLog('✅ Database connection setup complete');
48
+ await writeFile(
49
+ join(backendDir, 'db.ts'),
50
+ dbCode
51
+ );
52
+
53
+ const exampleModelCode = `
54
+ import mongoose from 'mongoose';
55
+
56
+ const exampleSchema = new mongoose.Schema({
57
+ name: { type: String, required: true },
58
+ createdAt: { type: Date, default: Date.now },
59
+ });
60
+
61
+ export const Example = mongoose.model('Example', exampleSchema);
62
+ `;
63
+
64
+ await writeFile(
65
+ join(modelsDir, 'example.ts'),
66
+ exampleModelCode
67
+ );
68
+ }
@@ -0,0 +1,14 @@
1
+ import { join } from 'node:path'
2
+ import { execSync } from 'node:child_process'
3
+ import { writeFileSync } from 'node:fs';
4
+
5
+
6
+ export async function setupPrisma(config: any, projectDir: string,emitLog: (log: string) => void) {
7
+ emitLog('Setting up Prisma...');
8
+ const backendDir = join(projectDir, 'backend');
9
+ const envContent = `DATABASE_URL=${config.dbUrl}\n`;
10
+ writeFileSync(join(projectDir, 'backend', '.env'), envContent);
11
+ await execSync('npm install prisma', { cwd: backendDir });
12
+ await execSync('npx prisma init', { cwd: backendDir });
13
+ emitLog('✅ Prisma setup complete');
14
+ }
@@ -0,0 +1,228 @@
1
+ import { writeFile, mkdir } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { execSync } from 'child_process';
4
+ import { existsSync } from 'fs';
5
+
6
+ export async function setupShadcn(
7
+ config: any,
8
+ projectDir: string,
9
+ emitLog: (log: string) => void
10
+ ) {
11
+ try {
12
+ const frontendDir = join(projectDir, 'frontend');
13
+ emitLog('📦 Setting up shadcn/ui...');
14
+
15
+ // Make sure Tailwind is set up first
16
+ emitLog('Ensuring Tailwind CSS is set up...');
17
+
18
+ // Install shadcn/ui dependencies
19
+ emitLog('Installing shadcn/ui dependencies...');
20
+ execSync('npm install @shadcn/ui class-variance-authority clsx tailwind-merge lucide-react', {
21
+ cwd: frontendDir,
22
+ stdio: 'inherit'
23
+ });
24
+
25
+ // Create components.json configuration
26
+ const componentsConfig = {
27
+ $schema: "https://ui.shadcn.com/schema.json",
28
+ style: "default",
29
+ rsc: false,
30
+ tailwind: {
31
+ config: "tailwind.config.js",
32
+ css: "src/index.css",
33
+ baseColor: "slate",
34
+ cssVariables: true,
35
+ },
36
+ aliases: {
37
+ components: "@/components",
38
+ utils: "@/lib/utils"
39
+ }
40
+ };
41
+
42
+ await writeFile(
43
+ join(frontendDir, 'components.json'),
44
+ JSON.stringify(componentsConfig, null, 2)
45
+ );
46
+
47
+ // Create utils file
48
+ const utilsDir = join(frontendDir, 'src', 'lib');
49
+ if (!existsSync(utilsDir)) {
50
+ await mkdir(utilsDir, { recursive: true });
51
+ }
52
+
53
+ const utilsContent = `
54
+ import { type ClassValue, clsx } from "clsx"
55
+ import { twMerge } from "tailwind-merge"
56
+
57
+ export function cn(...inputs: ClassValue[]) {
58
+ return twMerge(clsx(inputs))
59
+ }
60
+ `;
61
+
62
+ await writeFile(
63
+ join(utilsDir, 'utils.ts'),
64
+ utilsContent.trim() + '\n'
65
+ );
66
+
67
+ emitLog('✅ shadcn/ui setup completed successfully!');
68
+ } catch (error) {
69
+ emitLog(`❌ Error setting up shadcn/ui: ${error instanceof Error ? error.message : 'Unknown error'}`);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ function generateShadcnTailwindConfig(frontend: string): string {
75
+ const baseConfig = {
76
+ darkMode: ["class"],
77
+ content: frontend === 'django'
78
+ ? ["./templates/**/*.html", "./static/**/*.{js,ts}"]
79
+ : ["./index.html", "./src/**/*.{js,ts,jsx,tsx,vue}"],
80
+ theme: {
81
+ container: {
82
+ center: true,
83
+ padding: "2rem",
84
+ screens: {
85
+ "2xl": "1400px",
86
+ },
87
+ },
88
+ extend: {
89
+ colors: {
90
+ border: "hsl(var(--border))",
91
+ input: "hsl(var(--input))",
92
+ ring: "hsl(var(--ring))",
93
+ background: "hsl(var(--background))",
94
+ foreground: "hsl(var(--foreground))",
95
+ primary: {
96
+ DEFAULT: "hsl(var(--primary))",
97
+ foreground: "hsl(var(--primary-foreground))",
98
+ },
99
+ secondary: {
100
+ DEFAULT: "hsl(var(--secondary))",
101
+ foreground: "hsl(var(--secondary-foreground))",
102
+ },
103
+ destructive: {
104
+ DEFAULT: "hsl(var(--destructive))",
105
+ foreground: "hsl(var(--destructive-foreground))",
106
+ },
107
+ muted: {
108
+ DEFAULT: "hsl(var(--muted))",
109
+ foreground: "hsl(var(--muted-foreground))",
110
+ },
111
+ accent: {
112
+ DEFAULT: "hsl(var(--accent))",
113
+ foreground: "hsl(var(--accent-foreground))",
114
+ },
115
+ popover: {
116
+ DEFAULT: "hsl(var(--popover))",
117
+ foreground: "hsl(var(--popover-foreground))",
118
+ },
119
+ card: {
120
+ DEFAULT: "hsl(var(--card))",
121
+ foreground: "hsl(var(--card-foreground))",
122
+ },
123
+ },
124
+ borderRadius: {
125
+ lg: "var(--radius)",
126
+ md: "calc(var(--radius) - 2px)",
127
+ sm: "calc(var(--radius) - 4px)",
128
+ },
129
+ keyframes: {
130
+ "accordion-down": {
131
+ from: { height: "0" },
132
+ to: { height: "var(--radix-accordion-content-height)" },
133
+ },
134
+ "accordion-up": {
135
+ from: { height: "var(--radix-accordion-content-height)" },
136
+ to: { height: "0" },
137
+ },
138
+ },
139
+ animation: {
140
+ "accordion-down": "accordion-down 0.2s ease-out",
141
+ "accordion-up": "accordion-up 0.2s ease-out",
142
+ },
143
+ },
144
+ },
145
+ plugins: ["require('tailwindcss-animate')"],
146
+ };
147
+
148
+ return `/** @type {import('tailwindcss').Config} */
149
+ export default ${JSON.stringify(baseConfig, null, 2)}`;
150
+ }
151
+
152
+ function generateShadcnStyles(frontend: string): string {
153
+ return `@tailwind base;
154
+ @tailwind components;
155
+ @tailwind utilities;
156
+ @layer base {
157
+ :root {
158
+ --background: 0 0% 100%;
159
+ --foreground: 222.2 84% 4.9%;
160
+
161
+ --card: 0 0% 100%;
162
+ --card-foreground: 222.2 84% 4.9%;
163
+
164
+ --popover: 0 0% 100%;
165
+ --popover-foreground: 222.2 84% 4.9%;
166
+
167
+ --primary: 222.2 47.4% 11.2%;
168
+ --primary-foreground: 210 40% 98%;
169
+
170
+ --secondary: 210 40% 96.1%;
171
+ --secondary-foreground: 222.2 47.4% 11.2%;
172
+
173
+ --muted: 210 40% 96.1%;
174
+ --muted-foreground: 215.4 16.3% 46.9%;
175
+
176
+ --accent: 210 40% 96.1%;
177
+ --accent-foreground: 222.2 47.4% 11.2%;
178
+
179
+ --destructive: 0 84.2% 60.2%;
180
+ --destructive-foreground: 210 40% 98%;
181
+
182
+ --border: 214.3 31.8% 91.4%;
183
+ --input: 214.3 31.8% 91.4%;
184
+ --ring: 222.2 84% 4.9%;
185
+
186
+ --radius: 0.5rem;
187
+ }
188
+
189
+ .dark {
190
+ --background: 222.2 84% 4.9%;
191
+ --foreground: 210 40% 98%;
192
+
193
+ --card: 222.2 84% 4.9%;
194
+ --card-foreground: 210 40% 98%;
195
+
196
+ --popover: 222.2 84% 4.9%;
197
+ --popover-foreground: 210 40% 98%;
198
+
199
+ --primary: 210 40% 98%;
200
+ --primary-foreground: 222.2 47.4% 11.2%;
201
+
202
+ --secondary: 217.2 32.6% 17.5%;
203
+ --secondary-foreground: 210 40% 98%;
204
+
205
+ --muted: 217.2 32.6% 17.5%;
206
+ --muted-foreground: 215 20.2% 65.1%;
207
+
208
+ --accent: 217.2 32.6% 17.5%;
209
+ --accent-foreground: 210 40% 98%;
210
+
211
+ --destructive: 0 62.8% 30.6%;
212
+ --destructive-foreground: 210 40% 98%;
213
+
214
+ --border: 217.2 32.6% 17.5%;
215
+ --input: 217.2 32.6% 17.5%;
216
+ --ring: 212.7 26.8% 83.9%;
217
+ }
218
+ }
219
+
220
+ @layer base {
221
+ * {
222
+ @apply border-border;
223
+ }
224
+ body {
225
+ @apply bg-background text-foreground;
226
+ }
227
+ }`;
228
+ }