Skip to content

Commit 6d8af0e

Browse files
committed
refactor: เพิ่ม page( / , 404, 500) ใส่ bg login และปรับ middleware
1 parent 920c486 commit 6d8af0e

39 files changed

+538
-1236
lines changed
Lines changed: 137 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
'use client';
2+
23
import { useState } from 'react';
34
import { Button } from "@/components/ui/button";
45
import {
5-
Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,
6+
Card, CardContent, CardFooter, CardHeader,
67
} from "@/components/ui/card";
78
import { 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
}

client/my-app/src/app/(with-layout)/cameras/[cam_id]/details/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Camera } from "@/app/models/cameras.model";
1+
import { Camera } from "@/app/Models/cameras.model";
22
import CameraDetails from '@/app/components/Cameras/Details/CameraDetails'
33

44
const base = process.env.NEXT_PUBLIC_APP_URL!;

client/my-app/src/app/(with-layout)/cameras/[cam_id]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import FullScreenView from "@/app/components/Cameras/FullScreenView";
2-
import { Camera } from "@/app/models/cameras.model";
2+
import { Camera } from "@/app/Models/cameras.model";
33

44
const base = process.env.NEXT_PUBLIC_APP_URL!;
55

client/my-app/src/app/(with-layout)/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import "../../styles/globals.css";
22
import Sidebar from "../components/Layouts/SideBar";
33
import Header from "../components/Layouts/Header";
4-
import { UIProvider } from "../components/Layouts/ui-provider";
4+
import { UIProvider } from "../components/Layouts/UI-Provider";
55
import Title from "../components/Layouts/Title";
66

77
export default function RootLayout({ children }: { children: React.ReactNode }) {

client/my-app/src/app/(with-layout)/test/[cam_id]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import AccessControl from "@/app/components/CameraAccess";
3+
import AccessControl from "@/app/components/Cameras/Details/CameraAccess";
44

55
export default function Page() {
66
return (

client/my-app/src/app/(with-layout)/test/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export default function Page() {
44
return (
55
<div className="rounded-lg bg-[var(--color-white)] shadow-md p-6">
66
<div className="grid grid-cols-[repeat(auto-fit,minmax(320px,1fr))] gap-6">
7-
87
</div>
98
</div>
109
);
File renamed without changes.

0 commit comments

Comments
 (0)