11'use client' ;
2+
23import { useState } from 'react' ;
34import { Button } from "@/components/ui/button" ;
45import {
5- Card , CardContent , CardDescription , CardFooter , CardHeader , CardTitle ,
6+ Card , CardContent , CardFooter , CardHeader ,
67} from "@/components/ui/card" ;
78import { Eye , EyeOff } from "lucide-react" ;
89
@@ -39,106 +40,151 @@ export default function LoginPage() {
3940 }
4041
4142 return (
42- < div className = "min-h-screen grid place-items-center bg-[var(--color-bg)] p-4" >
43- < Card className = "w-full max-w-sm shadow-lg" >
44- < CardHeader className = "space-y-5" >
45- < div className = "flex items-center justify-center gap-3" >
46- { /* โลโก้ซ้าย */ }
47- < img src = "/automate-object-detection-system-icon.png" alt = "Logo" className = "h-9 w-9" />
48- { /* ไตเติลขวา (สองบรรทัด/สองสี) */ }
49- < div className = "leading-tight" >
50- < div className = "text-xl font-semibold text-[var(--color-secondary)]" >
51- Automate
52- </ div >
53- < div className = "text-sm font-medium text-[var(--color-primary)]" >
54- Object Detection System
55- </ div >
56- </ div >
57- </ div >
58- { /* <CardDescription className="text-center">
59- Sign in to your account
60- </CardDescription> */ }
61- < label htmlFor = "Login" className = "text-[var(--color-primary)] font-bold" > Login</ label >
62- </ CardHeader >
43+ < main
44+ className = "
45+ relative isolate min-h-[100dvh] overflow-hidden
46+ bg-gradient-to-b from-[#F0F7FF] via-[#F6FAFF] to-[#EEF2FF]
47+ dark:from-[#0B1220] dark:via-[#0A1020] dark:to-[#0A0F1E]
48+ "
49+ >
50+ { /* Blue spotlights background */ }
51+ < div aria-hidden className = "pointer-events-none absolute inset-0 -z-10" >
52+ < div className = "absolute -top-40 -left-40 h-[42rem] w-[42rem] rounded-full bg-blue-300/40 blur-3xl dark:bg-blue-900/30" />
53+ < div className = "absolute -bottom-48 -right-40 h-[48rem] w-[48rem] rounded-full bg-indigo-300/40 blur-3xl dark:bg-indigo-900/30" />
54+ { /* Subtle divider line */ }
55+ { /* <div className="absolute inset-x-0 top-1/2 h-px bg-gradient-to-r from-transparent via-blue-300/40 to-transparent dark:via-blue-800/30" /> */ }
56+ </ div >
6357
64- < CardContent >
65- < form onSubmit = { onSubmit } className = "space-y-4" >
66- < div className = "grid gap-2 mb-6" >
67- < label htmlFor = "usernameOrEmail" className = "text-sm font-light" > Username or Email</ label >
68- < input
69- id = "usernameOrEmail"
70- name = "usernameOrEmail"
71- type = "text"
72- autoComplete = "username"
73- value = { usernameOrEmail }
74- onChange = { ( e ) => setUsernameOrEmail ( e . target . value ) }
75- placeholder = "Enter your email or username"
76- className = "w-full rounded-md border px-3 py-2 outline-none focus:ring focus:ring-blue-100 text-sm font-light"
77- required
78- />
58+ < section className = "grid min-h-[100dvh] place-items-center p-4" >
59+ < Card className = "w-full max-w-sm shadow-lg border border-slate-200/60 bg-white/80 backdrop-blur-md dark:bg-slate-900/60 dark:border-slate-800/60" >
60+ < CardHeader className = "space-y-5" >
61+ < div className = "flex items-center justify-center gap-3" >
62+ < img src = "/automate-object-detection-system-icon.png" alt = "Logo" className = "h-9 w-9" />
63+ < div className = "leading-tight" >
64+ < div className = "text-xl font-semibold text-[var(--color-secondary,_#1E3A8A)]" >
65+ Automate
66+ </ div >
67+ < div className = "text-sm font-medium text-[var(--color-primary,_#0B63FF)]" >
68+ Object Detection System
69+ </ div >
70+ </ div >
7971 </ div >
72+ < label htmlFor = "Login" className = "text-[var(--color-primary,_#0B63FF)] font-bold" > Login</ label >
73+ </ CardHeader >
8074
81- < div className = "grid gap-2 mb-6" >
82- < label htmlFor = "password" className = "text-sm font-light" > Password</ label >
83- < div className = "relative" >
75+ < CardContent >
76+ < form onSubmit = { onSubmit } className = "space-y-4" >
77+ < div className = "grid gap-2 mb-6" >
78+ < label htmlFor = "usernameOrEmail" className = "text-sm font-light" > Username or Email</ label >
8479 < input
85- id = "password "
86- name = "password "
87- type = { showPass ? "text" : "password" }
88- autoComplete = "current-password "
89- value = { password }
90- onChange = { ( e ) => setPassword ( e . target . value ) }
91- placeholder = ' Enter your password'
92- className = "w-full rounded-md border px-3 py-2 pr-10 outline-none focus:ring focus:ring-blue-100 text-sm font-light"
80+ id = "usernameOrEmail "
81+ name = "usernameOrEmail "
82+ type = "text"
83+ autoComplete = "username "
84+ value = { usernameOrEmail }
85+ onChange = { ( e ) => setUsernameOrEmail ( e . target . value ) }
86+ placeholder = " Enter your email or username"
87+ className = "w-full rounded-md border border-slate-200 px-3 py-2 outline-none focus:ring-2 focus:ring-blue-200 text-sm font-light bg-white/90 dark:bg-slate-950/30 "
9388 required
9489 />
95- < button
96- type = "button"
97- aria-label = { showPass ? "Hide password" : "Show password" }
98- onClick = { ( ) => setShowPass ( v => ! v ) }
99- className = "absolute right-2 top-1/2 -translate-y-1/2 p-1"
100- >
101- { showPass ? < EyeOff size = { 18 } /> : < Eye size = { 18 } /> }
102- </ button >
10390 </ div >
104- </ div >
10591
106- { /* Remember + Forgot ในบรรทัดเดียวกัน */ }
107- < div className = "flex items-center justify-between mb-6" >
108- < label className = "flex items-center gap-2 select-none text-sm font-light" htmlFor = "remember" >
109- < input
110- id = "remember"
111- name = "remember"
112- type = "checkbox"
113- checked = { remember }
114- onChange = { ( e ) => setRemember ( e . target . checked ) }
115- className = "h-4 w-4 accent-[var(--color-primary)]"
116- />
117- Remember me
118- </ label >
92+ < div className = "grid gap-2 mb-6" >
93+ < label htmlFor = "password" className = "text-sm font-light" > Password</ label >
94+ < div className = "relative" >
95+ < input
96+ id = "password"
97+ name = "password"
98+ type = { showPass ? "text" : "password" }
99+ autoComplete = "current-password"
100+ value = { password }
101+ onChange = { ( e ) => setPassword ( e . target . value ) }
102+ placeholder = 'Enter your password'
103+ className = "w-full rounded-md border border-slate-200 px-3 py-2 pr-10 outline-none focus:ring-2 focus:ring-blue-200 text-sm font-light bg-white/90 dark:bg-slate-950/30"
104+ required
105+ />
106+ < button
107+ type = "button"
108+ aria-label = { showPass ? "Hide password" : "Show password" }
109+ onClick = { ( ) => setShowPass ( v => ! v ) }
110+ className = "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
111+ >
112+ { showPass ? < EyeOff size = { 18 } /> : < Eye size = { 18 } /> }
113+ </ button >
114+ </ div >
115+ </ div >
119116
120- < a
121- href = "/forgot"
122- className = "text-sm underline-offset-4 hover:underline font-light"
123- >
124- Forgot password?
125- </ a >
126- </ div >
117+ { /* Remember + Forgot */ }
118+ < div className = "flex items-center justify-between mb-6" >
119+ < label htmlFor = "remember" className = "group inline-flex items-center gap-3 cursor-pointer select-none text-sm font-light" >
120+ < span className = "relative inline-grid h-5 w-5 place-items-center" >
121+ { /* ตัว input จริง (คง semantics + focus) */ }
122+ < input
123+ id = "remember"
124+ name = "remember"
125+ type = "checkbox"
126+ checked = { remember }
127+ onChange = { ( e ) => setRemember ( e . target . checked ) }
128+ className = "
129+ peer absolute inset-0 h-5 w-5 cursor-pointer appearance-none opacity-0 rounded-sm
130+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-opacity-30
131+ disabled:cursor-not-allowed
132+ "
133+ />
134+ { /* กล่องแสดงผล */ }
135+ < span
136+ className = "
137+ h-5 w-5 rounded-sm border transition
138+ border-[var(--color-primary)] bg-[var(--color-primary-bg)]
139+ group-hover:brightness-105
140+ peer-active:scale-95
141+ peer-checked:bg-[var(--color-primary)]
142+ peer-checked:border-[var(--color-primary)]
143+ peer-disabled:opacity-60
144+ "
145+ />
146+ { /* ไอคอนติ๊ก (โชว์ตอน checked) */ }
147+ < svg
148+ viewBox = "0 0 20 20"
149+ className = "pointer-events-none absolute h-3.5 w-3.5 text-white opacity-0 transition-opacity peer-checked:opacity-100"
150+ aria-hidden = "true"
151+ >
152+ < path fill = "currentColor" d = "M16.704 5.292a1 1 0 010 1.416l-8.25 8.25a1 1 0 01-1.416 0L3.296 11.67a1 1 0 111.416-1.416l2.326 2.326 7.542-7.542a1 1 0 011.124-.246z" />
153+ </ svg >
154+ </ span >
155+ < span > Remember me</ span >
156+ </ label >
157+
158+ < a
159+ href = "/forgot"
160+ className = "text-sm font-light text-blue-600 hover:text-blue-700 underline-offset-4 hover:underline dark:text-blue-400 dark:hover:text-blue-300"
161+ >
162+ Forgot password?
163+ </ a >
164+ </ div >
165+
166+ { err && < p className = "text-sm text-red-600" > { err } </ p > }
127167
128- { err && < p className = "text-sm text-red-600" > { err } </ p > }
168+ < CardFooter className = "p-0" >
169+ < div className = "w-full" >
170+ < Button
171+ type = "submit"
172+ disabled = { submitting }
173+ className = "w-full bg-[var(--color-primary,_#0B63FF)] text-white hover:bg-[var(--color-secondary,_#1E3A8A)] rounded-md disabled:opacity-50"
174+ >
175+ { submitting ? "Logging in..." : "Login" }
176+ </ Button >
129177
130- < CardFooter className = "p-0" >
131- < Button
132- type = "submit"
133- disabled = { submitting }
134- className = "w-full bg-[var(--color-primary)] text-white hover:bg-[var(--color-secondary)] rounded-md disabled:opacity-50"
135- >
136- { submitting ? "Logging in..." : "Login" }
137- </ Button >
138- </ CardFooter >
139- </ form >
140- </ CardContent >
141- </ Card >
142- </ div >
178+ { /* credit */ }
179+ < p className = "mt-3 w-full text-center text-[11px] sm:text-xs text-slate-500/80 dark:text-slate-400/80" >
180+ SynTech-T5 x TTT Brother
181+ </ p >
182+ </ div >
183+ </ CardFooter >
184+ </ form >
185+ </ CardContent >
186+ </ Card >
187+ </ section >
188+ </ main >
143189 ) ;
144190}
0 commit comments