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 './App.css';
|
||||||
|
|
||||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||||
import { FirstFactor } from './first-factor';
|
import { FirstFactor } from './pages/first-factor/first-factor';
|
||||||
import { SecondFactor } from './second-factor';
|
import { SecondFactor } from './pages/second-factor/second-factor';
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
render() {
|
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;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAIN */
|
/* FRAME */
|
||||||
|
|
||||||
.frame {
|
.frame {
|
||||||
box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px;
|
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;
|
background-color: white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 0.5em 3em 3em 3em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.innerFrame {
|
.innerFrame {
|
||||||
width: 100%;
|
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 */
|
||||||
|
|
||||||
.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