mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
First design of second factor page.
This commit is contained in:
parent
f5c653551a
commit
337f0df12a
|
@ -2,8 +2,8 @@ import React, { Component } from 'react';
|
|||
import './App.css';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
import { FirstFactor } from './first-factor';
|
||||
import { SecondFactor } from './second-factor';
|
||||
import { FirstFactor } from './pages/first-factor/first-factor';
|
||||
import { SecondFactor } from './pages/second-factor/second-factor';
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
|
||||
import logo from '../logo.svg';
|
||||
import styles from "./index.module.css"
|
||||
|
||||
interface State {
|
||||
rememberMe: boolean;
|
||||
}
|
||||
|
||||
export class FirstFactor extends Component<any, State> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = {
|
||||
rememberMe: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleRememberMe = () => {
|
||||
this.setState({
|
||||
rememberMe: !(this.state.rememberMe)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.mainContent}>
|
||||
<div className={styles.header}>
|
||||
<h1>Sign in</h1>
|
||||
</div>
|
||||
<div className={styles.frame}>
|
||||
<div className={styles.innerFrame}>
|
||||
<div className={styles.fields}>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={styles.input}
|
||||
id="username"
|
||||
label="Username">
|
||||
</TextField>
|
||||
</div>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={styles.input}
|
||||
id="password"
|
||||
label="Password"
|
||||
type="password">
|
||||
</TextField>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.controlArea}>
|
||||
<div className={styles.controls}>
|
||||
<div className={styles.rememberMe}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={this.state.rememberMe}
|
||||
onChange={this.toggleRememberMe}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Remember me"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.resetPassword}>
|
||||
<a href="/">Forgot password?</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={styles.button}>
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<img src={logo} alt="logo"></img>
|
||||
<div>Powered by <a href="#">Authelia</a></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
39
client-react/src/pages/first-factor/first-factor.module.css
Normal file
39
client-react/src/pages/first-factor/first-factor.module.css
Normal file
|
@ -0,0 +1,39 @@
|
|||
.main {
|
||||
padding: 2em 3em 2em 3em;
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.field .input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.controls .rememberMe {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.controls .resetPassword {
|
||||
padding: 12px 0px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.controls .resetPassword a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.buttons button {
|
||||
width: 100%;
|
||||
}
|
83
client-react/src/pages/first-factor/first-factor.tsx
Normal file
83
client-react/src/pages/first-factor/first-factor.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
|
||||
import FormTemplate from '../../templates/form-template';
|
||||
|
||||
import styles from "./first-factor.module.css"
|
||||
|
||||
interface State {
|
||||
rememberMe: boolean;
|
||||
}
|
||||
|
||||
export class FirstFactor extends Component<any, State> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = {
|
||||
rememberMe: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleRememberMe = () => {
|
||||
this.setState({
|
||||
rememberMe: !(this.state.rememberMe)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormTemplate title="Sign in">
|
||||
<div className={styles.main}>
|
||||
<div className={styles.fields}>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={styles.input}
|
||||
id="username"
|
||||
label="Username">
|
||||
</TextField>
|
||||
</div>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={styles.input}
|
||||
id="password"
|
||||
label="Password"
|
||||
type="password">
|
||||
</TextField>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.controlArea}>
|
||||
<div className={styles.controls}>
|
||||
<div className={styles.rememberMe}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={this.state.rememberMe}
|
||||
onChange={this.toggleRememberMe}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Remember me"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.resetPassword}>
|
||||
<a href="/">Forgot password?</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={styles.button}>
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormTemplate>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
.main {
|
||||
text-align: center;
|
||||
padding: 2em 3em 2em 3em;
|
||||
min-height: 350px;
|
||||
}
|
||||
|
||||
.authenticate {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.authenticate hr {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.authenticate .u2f img {
|
||||
width: 128px;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.authenticate .totpField {
|
||||
margin: 1em 0em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.register {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.register .buttons {
|
||||
margin: 2em 0em;
|
||||
}
|
||||
|
||||
.register .buttons button {
|
||||
margin: 0.8em 0em;
|
||||
width: 100%;
|
||||
}
|
103
client-react/src/pages/second-factor/second-factor.tsx
Normal file
103
client-react/src/pages/second-factor/second-factor.tsx
Normal file
|
@ -0,0 +1,103 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
|
||||
import BottomNavigation from '@material-ui/core/BottomNavigation';
|
||||
import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';
|
||||
import RestoreIcon from '@material-ui/core/Icon';
|
||||
import FavoriteIcon from '@material-ui/core/Icon';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
import FormTemplate from '../../templates/form-template';
|
||||
|
||||
import styles from './second-factor.module.css';
|
||||
import pendrive from '../../pendrive.png'
|
||||
|
||||
interface State {
|
||||
mode: number;
|
||||
}
|
||||
|
||||
export class SecondFactor extends Component<any, State> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
mode: 0
|
||||
}
|
||||
}
|
||||
|
||||
onMenuChanged(event: any, value: number) {
|
||||
this.setState({mode: value});
|
||||
}
|
||||
|
||||
renderInner() {
|
||||
const registerDevice = (
|
||||
<div className={styles.register}>
|
||||
<div>Register a new device</div>
|
||||
<div className={styles.buttons}>
|
||||
<Button variant="contained" color="primary">
|
||||
Security key
|
||||
</Button>
|
||||
<Button variant="contained" color="primary">
|
||||
One-time password
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const authenticate = (
|
||||
<div className={styles.authenticate}>
|
||||
<div className={styles.u2f}>
|
||||
Touch your security key
|
||||
<div>
|
||||
<img src={pendrive} alt="usb key"/>
|
||||
</div>
|
||||
</div>
|
||||
<table style={{width: '60%', margin: '2em auto'}}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={{width: '40%'}}><hr/></td>
|
||||
<td style={{width: '20%'}}>or</td>
|
||||
<td style={{width: '40%'}}><hr/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div className={styles.totp}>
|
||||
Provide a one-time password
|
||||
<div className={styles.totpField}>
|
||||
<TextField
|
||||
id="otp"
|
||||
variant="outlined"
|
||||
label="Password">
|
||||
</TextField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (this.state.mode == 0) {
|
||||
return authenticate;
|
||||
}
|
||||
else if (this.state.mode == 1) {
|
||||
return registerDevice;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormTemplate title="2-Factor">
|
||||
<div className={styles.main}>
|
||||
{this.renderInner()}
|
||||
</div>
|
||||
<BottomNavigation
|
||||
value={this.state.mode}
|
||||
onChange={this.onMenuChanged.bind(this)}
|
||||
showLabels
|
||||
className={styles.menu}
|
||||
>
|
||||
<BottomNavigationAction label="Authenticate" icon={<RestoreIcon />} />
|
||||
<BottomNavigationAction label="Register" icon={<FavoriteIcon />} />
|
||||
</BottomNavigation>
|
||||
</FormTemplate>
|
||||
)
|
||||
}
|
||||
}
|
BIN
client-react/src/pendrive.png
Normal file
BIN
client-react/src/pendrive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
|
@ -1,7 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
export class SecondFactor extends Component {
|
||||
render() {
|
||||
return <div>second factor</div>
|
||||
}
|
||||
}
|
|
@ -12,55 +12,18 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
/* MAIN */
|
||||
/* FRAME */
|
||||
|
||||
.frame {
|
||||
box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 0.5em 3em 3em 3em;
|
||||
}
|
||||
|
||||
.innerFrame {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
margin: 20px 0px;
|
||||
}
|
||||
|
||||
.field .input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.controls .rememberMe {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.controls .resetPassword {
|
||||
padding: 12px 0px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.controls .resetPassword a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.buttons button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* FOOTER */
|
||||
|
||||
.footer {
|
30
client-react/src/templates/form-template.tsx
Normal file
30
client-react/src/templates/form-template.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import logo from '../logo.svg';
|
||||
import styles from "./form-template.module.css"
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export default class FormTemplate extends Component<Props> {
|
||||
render() {
|
||||
const children = this.props.children;
|
||||
return (
|
||||
<div className={styles.mainContent}>
|
||||
<div className={styles.header}>
|
||||
<h1>{this.props.title}</h1>
|
||||
</div>
|
||||
<div className={styles.frame}>
|
||||
<div className={styles.innerFrame}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<img src={logo} alt="logo"></img>
|
||||
<div>Powered by <a href="#">Authelia</a></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user