Skip to content

Commit 1df2ccd

Browse files
committed
new design for auth layouts
1 parent 49908d2 commit 1df2ccd

File tree

5 files changed

+268
-241
lines changed

5 files changed

+268
-241
lines changed

resources/js/components/common/app-logo.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ interface AppLogoProps {
66

77
export const AppLogo: React.FC<AppLogoProps> = ({ size = 'small' }) => {
88
const sizeClasses = {
9-
'small': 'h-8 w-8 text-base',
10-
'large': 'h-12 w-12 text-lg',
11-
'extra-large': 'h-16 w-16 text-xl',
9+
'small': 'size-6 text-base',
10+
'large': 'size-8 text-lg',
11+
'extra-large': 'size-12 text-xl',
1212
}
1313

1414
const iconSizeClasses = {
15-
'small': 'h-4 w-4',
16-
'large': 'h-6 w-6',
17-
'extra-large': 'h-8 w-8',
15+
'small': 'size-4',
16+
'large': 'size-6',
17+
'extra-large': 'size-8',
1818
}
1919

2020
return (
2121
<div
22-
className={`group flex ${sizeClasses[size]} shrink-0 items-center justify-center gap-2 rounded-full bg-primary font-semibold text-primary-foreground`}
22+
className={`group flex ${sizeClasses[size]} shrink-0 items-center justify-center gap-2 rounded-md bg-primary font-semibold text-primary-foreground`}
2323
>
2424
<GalleryVerticalEnd
2525
className={`${iconSizeClasses[size]} transition-all group-hover:scale-110`}

resources/js/components/layout/auth-layout.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Link } from '@inertiajs/react'
22
import { type PropsWithChildren } from 'react'
33
import { DASHBOARD_ROUTE } from '@/app/routes'
44
import { AppLogo } from '../common/app-logo'
5+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card'
56

67
interface AuthLayoutProps {
78
name?: string
@@ -15,23 +16,34 @@ export const AuthLayout = ({
1516
description,
1617
}: PropsWithChildren<AuthLayoutProps>) => {
1718
return (
18-
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-background p-6 md:p-10">
19-
<div className="w-full max-w-sm">
19+
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
20+
<div className="flex w-full max-w-sm flex-col gap-6">
2021
<div className="flex flex-col gap-8">
2122
<div className="items-left flex flex-col gap-4">
22-
<Link href={DASHBOARD_ROUTE} className="mb-6 flex flex-col gap-2 font-medium">
23+
<Link
24+
href={DASHBOARD_ROUTE}
25+
className="flex items-center gap-2 self-center font-medium"
26+
>
2327
<header className="flex items-center justify-between">
24-
<AppLogo size="large" />
28+
<AppLogo size="small" />
2529
</header>
26-
<span className="sr-only">{title}</span>
30+
<span className="sr-only">App Name</span>
31+
<p>App Name</p>
2732
</Link>
28-
29-
<div>
30-
<h1 className="text-4xl font-light text-zinc-900 dark:text-white">{title}</h1>
31-
<p className="mt-2 text-lg font-light text-zinc-400">{description}</p>
33+
<div className="flex flex-col gap-6">
34+
<Card>
35+
<CardHeader className="text-center">
36+
<CardTitle className="text-xl">{title}</CardTitle>
37+
<CardDescription>{description}</CardDescription>
38+
</CardHeader>
39+
<CardContent>{children}</CardContent>
40+
</Card>
41+
<div className="text-center text-xs text-balance text-muted-foreground *:[a]:underline *:[a]:underline-offset-4 *:[a]:hover:text-primary">
42+
By clicking continue, you agree to our <a href="#">Terms of Service</a> and{' '}
43+
<a href="#">Privacy Policy</a>.
44+
</div>
3245
</div>
3346
</div>
34-
{children}
3547
</div>
3648
</div>
3749
</div>

resources/js/components/navigation/app-sidebar.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
5757
asChild
5858
>
5959
<Link href="/dashboard" prefetch>
60-
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
60+
<div className="flex size-8 items-center justify-center text-sidebar-primary-foreground">
6161
<AppLogo size="small" />
6262
</div>
6363
<div className="grid flex-1 text-left text-sm leading-tight">
64-
<span className="truncate font-medium">Acme Inc</span>
64+
<span className="truncate font-medium">App name</span>
6565
<span className="truncate text-xs">Enterprise</span>
6666
</div>
6767
</Link>
@@ -78,6 +78,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
7878
<SidebarFooter>
7979
<NavUser />
8080
</SidebarFooter>
81+
8182
<SidebarRail />
8283
</Sidebar>
8384
)

resources/js/pages/auth/login.tsx

Lines changed: 112 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { LOGIN_API } from '@/lib/constants'
1010
import { type ValidationErrors } from '@/types'
1111
import { type PageProps } from '@/types/inertia'
1212
import { Head, router, useForm } from '@inertiajs/react'
13-
import { EyeIcon, EyeOffIcon, Github, LoaderCircle, ScanFaceIcon } from 'lucide-react'
13+
import { EyeIcon, EyeOffIcon, LoaderCircle } from 'lucide-react'
1414
import { useState } from 'react'
1515

1616
type LoginForm = {
@@ -37,12 +37,12 @@ const Login = ({ status, canResetPassword, auth, flash }: LoginProps) => {
3737
const handleSubmit = (e: React.FormEvent) => {
3838
e.preventDefault()
3939

40-
// Direct Inertia form submission - cleanest approach
40+
// Direct Inertia form submission
4141
post(LOGIN_API, {
4242
onFinish: () => reset('password'),
4343
onError: (_errors) => {
4444
// show a toast or send error to Sentry or log it to Firebase.
45-
// Whatever you prefer
45+
// whatever you prefer
4646
},
4747
})
4848
}
@@ -55,114 +55,126 @@ const Login = ({ status, canResetPassword, auth, flash }: LoginProps) => {
5555
<AuthLayout title="Welcome back" description="Log in to your account">
5656
<Head title="Log in" />
5757

58-
<form className="flex flex-col gap-6" onSubmit={handleSubmit}>
58+
<form onSubmit={handleSubmit}>
5959
<div className="grid gap-6">
60-
<div className="grid gap-2">
61-
<Label htmlFor="email">Email address</Label>
62-
<Input
63-
id="email"
64-
type="email"
65-
required
66-
autoFocus
67-
tabIndex={1}
68-
autoComplete="email"
69-
value={data.email}
70-
onChange={(e) => setData('email', e.target.value)}
71-
placeholder="name@example.com"
72-
/>
73-
<InputError message={errors?.email} />
74-
</div>
75-
</div>
60+
<div className="grid gap-6">
61+
<div className="grid gap-3">
62+
<Label htmlFor="email">Email</Label>
63+
<Input
64+
id="email"
65+
type="email"
66+
required
67+
autoFocus
68+
tabIndex={1}
69+
autoComplete="email"
70+
value={data.email}
71+
onChange={(e) => setData('email', e.target.value)}
72+
placeholder="name@example.com"
73+
/>
74+
<InputError message={errors?.email} />
75+
</div>
76+
<div className="grid gap-3">
77+
<div className="flex items-center">
78+
<Label htmlFor="password">Password</Label>
79+
<a href="#" className="ml-auto text-sm underline-offset-4 hover:underline">
80+
Forgot your password?
81+
</a>
82+
</div>
83+
<div className="relative">
84+
<Input
85+
id="password"
86+
type={showPassword ? 'text' : 'password'}
87+
required
88+
tabIndex={2}
89+
autoComplete="current-password"
90+
value={data.password}
91+
onChange={(e) => setData('password', e.target.value)}
92+
/>
93+
<Button
94+
type="button"
95+
variant="ghost"
96+
size="sm"
97+
disabled={!data.password}
98+
className="absolute top-0 right-0 h-full px-3 py-2 hover:cursor-pointer hover:bg-transparent"
99+
onClick={() => setShowPassword(!showPassword)}
100+
aria-label={showPassword ? 'Hide password' : 'Show password'}
101+
>
102+
{showPassword ? (
103+
<EyeOffIcon className="h-4 w-4" />
104+
) : (
105+
<EyeIcon className="h-4 w-4" />
106+
)}
107+
</Button>
108+
</div>
109+
<InputError message={errors?.password} />
110+
</div>
111+
112+
<div className="flex items-center justify-between space-x-3">
113+
<div className="flex flex-row items-center space-y-0 space-x-2">
114+
<Checkbox
115+
id="remember"
116+
name="remember"
117+
checked={data.remember}
118+
onClick={() => setData('remember', !data.remember)}
119+
tabIndex={3}
120+
/>
121+
<Label className="text-sm font-normal" htmlFor="remember">
122+
Remember me
123+
</Label>
124+
</div>
125+
{canResetPassword && (
126+
<TextLink href={'password.request'} className="ml-auto text-sm" tabIndex={5}>
127+
Forgot password?
128+
</TextLink>
129+
)}
130+
</div>
76131

77-
<div className="grid gap-2">
78-
<div className="flex items-center">
79-
<Label htmlFor="password">Password</Label>
80-
</div>
81-
<div className="relative">
82-
<Input
83-
id="password"
84-
type={showPassword ? 'text' : 'password'}
85-
required
86-
tabIndex={2}
87-
autoComplete="current-password"
88-
value={data.password}
89-
onChange={(e) => setData('password', e.target.value)}
90-
placeholder="Password"
91-
/>
92132
<Button
93-
type="button"
94-
variant="ghost"
95-
size="sm"
96-
disabled={!data.password}
97-
className="absolute top-0 right-0 h-full px-3 py-2 hover:cursor-pointer hover:bg-transparent"
98-
onClick={() => setShowPassword(!showPassword)}
99-
aria-label={showPassword ? 'Hide password' : 'Show password'}
133+
type="submit"
134+
className="mt-4 h-12 w-full rounded-full text-base"
135+
tabIndex={4}
136+
disabled={processing}
100137
>
101-
{showPassword ? <EyeOffIcon className="h-4 w-4" /> : <EyeIcon className="h-4 w-4" />}
138+
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
139+
Log in
102140
</Button>
103141
</div>
104-
<InputError message={errors?.password} />
105-
</div>
106142

107-
<div className="flex items-center justify-between space-x-3">
108-
<div className="flex flex-row items-center space-y-0 space-x-2">
109-
<Checkbox
110-
id="remember"
111-
name="remember"
112-
checked={data.remember}
113-
onClick={() => setData('remember', !data.remember)}
114-
tabIndex={3}
115-
/>
116-
<Label className="text-sm font-normal" htmlFor="remember">
117-
Remember me
118-
</Label>
143+
<div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
144+
<span className="relative z-10 bg-card px-2 text-muted-foreground">
145+
Or continue with
146+
</span>
119147
</div>
120-
{canResetPassword && (
121-
<TextLink href={'password.request'} className="ml-auto text-sm" tabIndex={5}>
122-
Forgot password?
123-
</TextLink>
124-
)}
125-
</div>
126148

127-
<Button
128-
type="submit"
129-
className="mt-4 h-12 w-full rounded-full text-base"
130-
tabIndex={4}
131-
disabled={processing}
132-
>
133-
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
134-
Log in
135-
</Button>
136-
</form>
149+
<div className="flex gap-4">
150+
<Button variant="secondary" size="icon" className="h-12 flex-1 rounded-full">
151+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
152+
<path
153+
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
154+
fill="currentColor"
155+
/>
156+
</svg>
157+
<span className="sr-only">Login with Google</span>
158+
</Button>
159+
<Button variant="secondary" size="icon" className="h-12 flex-1 rounded-full">
160+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
161+
<path
162+
d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
163+
fill="currentColor"
164+
/>
165+
</svg>
166+
<span className="sr-only">Login with Apple</span>
167+
</Button>
168+
</div>
137169

138-
<div className="relative">
139-
<div className="absolute inset-0 flex items-center">
140-
<span className="w-full border-t" />
141-
</div>
142-
<div className="relative flex justify-center text-xs uppercase">
143-
<span className="bg-background px-2 text-zinc-500">Or continue with</span>
170+
<div className="text-center text-sm">
171+
Don&apos;t have an account?{' '}
172+
<a href="/register" className="underline underline-offset-4">
173+
Sign up
174+
</a>
175+
</div>
144176
</div>
145-
</div>
146-
147-
<div className="flex gap-4">
148-
<Button variant="outline" size="icon" className="h-12 flex-1 rounded-full">
149-
<Github className="h-6 w-6" />
150-
<span className="sr-only">GitHub</span>
151-
</Button>
152-
<Button variant="outline" size="icon" className="h-12 flex-1 rounded-full">
153-
<ScanFaceIcon className="h-6 w-6" />
154-
<span className="sr-only">Face ID</span>
155-
</Button>
156-
</div>
157-
158-
<div className="text-center">
159-
<p className="text-sm text-foreground/80">
160-
<span>Don't have an account?</span>
161-
<TextLink className="ml-1" href={'/register'}>
162-
Sign up
163-
</TextLink>
164-
</p>
165-
</div>
177+
</form>
166178

167179
{status && (
168180
<div className="mb-4 text-center text-sm font-medium text-green-600">{status}</div>

0 commit comments

Comments
 (0)