create-solostack 1.1.0 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-solostack",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "The complete SaaS boilerplate for indie hackers - Next.js 15 with auth, payments, database, and email",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,59 +1,50 @@
1
1
  import path from 'path';
2
- import { writeFile, renderTemplateToFile, getTemplatePath, ensureDir } from '../utils/files.js';
2
+ import { writeFile, ensureDir } from '../utils/files.js';
3
3
  import { PACKAGE_VERSIONS } from '../constants.js';
4
4
 
5
- /**
6
- * Generates the base Next.js 15 project structure
7
- * @param {string} projectPath - Path where the project should be generated
8
- * @param {string} projectName - Name of the project
9
- * @param {object} config - Project configuration
10
- */
11
- export async function generateBase(projectPath, projectName, config) {
12
- // Create directory structure
5
+ export async function generateBase(projectPath, projectName) {
6
+ // Create project directory
7
+ await ensureDir(projectPath);
8
+
9
+ // Create src/app directory
13
10
  await ensureDir(path.join(projectPath, 'src/app'));
14
- await ensureDir(path.join(projectPath, 'src/components'));
15
- await ensureDir(path.join(projectPath, 'src/lib'));
11
+
12
+ // Create public directory
16
13
  await ensureDir(path.join(projectPath, 'public'));
17
14
 
18
- //Generate package.json
15
+ // Generate package.json
19
16
  const packageJson = {
20
17
  name: projectName,
21
18
  version: '0.1.0',
22
19
  private: true,
23
- type: 'module',
20
+ type: "module",
24
21
  scripts: {
25
22
  dev: 'next dev',
26
23
  build: 'next build',
27
24
  start: 'next start',
28
25
  lint: 'next lint',
29
- 'db:push': 'prisma db push',
30
- 'db:seed': 'tsx prisma/seed.ts',
31
- 'db:studio': 'prisma studio',
26
+ "db:push": "prisma db push",
27
+ "db:seed": "tsx prisma/seed.ts",
28
+ "db:studio": "prisma studio",
29
+ postinstall: "prisma generate"
32
30
  },
33
31
  dependencies: {
34
32
  next: PACKAGE_VERSIONS.next,
35
33
  react: PACKAGE_VERSIONS.react,
36
- 'react-dom': PACKAGE_VERSIONS.reactDom,
37
- '@prisma/client': PACKAGE_VERSIONS['@prisma/client'],
34
+ 'react-dom': PACKAGE_VERSIONS['react-dom'],
38
35
  'next-auth': PACKAGE_VERSIONS['next-auth'],
39
- bcryptjs: PACKAGE_VERSIONS.bcryptjs,
36
+ '@prisma/client': PACKAGE_VERSIONS['@prisma/client'],
40
37
  stripe: PACKAGE_VERSIONS.stripe,
41
38
  resend: PACKAGE_VERSIONS.resend,
42
- '@react-email/components': PACKAGE_VERSIONS['@react-email/components'],
43
39
  zod: PACKAGE_VERSIONS.zod,
44
- 'react-hook-form': PACKAGE_VERSIONS['react-hook-form'],
45
- '@hookform/resolvers': PACKAGE_VERSIONS['@hookform/resolvers'],
46
- 'class-variance-authority': PACKAGE_VERSIONS['class-variance-authority'],
47
- clsx: PACKAGE_VERSIONS.clsx,
48
- 'tailwind-merge': PACKAGE_VERSIONS['tailwind-merge'],
49
- 'tailwindcss-animate': PACKAGE_VERSIONS['tailwindcss-animate'],
50
40
  'lucide-react': PACKAGE_VERSIONS['lucide-react'],
51
- '@radix-ui/react-dropdown-menu': PACKAGE_VERSIONS['@radix-ui/react-dropdown-menu'],
41
+ 'date-fns': PACKAGE_VERSIONS['date-fns'],
42
+ 'clsx': PACKAGE_VERSIONS.clsx,
43
+ 'tailwind-merge': PACKAGE_VERSIONS['tailwind-merge'],
52
44
  '@radix-ui/react-slot': PACKAGE_VERSIONS['@radix-ui/react-slot'],
53
- '@radix-ui/react-toast': PACKAGE_VERSIONS['@radix-ui/react-toast'],
54
- '@radix-ui/react-dialog': PACKAGE_VERSIONS['@radix-ui/react-dialog'],
55
- '@radix-ui/react-label': PACKAGE_VERSIONS['@radix-ui/react-label'],
56
- '@auth/prisma-adapter': PACKAGE_VERSIONS['@auth/prisma-adapter'],
45
+ '@radix-ui/react-label': '^2.0.2',
46
+ 'class-variance-authority': '^0.7.0',
47
+ 'tailwindcss-animate': '^1.0.7',
57
48
  },
58
49
  devDependencies: {
59
50
  typescript: PACKAGE_VERSIONS.typescript,
@@ -112,7 +103,14 @@ export async function generateBase(projectPath, projectName, config) {
112
103
 
113
104
  // Generate next.config.js
114
105
  const nextConfig = `/** @type {import('next').NextConfig} */
106
+ import path from 'path';
107
+ import { fileURLToPath } from 'url';
108
+
109
+ const __filename = fileURLToPath(import.meta.url);
110
+ const __dirname = path.dirname(__filename);
111
+
115
112
  const nextConfig = {
113
+ outputFileTracingRoot: __dirname,
116
114
  experimental: {
117
115
  serverActions: {
118
116
  bodySizeLimit: '2mb',
@@ -310,46 +308,171 @@ export default function RootLayout({
310
308
  await writeFile(path.join(projectPath, 'src/app/layout.tsx'), layoutTsx);
311
309
 
312
310
  // Generate app/page.tsx
313
- const pageTsx = `export default function Home() {
311
+ const pageTsx = `'use client';
312
+
313
+ import { useState, useEffect } from 'react';
314
+ import Link from 'next/link';
315
+ import { Rocket, Users, DollarSign, Code, Database, CreditCard, Mail, Lock, CheckCircle2, Trophy } from 'lucide-react';
316
+
317
+ export default function Home() {
318
+ const [mounted, setMounted] = useState(false);
319
+ const [mrr, setMrr] = useState(0);
320
+ const [users, setUsers] = useState(0);
321
+ const [clicks, setClicks] = useState(0);
322
+ const [shipped, setShipped] = useState(0);
323
+
324
+ useEffect(() => {
325
+ setMounted(true);
326
+ }, []);
327
+
328
+ const ship = () => {
329
+ setClicks(prev => prev + 1);
330
+ setShipped(prev => prev + 1);
331
+ setUsers(prev => prev + Math.floor(Math.random() * 3) + 1);
332
+
333
+ // Revenue logic
334
+ if (Math.random() > 0.7) {
335
+ setMrr(prev => prev + Math.floor(Math.random() * 20) + 10);
336
+ }
337
+ };
338
+
339
+ if (!mounted) return (
340
+ <div className="min-h-screen bg-black text-white flex items-center justify-center">
341
+ <div className="animate-pulse">Loading SaaS...</div>
342
+ </div>
343
+ );
344
+
314
345
  return (
315
- <main className="flex min-h-screen flex-col items-center justify-center p-24">
316
- <div className="z-10 max-w-5xl w-full items-center justify-center font-mono text-sm">
317
- <h1 className="text-4xl font-bold text-center mb-4">
318
- Welcome to ${projectName}
319
- </h1>
320
- <p className="text-center text-muted-foreground">
321
- Built with SoloStack - Your Next.js SaaS boilerplate
322
- </p>
323
- <div className="mt-8 grid grid-cols-1 md:grid-cols-2 gap-4">
324
- <div className="p-6 border rounded-lg">
325
- <h2 className="text-xl font-semibold mb-2">✅ Authentication</h2>
326
- <p className="text-sm text-muted-foreground">
327
- NextAuth.js configured with email and OAuth providers
328
- </p>
346
+ <main className="min-h-screen bg-black text-white font-sans selection:bg-indigo-500/30 overflow-hidden">
347
+ {/* Background Gradient */}
348
+ <div className="fixed inset-0 z-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-indigo-900/20 via-black to-black pointer-events-none" />
349
+
350
+ <div className="relative z-10 max-w-6xl mx-auto px-4 py-12">
351
+ {/* Header */}
352
+ <header className="flex items-center justify-between mb-16">
353
+ <div className="flex items-center gap-2">
354
+ <div className="h-8 w-8 bg-indigo-600 rounded-lg flex items-center justify-center">
355
+ <Code className="h-5 w-5 text-white" />
356
+ </div>
357
+ <span className="font-bold text-xl tracking-tight">${projectName}</span>
329
358
  </div>
330
- <div className="p-6 border rounded-lg">
331
- <h2 className="text-xl font-semibold mb-2">✅ Database</h2>
332
- <p className="text-sm text-muted-foreground">
333
- Prisma + PostgreSQL ready to use
334
- </p>
335
- </div>
336
- <div className="p-6 border rounded-lg">
337
- <h2 className="text-xl font-semibold mb-2">✅ Payments</h2>
338
- <p className="text-sm text-muted-foreground">
339
- Stripe integration for subscriptions
359
+
360
+ {process.env.NODE_ENV === 'development' && (
361
+ <Link
362
+ href="/setup"
363
+ className="text-sm text-zinc-400 hover:text-white transition-colors flex items-center gap-2 border border-zinc-800 rounded-full px-4 py-1.5 hover:border-zinc-600"
364
+ >
365
+ <CheckCircle2 className="h-4 w-4" />
366
+ Check Diagnostics
367
+ </Link>
368
+ )}
369
+ </header>
370
+
371
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center mb-24">
372
+ {/* Game Section */}
373
+ <div className="space-y-8">
374
+ <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-500/10 text-indigo-400 text-sm border border-indigo-500/20">
375
+ <Rocket className="h-4 w-4" />
376
+ <span>Interactive SaaS Simulator</span>
377
+ </div>
378
+
379
+ <h1 className="text-5xl md:text-6xl font-bold tracking-tight leading-none bg-clip-text text-transparent bg-gradient-to-r from-white to-zinc-500">
380
+ Build your SaaS <br />
381
+ <span className="text-indigo-500">in minutes.</span>
382
+ </h1>
383
+
384
+ <p className="text-xl text-zinc-400 max-w-lg leading-relaxed">
385
+ The ultimate Next.js 15 boilerplate for indie hackers. Authentication, Database, Payments, and Email - pre-configured and ready to ship.
340
386
  </p>
387
+
388
+ {/* Game UI */}
389
+ <div className="bg-zinc-900/50 backdrop-blur-sm border border-zinc-800 rounded-2xl p-6 shadow-2xl relative overflow-hidden group/game">
390
+ <div className="absolute inset-0 bg-indigo-500/5 group-hover/game:bg-indigo-500/10 transition-colors pointer-events-none" />
391
+
392
+ <div className="grid grid-cols-3 gap-4 mb-6 relative z-10">
393
+ <div className="bg-black/50 p-4 rounded-xl border border-zinc-800">
394
+ <div className="text-zinc-500 text-xs uppercase font-semibold mb-1">MRR</div>
395
+ <div className="text-2xl font-mono text-green-400 flex items-center">
396
+ <DollarSign className="h-5 w-5 mr-1" />
397
+ {mrr}
398
+ </div>
399
+ </div>
400
+ <div className="bg-black/50 p-4 rounded-xl border border-zinc-800">
401
+ <div className="text-zinc-500 text-xs uppercase font-semibold mb-1">Users</div>
402
+ <div className="text-2xl font-mono text-blue-400 flex items-center">
403
+ <Users className="h-5 w-5 mr-1" />
404
+ {users}
405
+ </div>
406
+ </div>
407
+ <div className="bg-black/50 p-4 rounded-xl border border-zinc-800">
408
+ <div className="text-zinc-500 text-xs uppercase font-semibold mb-1">Shipped</div>
409
+ <div className="text-2xl font-mono text-purple-400 flex items-center">
410
+ <Trophy className="h-5 w-5 mr-1" />
411
+ {shipped}
412
+ </div>
413
+ </div>
414
+ </div>
415
+
416
+ <button
417
+ onClick={ship}
418
+ className="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-4 rounded-xl transition-all active:scale-95 shadow-[0_0_20px_rgba(79,70,229,0.3)] hover:shadow-[0_0_30px_rgba(79,70,229,0.5)] flex items-center justify-center gap-3 group relative z-10"
419
+ >
420
+ <Rocket className="h-6 w-6 group-hover:rotate-12 transition-transform" />
421
+ SHIP FEATURE
422
+ </button>
423
+
424
+ <p className="text-center text-zinc-500 text-xs mt-4 relative z-10">
425
+ Click to simulate your indie hacker journey! 🚀
426
+ </p>
427
+ </div>
341
428
  </div>
342
- <div className="p-6 border rounded-lg">
343
- <h2 className="text-xl font-semibold mb-2">✅ Emails</h2>
344
- <p className="text-sm text-muted-foreground">
345
- Resend configured for transactional emails
346
- </p>
429
+
430
+ {/* Cards Section */}
431
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
432
+ <div className="p-6 rounded-2xl bg-zinc-900/30 border border-zinc-800 hover:border-zinc-600 transition-colors group">
433
+ <div className="h-10 w-10 bg-zinc-800 rounded-lg flex items-center justify-center mb-4 group-hover:bg-zinc-700 transition-colors">
434
+ <Lock className="h-5 w-5 text-indigo-400" />
435
+ </div>
436
+ <h3 className="text-lg font-semibold mb-2 text-white">Authentication</h3>
437
+ <p className="text-zinc-400 text-sm">
438
+ NextAuth.js v5 pre-configured with Google & GitHub OAuth.
439
+ </p>
440
+ </div>
441
+
442
+ <div className="p-6 rounded-2xl bg-zinc-900/30 border border-zinc-800 hover:border-zinc-600 transition-colors group">
443
+ <div className="h-10 w-10 bg-zinc-800 rounded-lg flex items-center justify-center mb-4 group-hover:bg-zinc-700 transition-colors">
444
+ <Database className="h-5 w-5 text-emerald-400" />
445
+ </div>
446
+ <h3 className="text-lg font-semibold mb-2 text-white">Database</h3>
447
+ <p className="text-zinc-400 text-sm">
448
+ Prisma ORM with PostgreSQL. Complete schema for Users and Subs.
449
+ </p>
450
+ </div>
451
+
452
+ <div className="p-6 rounded-2xl bg-zinc-900/30 border border-zinc-800 hover:border-zinc-600 transition-colors group">
453
+ <div className="h-10 w-10 bg-zinc-800 rounded-lg flex items-center justify-center mb-4 group-hover:bg-zinc-700 transition-colors">
454
+ <CreditCard className="h-5 w-5 text-pink-400" />
455
+ </div>
456
+ <h3 className="text-lg font-semibold mb-2 text-white">Payments</h3>
457
+ <p className="text-zinc-400 text-sm">
458
+ Stripe integration with Webhook idempotency and Customer Portal.
459
+ </p>
460
+ </div>
461
+
462
+ <div className="p-6 rounded-2xl bg-zinc-900/30 border border-zinc-800 hover:border-zinc-600 transition-colors group">
463
+ <div className="h-10 w-10 bg-zinc-800 rounded-lg flex items-center justify-center mb-4 group-hover:bg-zinc-700 transition-colors">
464
+ <Mail className="h-5 w-5 text-blue-400" />
465
+ </div>
466
+ <h3 className="text-lg font-semibold mb-2 text-white">Emails</h3>
467
+ <p className="text-zinc-400 text-sm">
468
+ Resend + React Email based transactional emails.
469
+ </p>
470
+ </div>
347
471
  </div>
348
472
  </div>
349
- <div className="mt-8 text-center">
350
- <p className="text-sm text-muted-foreground">
351
- Get started by editing <code className="font-mono bg-muted px-2 py-1 rounded">src/app/page.tsx</code>
352
- </p>
473
+
474
+ <div className="text-center text-zinc-500 text-sm">
475
+ Get started by editing <code className="bg-zinc-900 border border-zinc-700 px-2 py-1 rounded text-zinc-300 font-mono">src/app/page.tsx</code>
353
476
  </div>
354
477
  </div>
355
478
  </main>