merge intro-screen

This commit is contained in:
NikolaBorislavovHristov 2019-01-30 11:50:03 +02:00
commit 4d88542e2f
15 changed files with 279 additions and 193 deletions

View file

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 207 KiB

View file

@ -48,6 +48,7 @@
--poster-shape-ratio: 1.464;
--window-min-width: 800px;
--window-min-height: 600px;
--focusable-border-size: 2px;
}
* {
@ -59,6 +60,7 @@
user-select: none;
text-decoration: none;
outline: none;
appearance: none;
}
html, body, :global(#app) {
@ -77,6 +79,10 @@ html, body, :global(#app) {
height: 100%;
}
input {
user-select: text;
}
::-webkit-scrollbar {
width: var(--scroll-bar-width);
}

View file

@ -16,8 +16,8 @@
opacity: 0;
height: 0;
width: 0;
top: -99999999px;
left: -99999999px;
top: 0;
left: 0;
}
&:global(.checked) {

View file

@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { withFocusable } from 'stremio-common';
class TextInput extends PureComponent {
class Input extends PureComponent {
render() {
const { forwardedRef, focusable, ...props } = this.props;
return (
@ -15,21 +15,21 @@ class TextInput extends PureComponent {
}
}
TextInput.propTypes = {
Input.propTypes = {
focusable: PropTypes.bool.isRequired
};
TextInput.defaultProps = {
Input.defaultProps = {
focusable: false
};
const TextInputWithFocusable = withFocusable(TextInput);
const InputWithFocusable = withFocusable(Input);
TextInputWithFocusable.displayName = 'TextInputWithFocusable';
InputWithFocusable.displayName = 'InputWithFocusable';
const TextInputWithForwardedRef = React.forwardRef((props, ref) => (
<TextInputWithFocusable {...props} forwardedRef={ref} />
const InputWithForwardedRef = React.forwardRef((props, ref) => (
<InputWithFocusable {...props} forwardedRef={ref} />
));
TextInputWithForwardedRef.displayName = 'TextInputWithForwardedRef';
InputWithForwardedRef.displayName = 'InputWithForwardedRef';
export default TextInputWithForwardedRef;
export default InputWithForwardedRef;

View file

@ -0,0 +1,3 @@
import Input from './Input';
export default Input;

35
src/common/Link/Link.js Normal file
View file

@ -0,0 +1,35 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { withFocusable } from 'stremio-common';
class Link extends PureComponent {
render() {
const { forwardedRef, focusable, ...props } = this.props;
return (
<a
{...props}
ref={forwardedRef}
tabIndex={focusable ? 0 : -1}
/>
);
}
}
Link.propTypes = {
focusable: PropTypes.bool.isRequired
};
Link.defaultProps = {
focusable: false
};
const LinkWithFocusable = withFocusable(Link);
LinkWithFocusable.displayName = 'LinkWithFocusable';
const LinkWithForwardedRef = React.forwardRef((props, ref) => (
<LinkWithFocusable {...props} forwardedRef={ref} />
));
LinkWithForwardedRef.displayName = 'LinkWithForwardedRef';
export default LinkWithForwardedRef;

3
src/common/Link/index.js Normal file
View file

@ -0,0 +1,3 @@
import Link from './Link';
export default Link;

View file

@ -1,3 +0,0 @@
import TextInput from './TextInput';
export default TextInput;

View file

@ -2,7 +2,8 @@ import Slider from './Slider';
import { FocusableProvider, withFocusable } from './Focusable';
import Button from './Button';
import Checkbox from './Checkbox';
import TextInput from './TextInput';
import Input from './Input';
import Link from './Link';
import { Modal, ModalsContainerContext, withModalsContainer } from './Modal';
import Popup from './Popup';
import Router from './Router';
@ -13,7 +14,8 @@ import UserPanel from './UserPanel';
export {
Checkbox,
TextInput,
Input,
Link,
Popup,
NavBar,
ModalsContainerContext,

View file

@ -1,3 +0,0 @@
import CheckboxLabel from './CheckboxLabel';
export default CheckboxLabel;

View file

@ -4,8 +4,8 @@ import classnames from 'classnames';
import { Checkbox } from 'stremio-common';
import styles from './styles';
const CheckboxLabel = React.forwardRef(({ className, label, link, href, checked, onClick }, ref) => (
<label className={classnames(styles['checkbox-label-container'], className)}>
const ConsentCheckbox = React.forwardRef(({ className, label, link, href, checked, onClick }, ref) => (
<label className={classnames(styles['consent-checkbox-container'], className)}>
<Checkbox ref={ref} className={styles['checkbox']} checked={checked} onClick={onClick} />
<div className={styles['label']}>
{label}
@ -14,9 +14,9 @@ const CheckboxLabel = React.forwardRef(({ className, label, link, href, checked,
</label>
));
CheckboxLabel.displayName = 'CheckboxLabel';
ConsentCheckbox.displayName = 'ConsentCheckbox';
CheckboxLabel.propTypes = {
ConsentCheckbox.propTypes = {
className: PropTypes.string,
onClick: PropTypes.func,
label: PropTypes.string,
@ -25,4 +25,4 @@ CheckboxLabel.propTypes = {
checked: PropTypes.bool
};
export default CheckboxLabel;
export default ConsentCheckbox;

View file

@ -0,0 +1,3 @@
import ConsentCheckbox from './ConsentCheckbox';
export default ConsentCheckbox;

View file

@ -1,4 +1,4 @@
.checkbox-label-container {
.consent-checkbox-container {
display: flex;
flex-direction: row;
align-items: center;

View file

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import React, { Component, Fragment } from 'react';
import Icon from 'stremio-icons/dom';
import { Button, TextInput } from 'stremio-common';
import CheckboxLabel from './CheckboxLabel';
import { Button, Input, Link } from 'stremio-common';
import ConsentCheckbox from './ConsentCheckbox';
import styles from './styles';
const FORMS = {
@ -19,9 +19,10 @@ class Intro extends Component {
this.termsRef = React.createRef();
this.privacyPolicyRef = React.createRef();
this.marketingRef = React.createRef();
this.errorRef = React.createRef();
this.state = {
selectedForm: FORMS.SIGN_UP,
selectedForm: FORMS.LOGIN,
termsAccepted: false,
privacyPolicyAccepted: false,
marketingAccepted: false,
@ -33,6 +34,7 @@ class Intro extends Component {
}
changeSelectedForm = (event) => {
event.currentTarget.blur();
this.setState({
selectedForm: event.currentTarget.dataset.option,
termsAccepted: false,
@ -86,6 +88,16 @@ class Intro extends Component {
nextState.error !== this.state.error;
}
componentDidUpdate(prevProps, prevState) {
if (prevState.error !== this.state.error && this.state.error.length > 0) {
this.errorRef.current.scrollIntoView();
}
if (prevState.selectedForm !== this.state.selectedForm) {
this.emailRef.current.focus();
}
}
loginOnSubmit = (event) => {
event.preventDefault();
if (this.state.email.length < 8) {
@ -97,6 +109,8 @@ class Intro extends Component {
if (this.state.password.length === 0) {
this.setState({ error: 'Invalid password' });
} else {
this.setState({ error: '' });
}
}
}
@ -137,6 +151,7 @@ class Intro extends Component {
if (this.privacyPolicyRef.current === document.activeElement) {
this.marketingRef.current.focus();
}
this.setState({ error: '' });
}
}
@ -145,58 +160,11 @@ class Intro extends Component {
}
}
validateGuestLogin = (event) => {
guestLoginOnSubmit = () => {
if (!this.state.termsAccepted) {
event.preventDefault();
this.setState({ error: 'You must accept the Terms of Service' });
}
}
renderSignUpForm = () => {
return (
<form className={styles['form-container']} onSubmit={this.signUpOnSubmit}>
<TextInput ref={this.emailRef} className={styles['email']} type={'text'} placeholder={'Email'} value={this.state.email} onChange={this.emailOnChange} />
<input ref={this.passwordRef} className={styles['password']} type={'password'} placeholder={'Password'} value={this.state.password} onChange={this.passwordOnChange} />
<input ref={this.confirmPasswordRef} className={styles['password']} type={'password'} placeholder={'Confirm Password'} value={this.state.confirmPassword} onChange={this.confirmPasswordOnChange} />
<CheckboxLabel ref={this.termsRef} className={styles['checkbox-label']} label={'I have read and agree with the Stremio'} link={'Terms and conditions'} href={'https://www.stremio.com/tos'} checked={this.state.termsAccepted} onClick={this.toggleTerms} />
<CheckboxLabel ref={this.privacyPolicyRef} className={styles['checkbox-label']} label={'I have read and agree with the Stremio'} link={'Privacy Policy'} href={'https://www.stremio.com/privacy'} checked={this.state.privacyPolicyAccepted} onClick={this.togglePrivacyPolicy} />
<CheckboxLabel ref={this.marketingRef} className={styles['checkbox-label']} label={'I agree to receive marketing communications from Stremio'} checked={this.state.marketingAccepted} onClick={this.toggleMarketing} />
{
this.state.error.length > 0 ?
<div className={styles['error']}>{this.state.error}</div>
:
null
}
<input className={styles['submit-button']} type={'submit'} value={'SING UP'} />
</form>
);
}
renderLoginForm = () => {
return (
<form className={styles['form-container']} onSubmit={this.loginOnSubmit}>
<input ref={this.emailRef} className={styles['email']} type={'text'} placeholder={'Email'} value={this.state.email} onChange={this.emailOnChange} />
<input ref={this.passwordRef} className={styles['password']} type={'password'} placeholder={'Password'} value={this.state.password} onChange={this.passwordOnChange} />
<a className={styles['forgot-password']} href={'https://www.strem.io/reset-password/'} target={'_blank'}>Forgot password?</a>
{
this.state.error.length > 0 ?
<div className={styles['error']}>{this.state.error}</div>
:
null
}
<input className={styles['submit-button']} type={'submit'} value={'LOG IN'} />
</form>
);
}
renderSelectedMenu = () => {
switch (this.state.selectedForm) {
case FORMS.SIGN_UP:
return this.renderSignUpForm();
case FORMS.LOGIN:
return this.renderLoginForm();
default:
return null;
} else {
this.setState({ error: '' });
}
}
@ -204,20 +172,43 @@ class Intro extends Component {
return (
<div className={styles['intro-container']}>
<div className={styles['overlay']} />
<div className={styles['intro']}>
<Button className={styles['facebook-button']}>
<Icon className={styles['icon']} icon={'ic_facebook'} />
<div className={styles['label']}>Login with Facebook</div>
</Button>
<div className={styles['facebook-subtext']}>We won't post anything on your behalf</div>
{this.renderSelectedMenu()}
<div className={styles['option']} data-option={this.state.selectedForm === FORMS.SIGN_UP ? FORMS.LOGIN : FORMS.SIGN_UP} onClick={this.changeSelectedForm}>{this.state.selectedForm === FORMS.SIGN_UP ? 'LOG IN' : 'SING UP WITH EMAIL'}</div>
{
this.state.selectedForm === FORMS.SIGN_UP ?
<a className={styles['option']} href={'#/'} onClick={this.validateGuestLogin}>GUEST LOGIN</a>
:
null
}
<div className={styles['scroll-content']}>
<div className={styles['intro']}>
<Button className={styles['facebook-button']}>
<Icon className={styles['icon']} icon={'ic_facebook'} />
<div className={styles['label']}>Login with Facebook</div>
</Button>
<div className={styles['facebook-statement']}>We won't post anything on your behalf</div>
<form className={styles['form-container']} onSubmit={this.state.selectedForm === FORMS.LOGIN ? this.loginOnSubmit : this.signUpOnSubmit}>
<Input ref={this.emailRef} className={styles['text-input']} type={'text'} placeholder={'Email'} value={this.state.email} onChange={this.emailOnChange} />
<Input ref={this.passwordRef} className={styles['text-input']} type={'password'} placeholder={'Password'} value={this.state.password} onChange={this.passwordOnChange} />
{
this.state.selectedForm === FORMS.LOGIN ?
<Link className={styles['forgot-password']} href={'https://www.strem.io/reset-password/'} target={'_blank'}>Forgot password?</Link>
:
<Fragment>
<Input ref={this.confirmPasswordRef} className={styles['text-input']} type={'password'} placeholder={'Confirm Password'} value={this.state.confirmPassword} onChange={this.confirmPasswordOnChange} />
<ConsentCheckbox ref={this.termsRef} className={styles['consent-checkbox']} label={'I have read and agree with the Stremio'} link={'Terms and conditions'} href={'https://www.stremio.com/tos'} checked={this.state.termsAccepted} onClick={this.toggleTerms} />
<ConsentCheckbox ref={this.privacyPolicyRef} className={styles['consent-checkbox']} label={'I have read and agree with the Stremio'} link={'Privacy Policy'} href={'https://www.stremio.com/privacy'} checked={this.state.privacyPolicyAccepted} onClick={this.togglePrivacyPolicy} />
<ConsentCheckbox ref={this.marketingRef} className={styles['consent-checkbox']} label={'I agree to receive marketing communications from Stremio'} checked={this.state.marketingAccepted} onClick={this.toggleMarketing} />
</Fragment>
}
{
this.state.error.length > 0 ?
<div ref={this.errorRef} className={styles['error']}>{this.state.error}</div>
:
null
}
<Input className={styles['submit-button']} type={'submit'} value={this.state.selectedForm === FORMS.LOGIN ? 'LOG IN' : 'SING UP'} />
</form>
<Button className={styles['switch-form-button']} data-option={this.state.selectedForm === FORMS.SIGN_UP ? FORMS.LOGIN : FORMS.SIGN_UP} onClick={this.changeSelectedForm}>{this.state.selectedForm === FORMS.SIGN_UP ? 'LOG IN' : 'SING UP WITH EMAIL'}</Button>
{
this.state.selectedForm === FORMS.SIGN_UP ?
<Button className={styles['guest-login-button']} onClick={this.guestLoginOnSubmit}>GUEST LOGIN</Button>
:
null
}
</div>
</div>
</div>
);

View file

@ -9,7 +9,7 @@
z-index: 0;
width: 100%;
height: 100%;
background-image: url('/images/home-testimonials.jpg');
background-image: url('/images/login_background.jpg');
background-size: cover;
background-attachment: fixed;
@ -23,123 +23,172 @@
background-color: var(--color-backgrounddark80);
}
.intro {
.scroll-content {
display: flex;
flex-direction: row;
position: absolute;
z-index: 1;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow-y: auto;
overflow-x: hidden;
.facebook-button {
.intro {
margin: auto;
padding: calc(var(--login-form-width) * 0.2) 0;
width: var(--login-form-width);
height: calc(var(--login-form-width) * 0.25);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: calc(var(--spacing) * 1.25) 0;
background: var(--color-secondarydark);
.icon {
height: 100%;
margin-right: var(--spacing);
fill: var(--color-surfacelighter);
}
.label {
font-size: 1.1em;
color: var(--color-surfacelighter);
}
}
.facebook-subtext {
margin: calc(var(--spacing) * 0.5) 0 calc(var(--spacing) * 4) 0;
color: var(--color-surface);
}
.form-container {
width: var(--login-form-width);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.email {
width: 100%;
margin-bottom: var(--spacing);
padding: 0.5em 0;
border-bottom: 1px solid var(--color-surface);
font-size: 1.1em;
color: var(--color-surfacelighter);
background: none;
&::placeholder {
color: var(--color-surfacelight);
}
}
.password {
width: 100%;
margin-bottom: var(--spacing);
padding: 0.5em 0;
border-bottom: 1px solid var(--color-surface);
font-size: 1.1em;
color: var(--color-surfacelighter);
background: none;
&::placeholder {
color: var(--color-surfacelight);
}
}
.checkbox-label {
width: 100%;
margin-bottom: var(--spacing);
}
.forgot-password {
.facebook-button {
width: var(--login-form-width);
height: calc(var(--login-form-width) * 0.25);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border: var(--focusable-border-size) solid transparent;
background: var(--color-secondarydark);
cursor: pointer;
margin-bottom: var(--spacing);
color: var(--color-surfacelight);
&:hover {
.icon {
height: 1.7em;
margin-right: var(--spacing);
fill: var(--color-surfacelighter);
}
.label {
font-size: 1.1em;
color: var(--color-surfacelighter);
}
}
.error {
margin-bottom: var(--spacing);
text-align: center;
color: var(--color-signal1);
}
&:focus {
border-color: var(--color-surfacelighter);
}
.submit-button {
width: 100%;
cursor: pointer;
padding: calc(var(--spacing) * 1.1);
font-size: 1.1em;
font-weight: 600;
color: var(--color-surfacelighter);
background-color: var(--color-primarydark);
&:hover, &:focus {
background-color: var(--color-primary);
&:hover {
border-color: transparent;
}
}
}
.option {
margin-top: calc(var(--spacing) * 2);
cursor: pointer;
font-size: 1.1em;
font-weight: 600;
color: var(--color-surfacelighter);
.facebook-statement {
margin: calc(var(--spacing) * 0.5) 0 calc(var(--spacing) * 4) 0;
text-align: center;
color: var(--color-surface);
}
.form-container {
width: var(--login-form-width);
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: center;
.text-input {
margin: 0 calc(var(--spacing) * 0.5) var(--spacing) calc(var(--spacing) * 0.5);
padding: 0.5em 0;
border-bottom: 1px solid var(--color-surface);
font-size: 1.1em;
color: var(--color-surfacelighter);
background: none;
&::placeholder {
color: var(--color-surfacelight);
}
&:hover, &:focus {
border-bottom-color: var(--color-surfacelighter);
&::placeholder {
color: var(--color-surfacelighter);
}
}
}
.consent-checkbox {
width: 100%;
margin-bottom: var(--spacing);
padding: calc(var(--spacing) * 0.5);
border: var(--focusable-border-size) solid transparent;
&:focus-within {
border-color: var(--color-surfacelighter);
}
}
.forgot-password {
align-self: flex-end;
margin-bottom: var(--spacing);
padding: calc(var(--spacing) * 0.5);
border: var(--focusable-border-size) solid transparent;
color: var(--color-surfacelight);
cursor: pointer;
&:hover, &:focus {
color: var(--color-surfacelighter);
}
&:focus {
border-color: var(--color-surfacelighter);
}
&:hover {
border-color: transparent;
}
}
.error {
margin-bottom: var(--spacing);
text-align: center;
color: var(--color-signal1);
}
.submit-button {
width: 100%;
outline: none;
padding: calc(var(--spacing) * 1.1);
font-size: 1.1em;
font-weight: 600;
border: var(--focusable-border-size) solid transparent;
color: var(--color-surfacelighter);
background-color: var(--color-primarydark);
cursor: pointer;
&:hover, &:focus {
background-color: var(--color-primary);
}
&:focus {
border-color: var(--color-surfacelighter);
}
&:hover {
border-color: transparent;
}
}
}
.switch-form-button, .guest-login-button {
width: 100%;
display: inline-block;
margin-top: var(--spacing);
padding: calc(var(--spacing) * 0.5);
text-align: center;
font-size: 1.1em;
font-weight: 600;
border: var(--focusable-border-size) solid transparent;
color: var(--color-surfacelighter);
cursor: pointer;
&:focus {
border-color: var(--color-surfacelighter);
}
&:hover {
border-color: transparent;
}
}
}
}
}