auto-save 2026-05-15 17:11 (~6)

This commit is contained in:
2026-05-15 17:11:52 +08:00
parent f3230ff99e
commit 6c9806ce98
6 changed files with 106 additions and 14 deletions

View File

@@ -296,6 +296,50 @@
font-weight: 600;
line-height: 1.05;
}
.login-dynamic-dock {
position: absolute;
left: 0;
bottom: 118px;
width: 252px;
border: 1px solid rgba(255, 255, 255, 0.72);
border-radius: 8px;
background: rgba(255, 255, 255, 0.64);
padding: 12px;
box-shadow: 0 22px 52px rgba(40, 40, 40, 0.12);
backdrop-filter: blur(18px);
}
.login-dynamic-dock__label {
display: block;
margin-bottom: 8px;
color: rgba(40, 40, 40, 0.46);
font-size: 11px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.login-dynamic-dock .login-character-stage {
min-height: 116px;
border-color: rgba(40, 40, 40, 0.08);
background:
linear-gradient(90deg, rgba(40, 40, 40, 0.04) 1px, transparent 1px),
linear-gradient(180deg, rgba(40, 40, 40, 0.04) 1px, transparent 1px),
rgba(255, 255, 255, 0.5);
background-size: 22px 22px, 22px 22px, auto;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.84);
}
.login-dynamic-dock .login-character-stage::after {
height: 48%;
background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.7));
}
.login-dynamic-dock .login-stage-grid {
inset: 12px;
border-color: rgba(40, 40, 40, 0.08);
}
.login-dynamic-dock .login-characters-container {
left: 50%;
bottom: 0;
transform: translateX(-50%) scale(0.28);
}
.login-studio-chip {
position: absolute;
display: inline-flex;
@@ -816,6 +860,18 @@
.login-product-caption b {
font-size: 22px;
}
.login-dynamic-dock {
left: 0;
bottom: 132px;
width: 210px;
padding: 10px;
}
.login-dynamic-dock .login-character-stage {
min-height: 94px;
}
.login-dynamic-dock .login-characters-container {
transform: translateX(-50%) scale(0.22);
}
.login-studio-chip {
font-size: 12px;
}

View File

@@ -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("")