auto-save 2026-05-15 17:11 (~6)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import type { FormEvent } from "react"
|
||||
import { useState } from "react"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import {
|
||||
AlertCircle,
|
||||
ArrowRight,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
Sparkles,
|
||||
UserRound,
|
||||
} from "lucide-react"
|
||||
import { AnimatedLoginCharacters, type LoginCharacterMood } from "@/components/login/animated-login-characters"
|
||||
|
||||
type LoginStatus = "idle" | "loading" | "success"
|
||||
|
||||
@@ -25,11 +26,33 @@ export default function LoginPage() {
|
||||
const [password, setPassword] = useState("")
|
||||
const [remember, setRemember] = useState(true)
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const [activeField, setActiveField] = useState<"username" | "password" | null>(null)
|
||||
const [error, setError] = useState("")
|
||||
const [status, setStatus] = useState<LoginStatus>("idle")
|
||||
const [eyeOffset, setEyeOffset] = useState({ x: 0, y: 0 })
|
||||
|
||||
useEffect(() => {
|
||||
const onPointerMove = (event: PointerEvent) => {
|
||||
const centerX = window.innerWidth / 2
|
||||
const centerY = window.innerHeight / 2
|
||||
const nextX = Math.max(-1, Math.min(1, (event.clientX - centerX) / centerX))
|
||||
const nextY = Math.max(-1, Math.min(1, (event.clientY - centerY) / centerY))
|
||||
setEyeOffset({ x: nextX * 8, y: nextY * 5.5 })
|
||||
}
|
||||
window.addEventListener("pointermove", onPointerMove)
|
||||
return () => window.removeEventListener("pointermove", onPointerMove)
|
||||
}, [])
|
||||
|
||||
const disabled = status === "loading" || status === "success"
|
||||
|
||||
const mood: LoginCharacterMood = useMemo(() => {
|
||||
if (status === "success") return "success"
|
||||
if (error) return "error"
|
||||
if (showPassword && activeField === "password") return "peek"
|
||||
if (activeField || username || password) return "typing"
|
||||
return "idle"
|
||||
}, [activeField, error, password, showPassword, status, username])
|
||||
|
||||
async function onSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
setError("")
|
||||
@@ -95,6 +118,10 @@ export default function LoginPage() {
|
||||
<span>G7 Pro Fold</span>
|
||||
<b>Neck Massager</b>
|
||||
</div>
|
||||
<div className="login-dynamic-dock">
|
||||
<span className="login-dynamic-dock__label">Live Studio Modules</span>
|
||||
<AnimatedLoginCharacters mood={mood} eyeOffset={eyeOffset} />
|
||||
</div>
|
||||
<div className="login-studio-chip login-studio-chip--visual">
|
||||
<Sparkles className="h-4 w-4" />
|
||||
<span>Visual Asset Flow</span>
|
||||
@@ -141,6 +168,8 @@ export default function LoginPage() {
|
||||
disabled={disabled}
|
||||
autoComplete="username"
|
||||
placeholder="请输入账号"
|
||||
onFocus={() => setActiveField("username")}
|
||||
onBlur={() => setActiveField(null)}
|
||||
onChange={(event) => {
|
||||
setUsername(event.target.value)
|
||||
if (error) setError("")
|
||||
@@ -160,6 +189,8 @@ export default function LoginPage() {
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="current-password"
|
||||
placeholder="请输入密码"
|
||||
onFocus={() => setActiveField("password")}
|
||||
onBlur={() => setActiveField(null)}
|
||||
onChange={(event) => {
|
||||
setPassword(event.target.value)
|
||||
if (error) setError("")
|
||||
|
||||
Reference in New Issue
Block a user