Login screen looking good

This commit is contained in:
John Lyon-Smith
2018-02-26 16:38:18 -08:00
parent 93c1ecb919
commit 5faa4600f5
18 changed files with 120 additions and 135 deletions

View File

@@ -25,7 +25,8 @@ export class App extends React.Component {
</Row> </Row>
</Box> </Box>
</Column.Item> </Column.Item>
<Column.Item grow> <Column.Item grow />
<Column.Item>
<Router basename='/'> <Router basename='/'>
<Switch> <Switch>
<Route path='/login' component={Login} /> <Route path='/login' component={Login} />
@@ -40,9 +41,10 @@ export class App extends React.Component {
</Switch> </Switch>
</Router> </Router>
</Column.Item> </Column.Item>
<Column.Item grow />
<Column.Item> <Column.Item>
<Box color='#FAFAFA' borderTop='1px solid #B2B2B2'> <Box color='#FAFAFA' borderTop='1px solid #B2B2B2'>
<Text tone='dimmed' margin={10}>{versionInfo.fullVersion} {versionInfo.copyright}</Text> <Text tone='dimmed' margin={10}>{'v' + versionInfo.version} {versionInfo.copyright}</Text>
</Box> </Box>
</Column.Item> </Column.Item>
</Column> </Column>

View File

@@ -4,8 +4,9 @@ import { regExpPattern } from 'regexp-pattern'
import { api } from '../helpers' import { api } from '../helpers'
import { Validator, ValidatedInput, ValidatedCheckbox, ValidatedButton } from '../Validated' import { Validator, ValidatedInput, ValidatedCheckbox, ValidatedButton } from '../Validated'
import { WaitDialog, MessageDialog } from '../Dialog' import { WaitDialog, MessageDialog } from '../Dialog'
import { Image, Link, Text, Column } from 'ui' import { Image, Link, Text, Row, Column } from 'ui'
import headerLogo from 'images/deighton.png' import headerLogo from 'images/deighton.png'
import { versionInfo } from '../version'
export class Login extends React.Component { export class Login extends React.Component {
static propTypes = { static propTypes = {
@@ -87,41 +88,61 @@ export class Login extends React.Component {
} }
render() { render() {
return null && ( return (
<div> <Row minHeight='100%'>
<Row.Item grow>&nbsp;</Row.Item>
<Row.Item width='450px'>
<form onSubmit={this.handleSubmit}> <form onSubmit={this.handleSubmit}>
<Column> <Column minHeight='100%'>
<Column.Item> <Column.Item>
<Image source={headerLogo} width={279} height={73} /> <Row>
<Row.Item grow />
<Row.Item>
<Image source={headerLogo} width={250} />
</Row.Item>
<Row.Item grow />
</Row>
</Column.Item> </Column.Item>
<Column.Item> <Column.Item>
<ValidatedInput label='Email' name='email' <ValidatedInput label='Email' name='email'
placeholder='example@xyz.com' validator={this.state.validator} placeholder='example@xyz.com' validator={this.state.validator}
message='Enter the email address associated with your account.' width={16} /> message='Enter the email address associated with your account.' />
</Column.Item> </Column.Item>
<Column.Item> <Column.Item>
<ValidatedInput password label='Password' name='password' <ValidatedInput password label='Password' name='password'
validator={this.state.validator} message='Enter your password.' width={16} /> validator={this.state.validator} message='Enter your password.' />
</Column.Item> </Column.Item>
<Column.Item> <Column.Item>
<Row>
<Row.Item>
<Link to='/forgot-password'>Forgot your password?</Link> <Link to='/forgot-password'>Forgot your password?</Link>
</Column.Item> </Row.Item>
<Column.Item> <Row.Item grow />
<Row.Item>
<ValidatedCheckbox label='Remember Me' <ValidatedCheckbox label='Remember Me'
name='rememberMe' onChange={this.handleChange} validator={this.state.validator} name='rememberMe' onChange={this.handleChange} validator={this.state.validator} />
message='Should we keep you logged in on this computer?' className='login-checkbox' /> </Row.Item>
</Row>
</Column.Item> </Column.Item>
<Column.Item> <Column.Item>
<ValidatedButton className='submit' name='submit' content='Login' <Row>
submit validator={this.state.validator} /> <Row.Item grow />
<Row.Item>
<br />
<ValidatedButton name='submit' content='Login' height={60} submit validator={this.state.validator} />
</Row.Item>
</Row>
</Column.Item> </Column.Item>
<Column.Item> <Column.Item>
<Text> <Text>
Please contact <Link to='mailto:support@jamoki.com'>support@jamoki.com</Link> to request login credentials. <br />
Please contact <Link to={`mailto:${versionInfo.supportEmail}`}>{versionInfo.supportEmail}</Link> to request login credentials.
</Text> </Text>
</Column.Item> </Column.Item>
</Column> </Column>
</form> </form>
</Row.Item>
<Row.Item grow>&nbsp;</Row.Item>
<WaitDialog active={this.state.waitDialog} message='Logging In' /> <WaitDialog active={this.state.waitDialog} message='Logging In' />
@@ -129,7 +150,7 @@ export class Login extends React.Component {
title={this.state.messageDialog ? this.state.messageDialog.title : ''} title={this.state.messageDialog ? this.state.messageDialog.title : ''}
message={this.state.messageDialog ? this.state.messageDialog.message : ''} message={this.state.messageDialog ? this.state.messageDialog.message : ''}
onDismiss={this.handleMessageDialogDismiss} /> onDismiss={this.handleMessageDialogDismiss} />
</div> </Row>
) )
} }
} }

View File

@@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import './UserFormPlaceholder.scss'
export const UserFormPlaceholder = () => ( export const UserFormPlaceholder = () => (
<div className='user-form-placeholder'> <div className='user-form-placeholder'>

View File

@@ -1,7 +0,0 @@
.user-form-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}

View File

@@ -1,7 +1,6 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Label, Button, Icon } from 'ui' import { Text, Button, Icon } from 'ui'
import './ValidatedEmailIcon.scss'
// This is a validated component with a value that cannot change itself and is specialized // This is a validated component with a value that cannot change itself and is specialized
@@ -28,15 +27,14 @@ export class ValidatedEmailIcon extends React.Component {
if (this.state.value) { if (this.state.value) {
return ( return (
<div width={this.props.width}> <div width={this.props.width}>
<Label>&nbsp; <Text>&nbsp;</Text>
<Icon name='mail' color='green' size='big' className='mail-validated-icon' /> <Icon name='mail' color='green' size='big' className='mail-validated-icon' />
</Label>
</div> </div>
) )
} else { } else {
return ( return (
<div width={this.props.width}> <div width={this.props.width}>
<Label>&nbsp;</Label> <Text>&nbsp;</Text>
<Button fluid icon='mail outline' color='red' labelPosition='left' <Button fluid icon='mail outline' color='red' labelPosition='left'
content='Resend Email' onClick={this.props.onClick} disabled={this.state.disabled} /> content='Resend Email' onClick={this.props.onClick} disabled={this.state.disabled} />
</div> </div>

View File

@@ -1,3 +0,0 @@
.mail-validated-icon {
padding-top: 4px;
}

View File

@@ -10,10 +10,8 @@ export class ValidatedButton extends React.Component {
size: PropTypes.string, size: PropTypes.string,
content: PropTypes.string, content: PropTypes.string,
validator: PropTypes.object.isRequired, validator: PropTypes.object.isRequired,
primary: PropTypes.bool,
submit: PropTypes.bool, submit: PropTypes.bool,
color: PropTypes.string, color: PropTypes.string,
floated: PropTypes.string,
onClick: PropTypes.func onClick: PropTypes.func
} }
@@ -48,10 +46,11 @@ export class ValidatedButton extends React.Component {
return ( return (
<div width={this.props.width} disabled={this.state.disabled}> <div width={this.props.width} disabled={this.state.disabled}>
<label>{this.props.label}</label> <label>{this.props.label}</label>
<Button color={this.props.color} primary={this.props.primary} <Button
type={this.props.submit ? 'submit' : 'button'} onClick={this.props.onClick} color={this.props.color}
size={this.props.size} name={this.props.name} submit={this.props.submit}
floated={this.props.floated}> onClick={this.props.onClick}
size={this.props.size} name={this.props.name}>
{this.props.content} {this.props.content}
</Button> </Button>
</div> </div>

View File

@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Checkbox, Label } from 'ui' import { Checkbox } from 'ui'
// This is an example of a validated component with a value that can change itself, that cannot ever be invalid. // This is an example of a validated component with a value that can change itself, that cannot ever be invalid.
@@ -8,9 +8,7 @@ export class ValidatedCheckbox extends React.Component {
static propTypes = { static propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
label: PropTypes.string, label: PropTypes.string,
width: PropTypes.number,
validator: PropTypes.object.isRequired, validator: PropTypes.object.isRequired,
className: PropTypes.string
} }
constructor(props) { constructor(props) {
@@ -37,10 +35,7 @@ export class ValidatedCheckbox extends React.Component {
render() { render() {
return ( return (
<Label width={this.props.width} disabled={this.state.disabled} className={this.props.className}> <Checkbox value={!!this.state.value} name={this.props.name} label={this.props.label} />
<Checkbox value={!!this.state.value} name={this.props.name} />
{this.props.label}
</Label>
) )
} }
} }

View File

@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Input, Label, Text } from 'ui' import { Input, Text } from 'ui'
// This is an example of a validated component with a value that changes itself // This is an example of a validated component with a value that changes itself
@@ -9,7 +9,6 @@ export class ValidatedInput extends React.Component {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
message: PropTypes.string, message: PropTypes.string,
label: PropTypes.string, label: PropTypes.string,
width: PropTypes.number,
validator: PropTypes.object.isRequired, validator: PropTypes.object.isRequired,
password: PropTypes.bool, password: PropTypes.bool,
placeholder: PropTypes.string placeholder: PropTypes.string
@@ -39,16 +38,16 @@ export class ValidatedInput extends React.Component {
render() { render() {
return ( return (
<div width={this.props.width} disabled={this.state.disabled}> <div style={{ width: '100%' }} disabled={this.state.disabled}>
<Label>{this.props.label}<br /> <Text>{this.props.label}</Text>
<br />
<Input value={this.state.value} <Input value={this.state.value}
password={this.props.password} password={this.props.password}
name={this.props.name} name={this.props.name}
onChange={this.handleChange} onChange={this.handleChange}
placeholder={this.props.placeholder} /> placeholder={this.props.placeholder} />
</Label>
<br /> <br />
<Text size='small'>{this.props.message}</Text> <Text size='small' tone='alert'>{this.props.message}</Text>
</div> </div>
) )
} }

View File

@@ -4,7 +4,7 @@ import React, { Component } from 'react'
class Box extends Component { class Box extends Component {
static propTypes = { static propTypes = {
borderTop: PropTypes.number, borderTop: PropTypes.string,
borderBottom: PropTypes.string, borderBottom: PropTypes.string,
borderRight: PropTypes.string, borderRight: PropTypes.string,
borderLeft: PropTypes.string, borderLeft: PropTypes.string,

View File

@@ -5,13 +5,15 @@ import style from './Button.style'
class Button extends Component { class Button extends Component {
static propTypes = { static propTypes = {
submit: PropTypes.string, submit: PropTypes.bool,
children: PropTypes.node children: PropTypes.node,
width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])
} }
render() { render() {
const { children, submit, width } = this.props
return ( return (
<button type={this.props.submit ? 'submit' : 'button'} style={style.base}>{this.props.children}</button> <button type={submit ? 'submit' : 'button'} style={[style.base, { width }]}>{children}</button>
) )
} }
} }

View File

@@ -5,15 +5,14 @@ export default {
borderRadius: '10px', borderRadius: '10px',
fontFamily: fontInfo.family, fontFamily: fontInfo.family,
color: '#FFFFFF', color: '#FFFFFF',
fontSize: '20px', fontSize: fontInfo.size['large'],
background: colorInfo.buttonBackgroundHover, background: colorInfo.buttonBackgroundHover,
padding: '10px 20px 10px 20px', verticalAlign: 'middle',
textDecoration: 'none', padding: '8px 15px 8px 15px',
outline: 'none', outline: 'none',
':hover': { ':hover': {
background: colorInfo.buttonBackground, background: colorInfo.buttonBackground,
textDecoration: 'none'
} }
} }
} }

View File

@@ -3,10 +3,12 @@ import PropTypes from 'prop-types'
import React, { Component } from 'react' import React, { Component } from 'react'
import style from './Checkbox.style' import style from './Checkbox.style'
import { reactAutoBind } from 'auto-bind2' import { reactAutoBind } from 'auto-bind2'
import { fontInfo } from './style'
class Checkbox extends Component { class Checkbox extends Component {
static propTypes = { static propTypes = {
value: PropTypes.bool value: PropTypes.bool,
label: PropTypes.string,
} }
constructor(props) { constructor(props) {
@@ -23,9 +25,18 @@ class Checkbox extends Component {
render() { render() {
return ( return (
<div>
<div style={[style.checkbox, !this.state.checked && style.checkboxUnchecked]} onClick={this.onClick}> <div style={[style.checkbox, !this.state.checked && style.checkboxUnchecked]} onClick={this.onClick}>
<div style={[style.checkmark, !this.state.checked && style.checkmarkUnchecked]} /> <div style={[style.checkmark, !this.state.checked && style.checkmarkUnchecked]} />
</div> </div>
<span style={{
verticalAlign: 'top',
fontSize: fontInfo.size['medium'],
fontFamily: fontInfo.family,
color: fontInfo.color['normal'],
marginLeft: 10
}}>{this.props.label}</span>
</div>
) )
} }
} }

View File

@@ -2,13 +2,12 @@ import { colorInfo } from './style'
export default { export default {
checkbox: { checkbox: {
display: 'inline-block',
cursor: 'pointer', cursor: 'pointer',
position: 'relative', position: 'relative',
backgroundColor: colorInfo.buttonBackground, backgroundColor: colorInfo.buttonBackground,
top: 0,
left: 0,
height: 25, height: 25,
width: 25 width: 25,
}, },
checkboxUnchecked: { checkboxUnchecked: {
@@ -20,7 +19,6 @@ export default {
checkmark: { checkmark: {
position: 'absolute', position: 'absolute',
display: 'block',
content: '', content: '',
left: 8, left: 8,
top: 4, top: 4,
@@ -34,5 +32,5 @@ export default {
checkmarkUnchecked: { checkmarkUnchecked: {
display: 'none' display: 'none'
} },
} }

View File

@@ -6,12 +6,17 @@ import style from './Input.style'
class Input extends Component { class Input extends Component {
static propTypes = { static propTypes = {
password: PropTypes.bool, password: PropTypes.bool,
children: PropTypes.node children: PropTypes.node,
width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])
} }
render() { render() {
let { children, width } = this.props
width = width || '100%'
return ( return (
<input type={this.props.password ? 'password' : 'text'} style={style.base}>{this.props.children}</input> <input type={this.props.password ? 'password' : 'text'} style={[ { width }, style.base ]}>{children}</input>
) )
} }
} }

View File

@@ -1,33 +0,0 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { fontInfo } from './style'
class Label extends Component {
static propTypes = {
size: PropTypes.string,
color: PropTypes.string,
margin: PropTypes.number,
children: PropTypes.node
}
static defaultProps = {
size: 'medium',
color: 'normal',
margin: 0
}
render() {
return (
<label style={{
display: 'inline-block',
fontSize: fontInfo.size[this.props.size],
color: fontInfo.color[this.props.color],
fontFamily: fontInfo.family,
margin: this.props.margin
}}>{this.props.children}</label>
)
}
}
export default Radium(Label)

View File

@@ -5,7 +5,7 @@ import PropTypes from 'prop-types'
class Row extends Component { class Row extends Component {
static propTypes = { static propTypes = {
children: PropTypes.node, children: PropTypes.node,
minWidth: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]).isRequired minWidth: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])
} }
render() { render() {
@@ -21,15 +21,16 @@ Row.Item = Radium(class RowLayoutItem extends Component {
static propTypes = { static propTypes = {
children: PropTypes.node, children: PropTypes.node,
minWidth: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]), minWidth: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
grow: PropTypes.bool, grow: PropTypes.bool,
} }
render() { render() {
const { children, grow, minWidth } = this.props const { children, grow, width, minWidth } = this.props
const flexGrow = grow ? 1 : null const flexGrow = grow ? 1 : null
return ( return (
<div style={{ minWidth, flexGrow }}>{children}</div> <div style={{ width, minWidth, flexGrow }}>{children}</div>
) )
} }
}) })

View File

@@ -5,7 +5,6 @@ export { default as Input } from './Input'
export { default as Image } from './Image' export { default as Image } from './Image'
export { default as Text } from './Text' export { default as Text } from './Text'
export { default as Link } from './Link' export { default as Link } from './Link'
export { default as Label } from './Label'
export { default as Icon } from './Icon' export { default as Icon } from './Icon'
export { default as List } from './List' export { default as List } from './List'
export { default as Dropdown } from './Dropdown' export { default as Dropdown } from './Dropdown'