From ce97a1096e615e0837fa9e8c3bae372e73b1ec58 Mon Sep 17 00:00:00 2001 From: Francisco Pessano Date: Wed, 10 Sep 2025 20:47:40 -0300 Subject: [PATCH] feat: add auth layout component with shared sign-in/sign-up forms --- apps/web/src/components/auth-layout.tsx | 69 ++++++++ apps/web/src/components/sign-in-form.tsx | 152 ++++++++---------- apps/web/src/components/sign-up-form.tsx | 191 ++++++++++------------- apps/web/src/routes/login.tsx | 58 ++++++- 4 files changed, 272 insertions(+), 198 deletions(-) create mode 100644 apps/web/src/components/auth-layout.tsx diff --git a/apps/web/src/components/auth-layout.tsx b/apps/web/src/components/auth-layout.tsx new file mode 100644 index 0000000..fe9ccae --- /dev/null +++ b/apps/web/src/components/auth-layout.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { Link } from "@tanstack/react-router"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card"; + +export default function AuthLayout({ + title, + subtitle, + children, + footer, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; + footer?: React.ReactNode; +}) { + return ( +
+ {/* Background aesthetics */} +
+
+
+
+ +
+ {/* Marketing / Brand panel */} + + + {/* Form panel */} +
+
+ + + {title} + {subtitle ? ( + {subtitle} + ) : null} + + {children} + + {footer ?
{footer}
: null} +
+
+
+
+ ); +} diff --git a/apps/web/src/components/sign-in-form.tsx b/apps/web/src/components/sign-in-form.tsx index 2b59c81..8a8fbdd 100644 --- a/apps/web/src/components/sign-in-form.tsx +++ b/apps/web/src/components/sign-in-form.tsx @@ -64,95 +64,71 @@ export default function SignInForm({ } return ( -
-

Welcome Back

- -
{ - e.preventDefault(); - e.stopPropagation(); - form.handleSubmit(); - }} - > -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - type="email" - value={field.state.value} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
- -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - type="password" - value={field.state.value} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
- - - {(state) => ( - + { + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + > +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + type="email" + value={field.state.value} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
)} - - - -
-
- - -
- +
-
+ +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + type="password" + value={field.state.value} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
+ + + {(state) => ( + + )} + + ); } diff --git a/apps/web/src/components/sign-up-form.tsx b/apps/web/src/components/sign-up-form.tsx index 7965289..bec60cf 100644 --- a/apps/web/src/components/sign-up-form.tsx +++ b/apps/web/src/components/sign-up-form.tsx @@ -66,112 +66,93 @@ export default function SignUpForm({ } return ( -
-

Create Account

- -
{ - e.preventDefault(); - e.stopPropagation(); - form.handleSubmit(); - }} - > -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - value={field.state.value} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
- -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - type="email" - value={field.state.value} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
- -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - type="password" - value={field.state.value} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
- - - {(state) => ( - + { + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + > +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + value={field.state.value} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
)} - - - -
-
- - -
+
-
+ +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + type="email" + value={field.state.value} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
+ +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + type="password" + value={field.state.value} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
+ + + {(state) => ( + + )} + + ); } diff --git a/apps/web/src/routes/login.tsx b/apps/web/src/routes/login.tsx index ac54a64..a3d172d 100644 --- a/apps/web/src/routes/login.tsx +++ b/apps/web/src/routes/login.tsx @@ -1,7 +1,9 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; +import { createFileRoute, Link, redirect } from "@tanstack/react-router"; import { useState } from "react"; import SignInForm from "@/components/sign-in-form"; import SignUpForm from "@/components/sign-up-form"; +import AuthLayout from "@/components/auth-layout"; +import { Button } from "@/components/ui/button"; import { account } from "@/lib/auth-client"; export const Route = createFileRoute("/login")({ @@ -27,9 +29,55 @@ export const Route = createFileRoute("/login")({ function RouteComponent() { const [showSignIn, setShowSignIn] = useState(false); - return showSignIn ? ( - setShowSignIn(false)} /> - ) : ( - setShowSignIn(true)} /> + const title = showSignIn ? "Welcome back" : "Create your account"; + const subtitle = showSignIn + ? "Sign in to access your dashboard and keep creating." + : "Join Reflecto to capture ideas and collaborate seamlessly."; + + return ( + +
+ + +
+ +
+ {showSignIn ? ( + + ) : ( + + )} +
+
+ } + subtitle={subtitle} + title={title} + > + {showSignIn ? ( + setShowSignIn(false)} /> + ) : ( + setShowSignIn(true)} /> + )} + ); }