С помощью material-ui можно создавать красивый интерфейс, не используя верстку и прописывание стилей. Очень удобно!
Установка Material-ui
npm install @material-ui/core
npm install @material-ui/icons
И также шрифты в index.html
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
Файлы проекта:
Структура проекта:
В файл index.html – добавлены шрифт Roboto для material-ui
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Список дел"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<title>Список дел</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Файл index.js – стандартный, ничего особенного:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
В файл App.js – добавил роутер на будущее:
import React from 'react';
import {BrowserRouter as Router, Route, Switch, Redirect} from 'react-router-dom';
import WelcomePage from './WelcomePage';
function App() {
return (
<Router>
<Switch>
<Route exact path='/(welcome)?' component={WelcomePage} />
<Redirect to='/' />
</Switch>
</Router>
);
}
export default App;
Файл Copyright.js
import React from 'react';
import Typography from '@material-ui/core/Typography';
import Link from '@material-ui/core/Link';
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{' © '}
<Link color="inherit" href="https://polyakovdmitriy.ru">
Дмитрий Поляков
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
export default Copyright;
В файле WelcomePage.js обработчики отправки формы, и обработчики полей ввода
import React from 'react';
import Login from './Login';
class WelcomePage extends React.Component {
state ={
email: '',
password: ''
}
onEmailChange = (e) =>{
this.setState({
email: e.target.value
})
}
onPasswordChahge = (e) =>{
this.setState({
password: e.target.value
})
}
onSigninSubmit = (e) =>{
e.preventDefault();
console.log('email: ' + this.state.email + ', password: ' + this.state.password);
}
render() {
return(
<Login
onSigninSubmit={this.onSigninSubmit}
onEmailChange={this.onEmailChange}
email={this.state.email}
password={this.state.password}
onPasswordChahge={this.onPasswordChahge}
/>
)
}
}
export default WelcomePage;
Файл Login.js – построен на material-ui
import React from 'react';
import Paper from '@material-ui/core/Paper';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import Avatar from '@material-ui/core/Avatar';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import Link from '@material-ui/core/Link';
import Box from '@material-ui/core/Box';
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
import { makeStyles } from '@material-ui/core/styles';
import Copyright from './Copyright';
const useStyles = makeStyles(theme => ({
root: {
height: '100vh',
},
image: {
backgroundImage: 'url(https://source.unsplash.com/random)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
backgroundPosition: 'center',
}, paper: {
margin: theme.spacing(8, 4),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
const Login = ({onSigninSubmit, email, onEmailChange, password, onPasswordChahge}) => {
const classes = useStyles();
return (
<Grid container component="main" className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Заходите на сайт, всегда Вам рады!
</Typography>
<form className={classes.form} onSubmit={onSigninSubmit} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Электронная почта"
name="email"
autoComplete="email"
autoFocus
value={email}
onChange={onEmailChange}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Пароль"
type="password"
id="password"
autoComplete="current-password"
value={password}
onChange={onPasswordChahge}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Войти
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Забыли пароль?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
"Нет учетной записи? Регистрация"
</Link>
</Grid>
</Grid>
<Box mt={5}>
<Copyright />
</Box>
</form>
</div>
</Grid>
</Grid>
);
}
export default Login;
Получилось примерно так и всегда разная картинка