@asynx/create-asynx-next-app 1.0.4 → 1.0.6
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/create-asynx-next-app-wrapper/index.js +3 -0
- package/create-asynx-next-app-wrapper/package.json +12 -0
- package/package.json +1 -1
- package/templates/advanced/.env.example +23 -0
- package/templates/advanced/README.md +148 -0
- package/templates/advanced/next.config.mjs +14 -0
- package/templates/advanced/package.json +1 -1
- package/templates/advanced/postcss.config.mjs +6 -0
- package/templates/advanced/src/app/app/billing/page.tsx +57 -0
- package/templates/advanced/src/app/app/layout.tsx +25 -0
- package/templates/advanced/src/app/app/page.tsx +36 -0
- package/templates/advanced/src/app/app/settings/page.tsx +50 -0
- package/templates/advanced/src/app/auth/login/page.tsx +41 -0
- package/templates/advanced/src/app/auth/signup/page.tsx +45 -0
- package/templates/advanced/src/app/globals.css +151 -8
- package/templates/advanced/src/app/layout.tsx +19 -18
- package/templates/advanced/src/app/page.tsx +25 -8
- package/templates/advanced/src/lib/api/client.ts +67 -0
- package/templates/advanced/src/lib/api/config/app.ts +19 -0
- package/templates/advanced/src/lib/api/config/constants.ts +38 -0
- package/templates/advanced/src/lib/api/features/analytics/lib/analytics-service.ts +26 -0
- package/templates/advanced/src/lib/api/features/app-shell/components/app-header.tsx +18 -0
- package/templates/advanced/src/lib/api/features/app-shell/components/app-sidebar.tsx +38 -0
- package/templates/advanced/src/lib/api/features/auth/lib/auth-service.ts +36 -0
- package/templates/advanced/src/lib/api/features/billing/lib/billing-service.ts +38 -0
- package/templates/advanced/src/types/index.ts +21 -0
- package/templates/advanced/tsconfig.json +14 -11
- package/templates/standard/README.md +53 -0
- package/templates/standard/package.json +1 -1
- package/templates/standard/postcss.config.mjs +6 -0
- package/templates/standard/src/app/(dashboard)/dashboard/page.tsx +45 -0
- package/templates/standard/src/app/(dashboard)/layout.tsx +30 -0
- package/templates/standard/src/app/(public)/layout.tsx +16 -0
- package/templates/standard/src/app/(public)/login/page.tsx +33 -0
- package/templates/standard/src/app/globals.css +151 -1
- package/templates/standard/src/app/layout.tsx +21 -1
- package/templates/standard/src/app/page.tsx +22 -3
- package/templates/standard/src/lib/api.ts +37 -0
- package/templates/standard/src/lib/constants.ts +14 -0
- package/templates/standard/tsconfig.json +12 -11
- package/templates/starter/package.json +1 -1
- package/templates/starter/src/app/globals.css +1 -0
- package/templates/advanced/next-env.d.ts +0 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-asynx-next-app",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Create Next.js apps using Asynx Devs templates",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-asynx-next-app": "index.js"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@asynx/create-asynx-next-app": "^0.1.0"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT"
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# App Configuration
|
|
2
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
3
|
+
NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_APP_URL/api
|
|
4
|
+
|
|
5
|
+
# Authentication
|
|
6
|
+
# Add your auth provider keys here
|
|
7
|
+
# AUTH_SECRET=
|
|
8
|
+
# NEXT_PUBLIC_AUTH_PROVIDER=
|
|
9
|
+
|
|
10
|
+
# Database
|
|
11
|
+
# DATABASE_URL=
|
|
12
|
+
|
|
13
|
+
# Payment Provider (Stripe example)
|
|
14
|
+
# STRIPE_SECRET_KEY=
|
|
15
|
+
# NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
|
16
|
+
# STRIPE_WEBHOOK_SECRET=
|
|
17
|
+
|
|
18
|
+
# Analytics
|
|
19
|
+
# NEXT_PUBLIC_ANALYTICS_ID=
|
|
20
|
+
|
|
21
|
+
# Email
|
|
22
|
+
# EMAIL_FROM=
|
|
23
|
+
# EMAIL_PROVIDER=
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Advanced Template (SaaS)
|
|
2
|
+
|
|
3
|
+
This template is designed for **real SaaS products, multi-feature applications, and long-term scalable codebases**.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
This template follows a **domain-driven, feature-based architecture** for maximum scalability.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
├── app/
|
|
12
|
+
│ ├── auth/ # Auth feature routes
|
|
13
|
+
│ │ ├── login/
|
|
14
|
+
│ │ └── signup/
|
|
15
|
+
│ ├── app/ # Main app shell (authenticated)
|
|
16
|
+
│ │ ├── billing/
|
|
17
|
+
│ │ ├── settings/
|
|
18
|
+
│ │ ├── layout.tsx # App shell layout
|
|
19
|
+
│ │ └── page.tsx # Dashboard
|
|
20
|
+
│ ├── layout.tsx # Root layout
|
|
21
|
+
│ ├── page.tsx # Landing page
|
|
22
|
+
│ └── globals.css
|
|
23
|
+
├── features/ # Feature modules (domains)
|
|
24
|
+
│ ├── app-shell/ # Core navigation & layout
|
|
25
|
+
│ │ └── components/
|
|
26
|
+
│ ├── auth/ # Authentication domain
|
|
27
|
+
│ │ └── lib/
|
|
28
|
+
│ ├── billing/ # Billing & subscriptions
|
|
29
|
+
│ │ └── lib/
|
|
30
|
+
│ └── analytics/ # Analytics tracking
|
|
31
|
+
│ └── lib/
|
|
32
|
+
├── lib/ # Shared infrastructure
|
|
33
|
+
│ ├── api/ # API client
|
|
34
|
+
│ │ └── client.ts
|
|
35
|
+
│ └── config/ # App configuration
|
|
36
|
+
│ ├── app.ts
|
|
37
|
+
│ └── constants.ts
|
|
38
|
+
├── types/ # Shared TypeScript types
|
|
39
|
+
│ └── index.ts
|
|
40
|
+
└── utils/ # Utility functions
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Key Principles
|
|
44
|
+
|
|
45
|
+
### 1. Feature-Based Organization
|
|
46
|
+
Each major feature/domain gets its own folder in \`features/\`:
|
|
47
|
+
- Contains all feature-specific logic, components, and services
|
|
48
|
+
- Self-contained and independently testable
|
|
49
|
+
- Easy to extract into microservices later
|
|
50
|
+
|
|
51
|
+
### 2. Server/Client Boundary
|
|
52
|
+
- Services in \`lib/\` folders handle business logic
|
|
53
|
+
- Components handle presentation
|
|
54
|
+
- Clear separation prevents vendor lock-in
|
|
55
|
+
|
|
56
|
+
### 3. Shared Infrastructure
|
|
57
|
+
The \`lib/\` folder contains code shared across features:
|
|
58
|
+
- API client
|
|
59
|
+
- Configuration
|
|
60
|
+
- Auth utilities
|
|
61
|
+
- Database helpers (when added)
|
|
62
|
+
|
|
63
|
+
### 4. Scalability Patterns
|
|
64
|
+
This structure supports:
|
|
65
|
+
- Multi-tenant architectures
|
|
66
|
+
- Role-based access control
|
|
67
|
+
- Feature flags
|
|
68
|
+
- Background jobs
|
|
69
|
+
- Webhooks and integrations
|
|
70
|
+
|
|
71
|
+
## Getting Started
|
|
72
|
+
|
|
73
|
+
### 1. Configure Your App
|
|
74
|
+
Edit \`lib/config/app.ts\` with your app details and environment variables.
|
|
75
|
+
|
|
76
|
+
### 2. Set Up Authentication
|
|
77
|
+
Implement real auth in \`features/auth/lib/auth-service.ts\`:
|
|
78
|
+
- Add your auth provider (Supabase, Clerk, Auth.js, etc.)
|
|
79
|
+
- Update login/signup logic
|
|
80
|
+
- Add middleware for route protection
|
|
81
|
+
|
|
82
|
+
### 3. Add Billing
|
|
83
|
+
Implement billing in \`features/billing/lib/billing-service.ts\`:
|
|
84
|
+
- Integrate Stripe, Paddle, or your payment provider
|
|
85
|
+
- Set up webhooks in \`app/api/webhooks/\`
|
|
86
|
+
- Configure subscription plans
|
|
87
|
+
|
|
88
|
+
### 4. Build Features
|
|
89
|
+
Create new feature modules in \`features/\`:
|
|
90
|
+
```
|
|
91
|
+
features/
|
|
92
|
+
your-feature/
|
|
93
|
+
components/
|
|
94
|
+
lib/
|
|
95
|
+
types/
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Best Practices
|
|
99
|
+
|
|
100
|
+
### Service Layer Pattern
|
|
101
|
+
Keep business logic in service files:
|
|
102
|
+
```typescript
|
|
103
|
+
// features/your-feature/lib/your-service.ts
|
|
104
|
+
export class YourService {
|
|
105
|
+
async doSomething() {
|
|
106
|
+
// Business logic here
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### API Routes
|
|
112
|
+
Create API routes in \`app/api/\`:
|
|
113
|
+
```typescript
|
|
114
|
+
// app/api/your-feature/route.ts
|
|
115
|
+
export async function POST(request: Request) {
|
|
116
|
+
// Handle request
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Type Safety
|
|
121
|
+
Define shared types in \`types/\`:
|
|
122
|
+
```typescript
|
|
123
|
+
// types/your-feature.ts
|
|
124
|
+
export type YourType = {
|
|
125
|
+
// ...
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Scaling Considerations
|
|
130
|
+
|
|
131
|
+
This template is ready for:
|
|
132
|
+
- **Multi-tenancy**: Add tenant ID to database queries
|
|
133
|
+
- **RBAC**: Extend User type with permissions
|
|
134
|
+
- **Feature flags**: Add feature detection to \`lib/config\`
|
|
135
|
+
- **Background jobs**: Add \`lib/jobs/\` folder
|
|
136
|
+
- **Webhooks**: Create \`app/api/webhooks/\` routes
|
|
137
|
+
- **Monitoring**: Integrate Sentry, LogRocket, etc. in \`lib/monitoring\`
|
|
138
|
+
|
|
139
|
+
## No Vendor Lock-In
|
|
140
|
+
|
|
141
|
+
This template provides **structure without coupling**:
|
|
142
|
+
- Auth service can use any provider
|
|
143
|
+
- Billing service works with any payment platform
|
|
144
|
+
- Analytics service integrates with any tool
|
|
145
|
+
- Database can be added without rewriting
|
|
146
|
+
|
|
147
|
+
Simply implement the service interfaces with your chosen providers.
|
|
148
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
reactStrictMode: true,
|
|
4
|
+
// Recommended for production SaaS apps
|
|
5
|
+
poweredByHeader: false,
|
|
6
|
+
typescript: {
|
|
7
|
+
ignoreBuildErrors: true,
|
|
8
|
+
},
|
|
9
|
+
images: {
|
|
10
|
+
unoptimized: true,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default nextConfig;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Billing feature page
|
|
2
|
+
|
|
3
|
+
export default function BillingPage() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto">
|
|
6
|
+
<h1 className="text-3xl font-bold mb-2">Billing & Subscription</h1>
|
|
7
|
+
<p className="text-muted-foreground mb-8">Manage your subscription and billing information</p>
|
|
8
|
+
|
|
9
|
+
<div className="space-y-6">
|
|
10
|
+
{/* Current Plan */}
|
|
11
|
+
<div className="border rounded-lg p-6">
|
|
12
|
+
<h2 className="text-xl font-semibold mb-4">Current Plan</h2>
|
|
13
|
+
<div className="flex items-center justify-between">
|
|
14
|
+
<div>
|
|
15
|
+
<p className="font-medium text-lg">Pro Plan</p>
|
|
16
|
+
<p className="text-sm text-muted-foreground">$49/month • Renews on Jan 1, 2024</p>
|
|
17
|
+
</div>
|
|
18
|
+
<button className="px-4 py-2 border rounded-md hover:bg-muted">Manage Plan</button>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
{/* Payment Method */}
|
|
23
|
+
<div className="border rounded-lg p-6">
|
|
24
|
+
<h2 className="text-xl font-semibold mb-4">Payment Method</h2>
|
|
25
|
+
<div className="flex items-center justify-between">
|
|
26
|
+
<div>
|
|
27
|
+
<p className="font-medium">•••• •••• •••• 4242</p>
|
|
28
|
+
<p className="text-sm text-muted-foreground">Expires 12/24</p>
|
|
29
|
+
</div>
|
|
30
|
+
<button className="px-4 py-2 border rounded-md hover:bg-muted">Update</button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
{/* Billing History */}
|
|
35
|
+
<div className="border rounded-lg p-6">
|
|
36
|
+
<h2 className="text-xl font-semibold mb-4">Billing History</h2>
|
|
37
|
+
<div className="space-y-3">
|
|
38
|
+
{[1, 2, 3].map((i) => (
|
|
39
|
+
<div key={i} className="flex items-center justify-between py-2">
|
|
40
|
+
<div>
|
|
41
|
+
<p className="font-medium">Pro Plan</p>
|
|
42
|
+
<p className="text-sm text-muted-foreground">Dec {i}, 2023</p>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="text-right">
|
|
45
|
+
<p className="font-medium">$49.00</p>
|
|
46
|
+
<a href="#" className="text-sm text-blue-600 hover:underline">
|
|
47
|
+
Download
|
|
48
|
+
</a>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type React from "react"
|
|
2
|
+
// App shell layout
|
|
3
|
+
// This wraps the entire authenticated application
|
|
4
|
+
|
|
5
|
+
import { AppSidebar } from "@/features/app-shell/components/app-sidebar"
|
|
6
|
+
import { AppHeader } from "@/features/app-shell/components/app-header"
|
|
7
|
+
|
|
8
|
+
export default function AppLayout({
|
|
9
|
+
children,
|
|
10
|
+
}: {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<div className="min-h-screen flex">
|
|
15
|
+
{/* Sidebar navigation */}
|
|
16
|
+
<AppSidebar />
|
|
17
|
+
|
|
18
|
+
{/* Main content area */}
|
|
19
|
+
<div className="flex-1 flex flex-col">
|
|
20
|
+
<AppHeader />
|
|
21
|
+
<main className="flex-1 p-6">{children}</main>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Main app dashboard
|
|
2
|
+
// Entry point after authentication
|
|
3
|
+
|
|
4
|
+
export default function AppDashboard() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="container mx-auto">
|
|
7
|
+
<h1 className="text-3xl font-bold mb-6">Dashboard</h1>
|
|
8
|
+
|
|
9
|
+
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
|
|
10
|
+
<div className="border rounded-lg p-6">
|
|
11
|
+
<h3 className="text-sm font-medium text-muted-foreground mb-2">Total Revenue</h3>
|
|
12
|
+
<p className="text-3xl font-bold">$45,231</p>
|
|
13
|
+
<p className="text-sm text-muted-foreground mt-2">+20.1% from last month</p>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div className="border rounded-lg p-6">
|
|
17
|
+
<h3 className="text-sm font-medium text-muted-foreground mb-2">Active Users</h3>
|
|
18
|
+
<p className="text-3xl font-bold">2,350</p>
|
|
19
|
+
<p className="text-sm text-muted-foreground mt-2">+180 from last month</p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div className="border rounded-lg p-6">
|
|
23
|
+
<h3 className="text-sm font-medium text-muted-foreground mb-2">Conversion Rate</h3>
|
|
24
|
+
<p className="text-3xl font-bold">3.2%</p>
|
|
25
|
+
<p className="text-sm text-muted-foreground mt-2">+0.3% from last month</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="border rounded-lg p-6">
|
|
29
|
+
<h3 className="text-sm font-medium text-muted-foreground mb-2">Churn Rate</h3>
|
|
30
|
+
<p className="text-3xl font-bold">0.8%</p>
|
|
31
|
+
<p className="text-sm text-muted-foreground mt-2">-0.2% from last month</p>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Settings page
|
|
2
|
+
|
|
3
|
+
export default function SettingsPage() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto">
|
|
6
|
+
<h1 className="text-3xl font-bold mb-8">Settings</h1>
|
|
7
|
+
|
|
8
|
+
<div className="grid gap-6">
|
|
9
|
+
{/* Profile Settings */}
|
|
10
|
+
<div className="border rounded-lg p-6">
|
|
11
|
+
<h2 className="text-xl font-semibold mb-4">Profile</h2>
|
|
12
|
+
<form className="space-y-4">
|
|
13
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
14
|
+
<div>
|
|
15
|
+
<label className="block text-sm font-medium mb-2">First Name</label>
|
|
16
|
+
<input type="text" className="w-full px-3 py-2 border rounded-md" placeholder="John" />
|
|
17
|
+
</div>
|
|
18
|
+
<div>
|
|
19
|
+
<label className="block text-sm font-medium mb-2">Last Name</label>
|
|
20
|
+
<input type="text" className="w-full px-3 py-2 border rounded-md" placeholder="Doe" />
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<label className="block text-sm font-medium mb-2">Email</label>
|
|
25
|
+
<input type="email" className="w-full px-3 py-2 border rounded-md" placeholder="john@example.com" />
|
|
26
|
+
</div>
|
|
27
|
+
<button type="submit" className="px-4 py-2 bg-foreground text-background rounded-md hover:opacity-90">
|
|
28
|
+
Save Changes
|
|
29
|
+
</button>
|
|
30
|
+
</form>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
{/* Security Settings */}
|
|
34
|
+
<div className="border rounded-lg p-6">
|
|
35
|
+
<h2 className="text-xl font-semibold mb-4">Security</h2>
|
|
36
|
+
<div className="space-y-4">
|
|
37
|
+
<div>
|
|
38
|
+
<label className="block text-sm font-medium mb-2">Change Password</label>
|
|
39
|
+
<button className="px-4 py-2 border rounded-md hover:bg-muted">Update Password</button>
|
|
40
|
+
</div>
|
|
41
|
+
<div>
|
|
42
|
+
<label className="block text-sm font-medium mb-2">Two-Factor Authentication</label>
|
|
43
|
+
<button className="px-4 py-2 border rounded-md hover:bg-muted">Enable 2FA</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Auth feature - login page
|
|
2
|
+
// Part of the auth domain
|
|
3
|
+
|
|
4
|
+
export default function LoginPage() {
|
|
5
|
+
return (
|
|
6
|
+
<main className="min-h-screen flex items-center justify-center p-6">
|
|
7
|
+
<div className="w-full max-w-md">
|
|
8
|
+
<h1 className="text-3xl font-bold mb-2 text-center">Sign In</h1>
|
|
9
|
+
<p className="text-muted-foreground text-center mb-8">Enter your credentials to access your account</p>
|
|
10
|
+
|
|
11
|
+
<div className="border rounded-lg p-8">
|
|
12
|
+
<form className="space-y-6">
|
|
13
|
+
<div>
|
|
14
|
+
<label className="block text-sm font-medium mb-2">Email Address</label>
|
|
15
|
+
<input type="email" className="w-full px-4 py-2 border rounded-md" placeholder="you@example.com" />
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<label className="block text-sm font-medium mb-2">Password</label>
|
|
20
|
+
<input type="password" className="w-full px-4 py-2 border rounded-md" placeholder="••••••••" />
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<button
|
|
24
|
+
type="submit"
|
|
25
|
+
className="w-full bg-foreground text-background py-3 rounded-md hover:opacity-90 font-medium"
|
|
26
|
+
>
|
|
27
|
+
Sign In
|
|
28
|
+
</button>
|
|
29
|
+
</form>
|
|
30
|
+
|
|
31
|
+
<p className="text-center text-sm text-muted-foreground mt-6">
|
|
32
|
+
Don't have an account?{" "}
|
|
33
|
+
<a href="/auth/signup" className="underline">
|
|
34
|
+
Sign up
|
|
35
|
+
</a>
|
|
36
|
+
</p>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</main>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Auth feature - signup page
|
|
2
|
+
|
|
3
|
+
export default function SignupPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main className="min-h-screen flex items-center justify-center p-6">
|
|
6
|
+
<div className="w-full max-w-md">
|
|
7
|
+
<h1 className="text-3xl font-bold mb-2 text-center">Create Account</h1>
|
|
8
|
+
<p className="text-muted-foreground text-center mb-8">Get started with your free account</p>
|
|
9
|
+
|
|
10
|
+
<div className="border rounded-lg p-8">
|
|
11
|
+
<form className="space-y-6">
|
|
12
|
+
<div>
|
|
13
|
+
<label className="block text-sm font-medium mb-2">Full Name</label>
|
|
14
|
+
<input type="text" className="w-full px-4 py-2 border rounded-md" placeholder="John Doe" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div>
|
|
18
|
+
<label className="block text-sm font-medium mb-2">Email Address</label>
|
|
19
|
+
<input type="email" className="w-full px-4 py-2 border rounded-md" placeholder="you@example.com" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div>
|
|
23
|
+
<label className="block text-sm font-medium mb-2">Password</label>
|
|
24
|
+
<input type="password" className="w-full px-4 py-2 border rounded-md" placeholder="••••••••" />
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<button
|
|
28
|
+
type="submit"
|
|
29
|
+
className="w-full bg-foreground text-background py-3 rounded-md hover:opacity-90 font-medium"
|
|
30
|
+
>
|
|
31
|
+
Create Account
|
|
32
|
+
</button>
|
|
33
|
+
</form>
|
|
34
|
+
|
|
35
|
+
<p className="text-center text-sm text-muted-foreground mt-6">
|
|
36
|
+
Already have an account?{" "}
|
|
37
|
+
<a href="/auth/login" className="underline">
|
|
38
|
+
Sign in
|
|
39
|
+
</a>
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</main>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -1,8 +1,151 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
@custom-variant dark (&:is(.dark *));
|
|
5
|
+
|
|
6
|
+
:root {
|
|
7
|
+
--background: 0 0% 100%;
|
|
8
|
+
--foreground: 0 0% 3.9%;
|
|
9
|
+
--card: oklch(1 0 0);
|
|
10
|
+
--card-foreground: oklch(0.145 0 0);
|
|
11
|
+
--popover: oklch(1 0 0);
|
|
12
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
13
|
+
--primary: 221.2 83.2% 53.3%;
|
|
14
|
+
--primary-foreground: 0 0% 100%;
|
|
15
|
+
--secondary: oklch(0.97 0 0);
|
|
16
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
17
|
+
--muted: 0 0% 96.1%;
|
|
18
|
+
--muted-foreground: 0 0% 45.1%;
|
|
19
|
+
--accent: oklch(0.97 0 0);
|
|
20
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
21
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
22
|
+
--destructive-foreground: oklch(0.577 0.245 27.325);
|
|
23
|
+
--border: 0 0% 89.8%;
|
|
24
|
+
--input: oklch(0.922 0 0);
|
|
25
|
+
--ring: oklch(0.708 0 0);
|
|
26
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
27
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
28
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
29
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
30
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
31
|
+
--radius: 0.5rem;
|
|
32
|
+
--sidebar: oklch(0.985 0 0);
|
|
33
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
34
|
+
--sidebar-primary: oklch(0.205 0 0);
|
|
35
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
36
|
+
--sidebar-accent: oklch(0.97 0 0);
|
|
37
|
+
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
38
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
39
|
+
--sidebar-ring: oklch(0.708 0 0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.dark {
|
|
43
|
+
--background: 0 0% 3.9%;
|
|
44
|
+
--foreground: 0 0% 98%;
|
|
45
|
+
--card: oklch(0.145 0 0);
|
|
46
|
+
--card-foreground: oklch(0.985 0 0);
|
|
47
|
+
--popover: oklch(0.145 0 0);
|
|
48
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
49
|
+
--primary: 217.2 91.2% 59.8%;
|
|
50
|
+
--primary-foreground: 0 0% 100%;
|
|
51
|
+
--secondary: oklch(0.269 0 0);
|
|
52
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
53
|
+
--muted: 0 0% 14.9%;
|
|
54
|
+
--muted-foreground: 0 0% 63.9%;
|
|
55
|
+
--accent: oklch(0.269 0 0);
|
|
56
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
57
|
+
--destructive: oklch(0.396 0.141 25.723);
|
|
58
|
+
--destructive-foreground: oklch(0.637 0.237 25.331);
|
|
59
|
+
--border: 0 0% 14.9%;
|
|
60
|
+
--input: oklch(0.269 0 0);
|
|
61
|
+
--ring: oklch(0.439 0 0);
|
|
62
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
63
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
64
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
65
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
66
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
67
|
+
--sidebar: oklch(0.205 0 0);
|
|
68
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
69
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
70
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
71
|
+
--sidebar-accent: oklch(0.269 0 0);
|
|
72
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
73
|
+
--sidebar-border: oklch(0.269 0 0);
|
|
74
|
+
--sidebar-ring: oklch(0.439 0 0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@theme inline {
|
|
78
|
+
/* optional: --font-sans, --font-serif, --font-mono if they are applied in the layout.tsx */
|
|
79
|
+
--color-background: var(--background);
|
|
80
|
+
--color-foreground: var(--foreground);
|
|
81
|
+
--color-card: var(--card);
|
|
82
|
+
--color-card-foreground: var(--card-foreground);
|
|
83
|
+
--color-popover: var(--popover);
|
|
84
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
85
|
+
--color-primary: var(--primary);
|
|
86
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
87
|
+
--color-secondary: var(--secondary);
|
|
88
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
89
|
+
--color-muted: var(--muted);
|
|
90
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
91
|
+
--color-accent: var(--accent);
|
|
92
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
93
|
+
--color-destructive: var(--destructive);
|
|
94
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
95
|
+
--color-border: var(--border);
|
|
96
|
+
--color-input: var(--input);
|
|
97
|
+
--color-ring: var(--ring);
|
|
98
|
+
--color-chart-1: var(--chart-1);
|
|
99
|
+
--color-chart-2: var(--chart-2);
|
|
100
|
+
--color-chart-3: var(--chart-3);
|
|
101
|
+
--color-chart-4: var(--chart-4);
|
|
102
|
+
--color-chart-5: var(--chart-5);
|
|
103
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
104
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
105
|
+
--radius-lg: var(--radius);
|
|
106
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
107
|
+
--color-sidebar: var(--sidebar);
|
|
108
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
109
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
110
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
111
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
112
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
113
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
114
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@layer base {
|
|
118
|
+
* {
|
|
119
|
+
@apply border-border outline-ring/50;
|
|
120
|
+
}
|
|
121
|
+
body {
|
|
122
|
+
@apply bg-background text-foreground;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
* {
|
|
127
|
+
box-sizing: border-box;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
body {
|
|
131
|
+
margin: 0;
|
|
132
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
133
|
+
-webkit-font-smoothing: antialiased;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.container {
|
|
137
|
+
width: 100%;
|
|
138
|
+
max-width: 1280px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.text-muted-foreground {
|
|
142
|
+
color: hsl(var(--muted-foreground));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.border {
|
|
146
|
+
border: 1px solid hsl(var(--border));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.bg-muted {
|
|
150
|
+
background: hsl(var(--muted));
|
|
151
|
+
}
|