echoes/frontend/app/dashboard/login.tsx

199 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import "./styles/login.css";
import { Template } from "interface/template";
import { Container, Heading, Text, Box, Flex, Button } from "@radix-ui/themes";
import { PersonIcon, LockClosedIcon } from "@radix-ui/react-icons";
import { useEffect, useRef, useState, useMemo } from "react";
import { gsap } from "gsap";
import { AnimatedBackground } from "hooks/Background";
import { useThemeMode, ThemeModeToggle } from "hooks/ThemeMode";
import { useNotification } from "hooks/Notification";
export default new Template({}, ({ http, args }) => {
const containerRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { mode } = useThemeMode();
const [hasBackgroundError, setHasBackgroundError] = useState(false);
const notification = useNotification();
useEffect(() => {
setIsVisible(true);
const ctx = gsap.context(() => {
// 登录框动画
gsap.from(".login-box", {
y: 30,
opacity: 0,
duration: 1,
ease: "power3.out",
});
// 表单元素动画
gsap.from(".form-element", {
x: -20,
opacity: 0,
duration: 0.8,
stagger: 0.1,
ease: "power2.out",
delay: 0.3,
});
// 按钮动画
gsap.from(".login-button", {
scale: 0.9,
opacity: 0,
duration: 0.5,
ease: "back.out(1.7)",
delay: 0.8,
});
}, containerRef);
return () => ctx.revert();
}, []);
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
try {
// 这里添加登录逻辑
await new Promise((resolve) => setTimeout(resolve, 1500)); // 模拟API请求
// 登录成功的通知
notification.success("登录成功", "欢迎回来!");
// 登录成功后的处理
console.log("Login successful");
} catch (error) {
// 登录失败的通知
notification.error("登录失败", "用户名或密码错误");
console.error("Login failed:", error);
} finally {
setIsLoading(false);
}
};
const handleBackgroundError = () => {
console.log("Background failed to load, switching to fallback");
setHasBackgroundError(true);
};
// 使用 useMemo 包裹背景组件
const backgroundComponent = useMemo(
() =>
!hasBackgroundError && (
<AnimatedBackground onError={handleBackgroundError} />
),
[hasBackgroundError],
);
return (
<div className="relative min-h-screen">
{backgroundComponent}
<Box
className="fixed top-4 right-4 z-20 w-10 h-10 flex items-center justify-center [&_button]:w-10 [&_button]:h-10 [&_svg]:w-6 [&_svg]:h-6"
style={
{
"--button-color": "var(--gray-12)",
"--button-hover-color": "var(--accent-9)",
} as React.CSSProperties
}
>
<ThemeModeToggle />
</Box>
<Container
ref={containerRef}
className={`relative z-10 h-screen w-full flex items-center justify-center transition-all duration-300 ${
isVisible ? "opacity-100" : "opacity-0"
}`}
>
<Box className="w-full max-w-md mx-auto px-4">
<Box
className="login-box backdrop-blur-sm rounded-lg shadow-lg p-8 border transition-colors duration-300"
style={{
backgroundColor:
mode === "dark"
? "var(--gray-2-alpha-80)"
: "var(--white-alpha-80)",
borderColor: "var(--gray-6)",
}}
>
{/* Logo */}
<Flex direction="column" align="center" className="mb-8">
<Heading size="6" className="text-center mb-2">
</Heading>
</Flex>
{/* 登录表单 */}
<form onSubmit={handleLogin}>
<Flex direction="column" gap="4">
{/* 用户名输入框 */}
<Box className="form-element input-box relative">
<input
className="login-input"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<label></label>
</Box>
{/* 密码输入框 */}
<Box className="form-element input-box relative">
<input
className="login-input"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<label></label>
</Box>
{/* 登录按钮 */}
<Button
className="login-button w-full h-10 transition-colors duration-300 hover:bg-[--hover-bg]"
style={
{
backgroundColor: "var(--accent-9)",
color: "white",
"--hover-bg": "var(--accent-10)",
} as React.CSSProperties
}
size="3"
type="submit"
disabled={isLoading}
>
{isLoading ? "登录中..." : "登录"}
</Button>
{/* 其他选项 */}
<Flex justify="center" className="form-element">
<Text
size="2"
className="cursor-pointer transition-colors duration-300 hover:text-[--hover-color]"
style={
{
color: "var(--gray-11)",
"--hover-color": "var(--accent-9)",
} as React.CSSProperties
}
>
</Text>
</Flex>
</Flex>
</form>
</Box>
</Box>
</Container>
</div>
);
});