Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yaoai-video
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姚珂
yaoai-video
Commits
24b905e2
Commit
24b905e2
authored
May 27, 2026
by
yaoke.yk
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
登录页面优化
parent
3db44894
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
148 additions
and
54 deletions
+148
-54
LoginPage.tsx
doc/html/src/app/pages/LoginPage.tsx
+148
-54
login-ai-studio-bg.png
doc/html/src/assets/login-ai-studio-bg.png
+0
-0
No files found.
doc/html/src/app/pages/LoginPage.tsx
View file @
24b905e2
import
{
useState
}
from
"react"
;
import
{
type
FormEvent
,
useState
}
from
"react"
;
import
{
Link
}
from
"react-router"
;
import
{
ArrowRight
,
Eye
,
EyeOff
,
Film
,
Loader2
,
LockKeyhole
,
Mail
,
ShieldCheck
,
Sparkles
}
from
"lucide-react"
;
import
{
Button
}
from
"../components/ui/button"
;
import
{
Input
}
from
"../components/ui/input"
;
import
{
Label
}
from
"../components/ui/label"
;
import
{
Card
,
CardContent
,
CardDescription
,
CardHeader
,
CardTitle
}
from
"../components/ui/card"
;
import
{
useAuth
}
from
"../../hooks/useAuth"
;
import
loginAiStudioBg
from
"../../assets/login-ai-studio-bg.png"
;
export
function
LoginPage
()
{
const
{
login
,
loginPending
,
loginError
}
=
useAuth
();
const
[
form
,
setForm
]
=
useState
({
email
:
""
,
password
:
""
});
const
[
formError
,
setFormError
]
=
useState
<
string
|
null
>
(
null
);
const
[
showPassword
,
setShowPassword
]
=
useState
(
false
);
const
handleSubmit
=
(
e
:
React
.
FormEvent
)
=>
{
e
.
preventDefault
();
const
visibleError
=
formError
??
(
loginError
instanceof
Error
?
loginError
.
message
:
loginError
?
"登录失败,请稍后重试"
:
null
);
const
handleSubmit
=
(
event
:
FormEvent
<
HTMLFormElement
>
)
=>
{
event
.
preventDefault
();
const
email
=
form
.
email
.
trim
();
const
password
=
form
.
password
.
trim
()
;
const
password
=
form
.
password
;
if
(
!
email
||
!
password
)
{
setFormError
(
"请输入邮箱和密码"
);
...
...
@@ -25,63 +30,152 @@ export function LoginPage() {
login
({
email
,
password
});
};
const
updateField
=
(
field
:
"email"
|
"password"
,
value
:
string
)
=>
{
setFormError
(
null
);
setForm
((
current
)
=>
({
...
current
,
[
field
]:
value
}));
};
return
(
<
div
className=
"min-h-screen flex items-center justify-center bg-background px-4"
>
<
Card
className=
"w-full max-w-sm"
>
<
CardHeader
className=
"text-center"
>
<
CardTitle
className=
"text-2xl"
>
Dramix
</
CardTitle
>
<
CardDescription
>
登录您的账号
</
CardDescription
>
</
CardHeader
>
<
CardContent
>
<
form
onSubmit=
{
handleSubmit
}
className=
"space-y-4"
noValidate
>
<
div
className=
"space-y-2"
>
<
Label
htmlFor=
"email"
>
邮箱
</
Label
>
<
Input
id=
"email"
type=
"email"
placeholder=
"you@example.com"
required
value=
{
form
.
email
}
onChange=
{
(
e
)
=>
{
setFormError
(
null
);
setForm
((
f
)
=>
({
...
f
,
email
:
e
.
target
.
value
}));
}
}
/>
</
div
>
<
div
className=
"space-y-2"
>
<
Label
htmlFor=
"password"
>
密码
</
Label
>
<
Input
id=
"password"
type=
"password"
placeholder=
"••••••••"
required
value=
{
form
.
password
}
onChange=
{
(
e
)
=>
{
setFormError
(
null
);
setForm
((
f
)
=>
({
...
f
,
password
:
e
.
target
.
value
}));
}
}
/>
<
main
className=
"relative min-h-dvh overflow-hidden bg-[#090d18] text-white"
>
<
div
aria
-
hidden=
"true"
className=
"absolute inset-0 bg-cover bg-[46%_center] opacity-95"
style=
{
{
backgroundImage
:
`url(${loginAiStudioBg})`
}
}
/>
<
div
aria
-
hidden=
"true"
className=
"absolute inset-0 bg-[linear-gradient(90deg,rgba(5,8,17,0.66)_0%,rgba(8,12,24,0.30)_42%,rgba(8,12,24,0.62)_70%,rgba(5,8,17,0.92)_100%)]"
/>
<
div
aria
-
hidden=
"true"
className=
"absolute inset-x-0 bottom-0 h-1/3 bg-[linear-gradient(0deg,rgba(6,9,17,0.78),rgba(6,9,17,0))]"
/>
<
div
className=
"relative z-10 flex min-h-dvh flex-col px-5 py-6 sm:px-8 lg:px-12"
>
<
Link
to=
"/"
className=
"flex w-fit items-center gap-2 text-white"
aria
-
label=
"返回 Dramix.ai 首页"
>
<
span
className=
"flex h-9 w-9 items-center justify-center rounded-lg bg-white/14 shadow-[0_12px_28px_rgba(0,0,0,0.22)] ring-1 ring-white/18 backdrop-blur"
>
<
Film
className=
"h-5 w-5 text-white"
/>
</
span
>
<
span
className=
"text-lg font-semibold tracking-normal"
>
Dramix.ai
</
span
>
</
Link
>
<
section
className=
"grid flex-1 items-center gap-10 py-10 lg:grid-cols-[minmax(420px,0.95fr)_minmax(380px,460px)_minmax(48px,0.28fr)] lg:py-14"
>
<
div
className=
"hidden max-w-[680px] lg:block"
>
<
div
className=
"inline-flex items-center gap-2 rounded-full border border-white/16 bg-black/18 px-3 py-1.5 text-sm text-[#dbeafe] backdrop-blur"
>
<
Sparkles
className=
"h-4 w-4 text-[#7dd3fc]"
/>
从灵感到成片的一体化流程
</
div
>
<
h1
className=
"mt-5 text-[48px] font-semibold leading-[1.06] tracking-normal text-white xl:text-[64px]"
>
让每个短剧项目都有清晰的制作节奏。
</
h1
>
<
p
className=
"mt-5 max-w-[560px] text-base leading-8 text-[#d7e0ee]"
>
在控制台里完成剧本拆解、角色设定、分镜审阅和视频生成,团队可以围绕同一套素材持续迭代。
</
p
>
</
div
>
{
(
formError
||
loginError
)
&&
(
<
p
className=
"text-sm text-destructive"
>
{
formError
??
(
loginError
instanceof
Error
?
loginError
.
message
:
"登录失败"
)
}
<
div
className=
"w-full max-w-[460px] justify-self-center rounded-2xl border border-white/18 bg-white/[0.12] p-5 shadow-[0_28px_80px_rgba(0,0,0,0.34)] backdrop-blur-2xl sm:p-7"
>
<
div
className=
"mb-7"
>
<
div
className=
"mb-5 inline-flex items-center gap-2 rounded-full border border-white/16 bg-white/12 px-3 py-1.5 text-sm font-medium text-[#e5eefc]"
>
<
ShieldCheck
className=
"h-4 w-4 text-[#6ce9a6]"
/>
AI 漫剧平台控制台
</
div
>
<
h2
className=
"text-[32px] font-semibold leading-tight tracking-normal text-white sm:text-[38px]"
>
登录工作台
</
h2
>
<
p
className=
"mt-3 text-base leading-7 text-[#d7e0ee]"
>
管理剧本、角色、分镜和视频生成任务,继续推进你的短剧项目。
</
p
>
)
}
</
div
>
<
form
onSubmit=
{
handleSubmit
}
className=
"space-y-5"
noValidate
>
<
div
className=
"space-y-2"
>
<
Label
htmlFor=
"email"
className=
"text-sm font-semibold text-[#f2f4f7]"
>
邮箱
</
Label
>
<
div
className=
"relative"
>
<
Mail
className=
"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#98a2b3]"
/>
<
Input
id=
"email"
type=
"email"
autoComplete=
"email"
inputMode=
"email"
placeholder=
"admin@yaoai.com"
required
aria
-
invalid=
{
Boolean
(
visibleError
)
}
aria
-
describedby=
{
visibleError
?
"login-error"
:
undefined
}
className=
"h-12 rounded-lg border-white/18 bg-white/92 pl-10 text-[16px] text-[#101828] shadow-[0_1px_2px_rgba(16,24,40,0.08)] placeholder:text-[#98a2b3] focus-visible:border-[#8f7bff] focus-visible:ring-[#8f7bff]/30"
value=
{
form
.
email
}
onChange=
{
(
event
)
=>
updateField
(
"email"
,
event
.
target
.
value
)
}
/>
</
div
>
</
div
>
<
Button
type=
"submit"
className=
"w-full"
disabled=
{
loginPending
}
>
{
loginPending
?
"登录中..."
:
"登录"
}
</
Button
>
<
div
className=
"space-y-2"
>
<
Label
htmlFor=
"password"
className=
"text-sm font-semibold text-[#f2f4f7]"
>
密码
</
Label
>
<
div
className=
"relative"
>
<
LockKeyhole
className=
"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#98a2b3]"
/>
<
Input
id=
"password"
type=
{
showPassword
?
"text"
:
"password"
}
autoComplete=
"current-password"
placeholder=
"请输入密码"
required
aria
-
invalid=
{
Boolean
(
visibleError
)
}
aria
-
describedby=
{
visibleError
?
"login-error"
:
undefined
}
className=
"h-12 rounded-lg border-white/18 bg-white/92 pl-10 pr-12 text-[16px] text-[#101828] shadow-[0_1px_2px_rgba(16,24,40,0.08)] placeholder:text-[#98a2b3] focus-visible:border-[#8f7bff] focus-visible:ring-[#8f7bff]/30"
value=
{
form
.
password
}
onChange=
{
(
event
)
=>
updateField
(
"password"
,
event
.
target
.
value
)
}
/>
<
button
type=
"button"
aria
-
label=
{
showPassword
?
"隐藏密码"
:
"显示密码"
}
onClick=
{
()
=>
setShowPassword
((
value
)
=>
!
value
)
}
className=
"absolute right-2 top-1/2 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-md text-[#667085] transition hover:bg-[#eef2f6] hover:text-[#344054] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#8f7bff]/40"
>
{
showPassword
?
<
EyeOff
className=
"h-4 w-4"
/>
:
<
Eye
className=
"h-4 w-4"
/>
}
</
button
>
</
div
>
</
div
>
<
p
className=
"text-center text-sm text-muted-foreground"
>
{
visibleError
&&
(
<
div
id=
"login-error"
role=
"alert"
className=
"rounded-lg border border-[#fecdca] bg-[#fff4f3] px-3.5 py-3 text-sm leading-6 text-[#b42318]"
>
{
visibleError
}
</
div
>
)
}
<
Button
type=
"submit"
className=
"h-12 w-full rounded-lg bg-[#8064f1] text-base font-semibold text-white shadow-[0_16px_36px_rgba(79,70,229,0.34)] transition hover:bg-[#7357e8] focus-visible:ring-[#a99bff]/40"
disabled=
{
loginPending
}
>
{
loginPending
?
(
<>
<
Loader2
className=
"h-4 w-4 animate-spin"
/>
登录中
</>
)
:
(
<>
登录
<
ArrowRight
className=
"h-4 w-4"
/>
</>
)
}
</
Button
>
</
form
>
<
p
className=
"mt-7 text-center text-sm text-[#d7e0ee]"
>
没有账号?
{
" "
}
<
Link
to=
"/register"
className=
"
text-primary
underline-offset-4 hover:underline"
>
立即注册
<
Link
to=
"/register"
className=
"
font-semibold text-white
underline-offset-4 hover:underline"
>
创建账号
</
Link
>
</
p
>
</
form
>
</
CardContent
>
</
Card
>
</
div
>
</
div
>
</
section
>
<
p
className=
"relative z-10 text-xs leading-5 text-[#b8c2d3] lg:text-right"
>
© 2026 Dramix.ai
</
p
>
</
div
>
</
main
>
);
}
doc/html/src/assets/login-ai-studio-bg.png
0 → 100644
View file @
24b905e2
1.48 MB
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment