diff --git a/apps/web/app/(auth)/signin/page.tsx b/apps/web/app/(auth)/signin/page.tsx index 049865c..2435564 100644 --- a/apps/web/app/(auth)/signin/page.tsx +++ b/apps/web/app/(auth)/signin/page.tsx @@ -5,7 +5,13 @@ import { signIn } from "next-auth/react"; import { useRouter } from "next/navigation"; import Link from "next/link"; -export default function SignIn() { +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Code, ArrowLeft } from "lucide-react"; + +export default function SignInPage() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [isLoading, setIsLoading] = useState(false); @@ -25,14 +31,14 @@ export default function SignIn() { }); if (result?.error) { - setError("Invalid credentials"); + setError("Invalid email or password. Please try again."); } else { - router.push("/"); + router.push("/dashboard"); // Redirect to dashboard on success router.refresh(); } } catch (error: unknown) { console.error("Sign in error:", error); - setError("An error occurred. Please try again."); + setError("An unexpected error occurred. Please try again."); } finally { setIsLoading(false); } @@ -40,144 +46,138 @@ export default function SignIn() { const handleOAuthSignIn = async (provider: string) => { setIsLoading(true); - await signIn(provider, { callbackUrl: "/" }); + await signIn(provider, { callbackUrl: "/dashboard" }); + // No need to setIsLoading(false) here, as the page will redirect }; return ( -
-
-
-

- Sign in to your account -

-

- Or{" "} - - create a new account - -

-
-
- {error && ( -
-
-
-

{error}

-
+
+ {/* Header */} +
+
+
+ +
+
-
- )} -
-
- - setEmail(e.target.value)} - /> -
-
- - setPassword(e.target.value)} - /> -
+ Dev8.dev + +
+
+
-
- + {/* Sign In Form */} +
+
+
+

Welcome back

+

Sign in to access your Dev8.dev workspace

-
-
-
-
-
-
- - Or continue with - -
-
- -
- +
+ + - -
-
- +
+
+ +
+
+ Or continue with +
+
+ +
+ + +
+ +
+

+ Don't have an account?{" "} + + Sign up + +

+
+ + +
); -} +} \ No newline at end of file diff --git a/apps/web/app/(auth)/signup/page.tsx b/apps/web/app/(auth)/signup/page.tsx index 457015d..178ebf0 100644 --- a/apps/web/app/(auth)/signup/page.tsx +++ b/apps/web/app/(auth)/signup/page.tsx @@ -5,7 +5,13 @@ import { signIn } from "next-auth/react"; import { useRouter } from "next/navigation"; import Link from "next/link"; -export default function SignUp() { +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Code, ArrowLeft } from "lucide-react"; + +export default function SignUpPage() { const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); @@ -44,19 +50,18 @@ export default function SignUp() { const data = await response.json(); if (!response.ok) { - setError(data.error || "An error occurred"); + setError(data.error || "An error occurred during registration."); return; } - setSuccess("Account created successfully! You can now sign in."); + setSuccess("Account created successfully! Redirecting to sign in..."); - // Optionally auto-sign in the user setTimeout(() => { router.push("/signin"); }, 2000); } catch (error: unknown) { console.error("Sign up error:", error); - setError("An error occurred. Please try again."); + setError("An unexpected error occurred. Please try again."); } finally { setIsLoading(false); } @@ -64,187 +69,171 @@ export default function SignUp() { const handleOAuthSignIn = async (provider: string) => { setIsLoading(true); - await signIn(provider, { callbackUrl: "/" }); + await signIn(provider, { callbackUrl: "/dashboard" }); }; return ( -
-
-
-

- Create your account -

-

- Or{" "} - - sign in to your existing account - -

-
-
- {error && ( -
-
-
-

{error}

-
+
+ {/* Header */} +
+
+
+ +
+
-
- )} - {success && ( -
-
-
-

- {success} -

-
-
-
- )} -
-
- - setName(e.target.value)} - /> -
-
- - setEmail(e.target.value)} - /> -
-
- - setPassword(e.target.value)} - /> -
-
- - setConfirmPassword(e.target.value)} - /> -
+ Dev8.dev + +
+
+
-
- + {/* Sign Up Form */} +
+
+
+

Create your account

+

Start coding in the cloud in seconds

-
-
-
-
-
-
- - Or continue with - -
-
- -
- - - -
-
- +
+ + + + +
+
+ +
+
+ Or continue with +
+
+ +
+ + +
+ +
+

+ Already have an account?{" "} + + Sign in + +

+
+ + +
); -} +} \ No newline at end of file diff --git a/apps/web/app/components/theme-provider.tsx b/apps/web/app/components/theme-provider.tsx new file mode 100644 index 0000000..55c2f6e --- /dev/null +++ b/apps/web/app/components/theme-provider.tsx @@ -0,0 +1,11 @@ +'use client' + +import * as React from 'react' +import { + ThemeProvider as NextThemesProvider, + type ThemeProviderProps, +} from 'next-themes' + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children} +} diff --git a/apps/web/app/components/ui/accordion.tsx b/apps/web/app/components/ui/accordion.tsx new file mode 100644 index 0000000..e538a33 --- /dev/null +++ b/apps/web/app/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +'use client' + +import * as React from 'react' +import * as AccordionPrimitive from '@radix-ui/react-accordion' +import { ChevronDownIcon } from 'lucide-react' + +import { cn } from '@/lib/utils' + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180', + className, + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/apps/web/app/components/ui/alert-dialog.tsx b/apps/web/app/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..9704452 --- /dev/null +++ b/apps/web/app/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +'use client' + +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' + +import { cn } from '@/lib/utils' +import { buttonVariants } from '@/components/ui/button' + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/apps/web/app/components/ui/alert.tsx b/apps/web/app/components/ui/alert.tsx new file mode 100644 index 0000000..e6751ab --- /dev/null +++ b/apps/web/app/components/ui/alert.tsx @@ -0,0 +1,66 @@ +import * as React from 'react' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/lib/utils' + +const alertVariants = cva( + 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current', + { + variants: { + variant: { + default: 'bg-card text-card-foreground', + destructive: + 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<'div'> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/apps/web/app/components/ui/aspect-ratio.tsx b/apps/web/app/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..40bb120 --- /dev/null +++ b/apps/web/app/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +'use client' + +import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio' + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return +} + +export { AspectRatio } diff --git a/apps/web/app/components/ui/avatar.tsx b/apps/web/app/components/ui/avatar.tsx new file mode 100644 index 0000000..aa98465 --- /dev/null +++ b/apps/web/app/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +'use client' + +import * as React from 'react' +import * as AvatarPrimitive from '@radix-ui/react-avatar' + +import { cn } from '@/lib/utils' + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/apps/web/app/components/ui/badge.tsx b/apps/web/app/components/ui/badge.tsx new file mode 100644 index 0000000..fc4126b --- /dev/null +++ b/apps/web/app/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/lib/utils' + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden', + { + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', + secondary: + 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', + destructive: + 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<'span'> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'span' + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/apps/web/app/components/ui/breadcrumb.tsx b/apps/web/app/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..1750ff2 --- /dev/null +++ b/apps/web/app/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { ChevronRight, MoreHorizontal } from 'lucide-react' + +import { cn } from '@/lib/utils' + +function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) { + return