Files
live/frontend/src/admin/LoginPage.tsx
T
admin 2e4594fa77 Initial commit: LiveStream Platform
Backend: FastAPI + SQLAlchemy + SQLite
Frontend: React + Vite + Ant Design (serif Anthropic theme)
Media server: MediaMTX with edge node support
Load balancing: round-robin / weighted / least-conn
Multicast detection with automatic fallback
Transcoding support via FFmpeg (configurable quality)
hls.js player with line & quality switching
Admin panel with password auth
Windows compatible scripts
2026-08-07 15:02:07 +08:00

62 lines
1.8 KiB
TypeScript

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Card, Form, Input, Button, Typography, message, Space } from 'antd'
import { LockOutlined } from '@ant-design/icons'
import { login } from '../api/auth'
const { Title, Text } = Typography
export default function LoginPage() {
const [loading, setLoading] = useState(false)
const navigate = useNavigate()
const handleSubmit = async (values: { password: string }) => {
setLoading(true)
try {
await login(values.password)
message.success('Welcome back')
navigate('/admin')
} catch {
message.error('Invalid password')
} finally {
setLoading(false)
}
}
return (
<div style={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: '#FAF8F5',
}}>
<Card style={{ width: 400, boxShadow: '0 2px 16px rgba(0,0,0,0.04)' }}>
<Space direction="vertical" size="large" style={{ width: '100%' }}>
<div style={{ textAlign: 'center' }}>
<Title level={2} style={{ marginBottom: 4 }}>LiveStream</Title>
<Text type="secondary">Admin Panel</Text>
</div>
<Form onFinish={handleSubmit} layout="vertical">
<Form.Item
name="password"
rules={[{ required: true, message: 'Enter your password' }]}
>
<Input.Password
prefix={<LockOutlined />}
placeholder="Password"
size="large"
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={loading} block size="large">
Sign In
</Button>
</Form.Item>
</Form>
</Space>
</Card>
</div>
)
}