refactor(Login): rewrite login page using Material-UI components
- Replace styled components with Material-UI's AppBar, Toolbar, and Card - Update form fields to handle email and password instead of just username - Improve error handling for both email and password fields - Simplify layout and remove social login options
This commit is contained in:
BIN
src/assets/logo_bg_white.png
Normal file
BIN
src/assets/logo_bg_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 647 KiB |
BIN
src/assets/logo_text.png
Normal file
BIN
src/assets/logo_text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 558 KiB |
@@ -9,253 +9,156 @@ import {
|
||||
TextField,
|
||||
Typography,
|
||||
Link,
|
||||
styled
|
||||
AppBar,
|
||||
Toolbar,
|
||||
Card,
|
||||
CardContent
|
||||
} from '@mui/material';
|
||||
|
||||
const LoginContainer = styled(Box)({
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#f5f7fa',
|
||||
});
|
||||
|
||||
const TopBar = styled(Box)({
|
||||
height: '60px',
|
||||
backgroundColor: '#1a1a2e',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '0 20px',
|
||||
});
|
||||
|
||||
const BrandLogo = styled(Box)({
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
backgroundColor: '#fff',
|
||||
color: '#1a1a2e',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
});
|
||||
|
||||
const LoginMain = styled(Box)({
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
});
|
||||
|
||||
const LoginCard = styled(Box)({
|
||||
width: '400px',
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||
padding: '30px',
|
||||
});
|
||||
|
||||
const ServiceName = styled(Typography)({
|
||||
fontSize: '0.75rem',
|
||||
color: '#666',
|
||||
marginBottom: '10px',
|
||||
});
|
||||
|
||||
const LoginTitle = styled(Typography)({
|
||||
fontSize: '1.5rem',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '20px',
|
||||
});
|
||||
|
||||
const LoginForm = styled('form')({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '20px',
|
||||
});
|
||||
|
||||
const RememberRow = styled(Box)({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
const ActionButtons = styled(Box)({
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
marginTop: '10px',
|
||||
});
|
||||
|
||||
const PrimaryButton = styled(Button)({
|
||||
backgroundColor: '#e20074',
|
||||
'&:hover': {
|
||||
backgroundColor: '#c10062',
|
||||
},
|
||||
});
|
||||
|
||||
const SecondaryButton = styled(Button)({
|
||||
color: '#333',
|
||||
backgroundColor: '#f5f5f5',
|
||||
'&:hover': {
|
||||
backgroundColor: '#e0e0e0',
|
||||
},
|
||||
});
|
||||
|
||||
const HelpSection = styled(Box)({
|
||||
marginTop: '20px',
|
||||
textAlign: 'center',
|
||||
fontSize: '0.875rem',
|
||||
});
|
||||
|
||||
const SocialLogin = styled(Box)({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: '10px',
|
||||
marginTop: '15px',
|
||||
});
|
||||
|
||||
const SocialButton = styled(Box)({
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#e0e0e0',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
});
|
||||
|
||||
const Footer = styled(Box)({
|
||||
height: '50px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '0 20px',
|
||||
borderTop: '1px solid #eee',
|
||||
fontSize: '0.75rem',
|
||||
color: '#666',
|
||||
});
|
||||
|
||||
const LegalLinks = styled(Box)({
|
||||
display: 'flex',
|
||||
gap: '15px',
|
||||
});
|
||||
|
||||
const Login = () => {
|
||||
const [username, setUsername] = useState('');
|
||||
const [rememberUser, setRememberUser] = useState(false);
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [rememberEmail, setRememberEmail] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [error, setError] = useState(false);
|
||||
const [emailError, setEmailError] = useState(false);
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!username.trim()) {
|
||||
setError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const hasEmail = !!email.trim();
|
||||
const hasPassword = !!password.trim();
|
||||
setEmailError(!hasEmail);
|
||||
setPasswordError(!hasPassword);
|
||||
if (!hasEmail || !hasPassword) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
setError(false);
|
||||
|
||||
// 模拟登录过程
|
||||
setTimeout(() => {
|
||||
navigate('/');
|
||||
}, 800);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<LoginContainer>
|
||||
<TopBar>
|
||||
<BrandLogo>T</BrandLogo>
|
||||
</TopBar>
|
||||
|
||||
<LoginMain>
|
||||
<LoginCard>
|
||||
<ServiceName>Servicename</ServiceName>
|
||||
<LoginTitle>
|
||||
Enter Login <br/> Username
|
||||
</LoginTitle>
|
||||
|
||||
<LoginForm onSubmit={handleSubmit} noValidate>
|
||||
<TextField
|
||||
fullWidth
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
error={error}
|
||||
required
|
||||
/>
|
||||
|
||||
<RememberRow>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={rememberUser}
|
||||
onChange={(e) => setRememberUser(e.target.checked)}
|
||||
id="rememberUser"
|
||||
/>
|
||||
}
|
||||
label="Remember username"
|
||||
<Box sx={{ minHeight: '100vh', width: '100vw', bgcolor: 'background.default', display: 'flex', flexDirection: 'column' }}>
|
||||
{/* 顶部栏使用主题主色 */}
|
||||
<AppBar position="static" color="primary" enableColorOnDark>
|
||||
<Toolbar sx={{ minHeight: 60 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
bgcolor: 'common.white',
|
||||
color: 'primary.main',
|
||||
borderRadius: '50%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontWeight: 700,
|
||||
fontSize: '1.1rem',
|
||||
}}
|
||||
aria-label="Brand"
|
||||
>
|
||||
T
|
||||
</Box>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
{/* 主体卡片 */}
|
||||
<Container maxWidth="sm" sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
|
||||
<Card sx={{ width: '100%' }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
|
||||
Servicename
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
|
||||
Enter Login
|
||||
<br /> Email & Password
|
||||
</Typography>
|
||||
|
||||
<Box component="form" onSubmit={handleSubmit} noValidate>
|
||||
<TextField
|
||||
fullWidth
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
error={emailError}
|
||||
required
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
<Link href="#" variant="caption">
|
||||
Forgot your username or password?
|
||||
</Link>
|
||||
</RememberRow>
|
||||
|
||||
<ActionButtons>
|
||||
<PrimaryButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? 'Processing...' : 'Next'}
|
||||
</PrimaryButton>
|
||||
<SecondaryButton
|
||||
type="button"
|
||||
variant="contained"
|
||||
fullWidth
|
||||
onClick={handleCancel}
|
||||
>
|
||||
Cancel
|
||||
</SecondaryButton>
|
||||
</ActionButtons>
|
||||
</LoginForm>
|
||||
|
||||
<HelpSection>
|
||||
<Link href="#">Do you need help?</Link>
|
||||
<Box mt={1}>
|
||||
No account? <Link href="#">Sign up</Link> or log in with your social network account.
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
error={passwordError}
|
||||
required
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={rememberEmail}
|
||||
onChange={(e) => setRememberEmail(e.target.checked)}
|
||||
id="rememberEmail"
|
||||
/>
|
||||
}
|
||||
label="Remember email"
|
||||
/>
|
||||
<Link href="#" variant="caption">
|
||||
Forgot your username or password?
|
||||
</Link>
|
||||
</Box>
|
||||
|
||||
<Button type="submit" variant="contained" fullWidth disabled={isSubmitting}>
|
||||
{isSubmitting ? 'Processing...' : 'Login'}
|
||||
</Button>
|
||||
</Box>
|
||||
</HelpSection>
|
||||
|
||||
<SocialLogin>
|
||||
<SocialButton aria-label="Login with Facebook">
|
||||
<Link href="#" underline="none" color="inherit">f</Link>
|
||||
</SocialButton>
|
||||
<SocialButton aria-label="Login with Twitter">
|
||||
<Link href="#" underline="none" color="inherit">t</Link>
|
||||
</SocialButton>
|
||||
</SocialLogin>
|
||||
</LoginCard>
|
||||
</LoginMain>
|
||||
|
||||
<Footer>
|
||||
|
||||
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
||||
<Link href="#">Do you need help?</Link>
|
||||
<Box mt={0.5}>
|
||||
{/* 保留说明文案,去掉社交登录 */}
|
||||
No account? <Link href="#">Sign up</Link>.
|
||||
</Box>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Container>
|
||||
|
||||
{/* 页脚 */}
|
||||
<Box
|
||||
sx={{
|
||||
borderTop: '1px solid',
|
||||
borderColor: 'divider',
|
||||
height: 50,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
px: 2,
|
||||
color: 'text.secondary',
|
||||
bgcolor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
<Box>© Deutsche Telekom AG</Box>
|
||||
<LegalLinks>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<Link href="#" color="inherit">Imprint</Link>
|
||||
<Link href="#" color="inherit">Data privacy</Link>
|
||||
</LegalLinks>
|
||||
</Footer>
|
||||
</LoginContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user