Add full application structure with auth, dashboard, and Docker

- Add Dockerfile for production deployment
- Add authentication pages (login, signup)
- Add dashboard layout and navigation
- Add project pages with chat component
- Add shadcn/ui components
- Add Supabase client configuration
- Add middleware for auth protection
- Update next.config.ts for standalone output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-12 13:41:59 +01:00
parent a0ce63c2c0
commit 065f8029be
35 changed files with 4377 additions and 83 deletions

View File

@@ -0,0 +1,135 @@
'use client'
import { useState } from 'react'
import Link from 'next/link'
import { createClient } from '@/lib/supabase/client'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Bot, Loader2, Mail } from 'lucide-react'
export default function SignupPage() {
const [email, setEmail] = useState('')
const [fullName, setFullName] = useState('')
const [isLoading, setIsLoading] = useState(false)
const [isSent, setIsSent] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleSignup = async (e: React.FormEvent) => {
e.preventDefault()
setIsLoading(true)
setError(null)
const supabase = createClient()
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
emailRedirectTo: `${window.location.origin}/auth/callback`,
data: {
full_name: fullName,
},
},
})
if (error) {
setError(error.message)
setIsLoading(false)
return
}
setIsSent(true)
setIsLoading(false)
}
if (isSent) {
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-zinc-950 px-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<div className="mx-auto w-12 h-12 rounded-full bg-primary/10 flex items-center justify-center mb-4">
<Mail className="h-6 w-6 text-primary" />
</div>
<CardTitle>Check your email</CardTitle>
<CardDescription>
We sent a magic link to <strong>{email}</strong>
</CardDescription>
</CardHeader>
<CardContent className="text-center text-sm text-zinc-500">
Click the link in your email to complete your signup. If you don&apos;t see it, check your spam folder.
</CardContent>
<CardFooter className="flex justify-center">
<Button variant="ghost" onClick={() => setIsSent(false)}>
Try a different email
</Button>
</CardFooter>
</Card>
</div>
)
}
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-zinc-950 px-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<Link href="/" className="inline-flex items-center justify-center gap-2 mb-4">
<Bot className="h-8 w-8 text-primary" />
<span className="text-xl font-bold">Mylder</span>
</Link>
<CardTitle>Create your account</CardTitle>
<CardDescription>Start building with AI in minutes</CardDescription>
</CardHeader>
<form onSubmit={handleSignup}>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="name">Full Name</Label>
<Input
id="name"
type="text"
placeholder="John Doe"
value={fullName}
onChange={(e) => setFullName(e.target.value)}
required
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isLoading}
/>
</div>
{error && (
<p className="text-sm text-red-500">{error}</p>
)}
</CardContent>
<CardFooter className="flex flex-col gap-4">
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Creating account...
</>
) : (
'Get Started Free'
)}
</Button>
<p className="text-sm text-center text-zinc-500">
Already have an account?{' '}
<Link href="/login" className="text-primary hover:underline">
Log in
</Link>
</p>
</CardFooter>
</form>
</Card>
</div>
)
}