change: less intrusive first run experience
This commit is contained in:
parent
1f74ff3c63
commit
defc08eccb
24 changed files with 449 additions and 191 deletions
|
@ -67,6 +67,7 @@
|
|||
"react-feather": "^1.0.8",
|
||||
"react-modal": "^3.1.7",
|
||||
"react-paginate": "^5.2.1",
|
||||
"react-pose": "^4.0.5",
|
||||
"react-redux": "^5.0.3",
|
||||
"react-simplemde-editor": "^3.6.16",
|
||||
"react-toggle": "^4.0.2",
|
||||
|
|
29
src/renderer/component/emailCollection/index.js
Normal file
29
src/renderer/component/emailCollection/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import { connect } from 'react-redux';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { selectEmailToVerify, selectUser } from 'lbryinc';
|
||||
import FirstRunEmailCollection from './view';
|
||||
|
||||
const select = state => ({
|
||||
emailCollectionAcknowledged: makeSelectClientSetting(SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED)(
|
||||
state
|
||||
),
|
||||
email: selectEmailToVerify(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => () => ({
|
||||
completeFirstRun: () => {
|
||||
dispatch(doSetClientSetting(SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED, true));
|
||||
dispatch(doSetClientSetting(SETTINGS.FIRST_RUN_COMPLETED, true));
|
||||
},
|
||||
acknowledgeEmail: () => {
|
||||
dispatch(doSetClientSetting(SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED, true));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(FirstRunEmailCollection);
|
46
src/renderer/component/emailCollection/view.jsx
Normal file
46
src/renderer/component/emailCollection/view.jsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import UserEmailNew from 'component/userEmailNew';
|
||||
import UserEmailVerify from 'component/userEmailVerify';
|
||||
|
||||
type Props = {
|
||||
email: string,
|
||||
emailCollectionAcknowledged: boolean,
|
||||
user: ?{ has_verified_email: boolean },
|
||||
completeFirstRun: () => void,
|
||||
acknowledgeEmail: () => void,
|
||||
};
|
||||
|
||||
class FirstRunEmailCollection extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
completeFirstRun,
|
||||
email,
|
||||
user,
|
||||
emailCollectionAcknowledged,
|
||||
acknowledgeEmail,
|
||||
} = this.props;
|
||||
|
||||
// this shouldn't happen
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cancelButton = <Button button="link" onClick={completeFirstRun} label={__('Not Now')} />;
|
||||
if (user && !user.has_verified_email && !email) {
|
||||
return <UserEmailNew cancelButton={cancelButton} />;
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return <UserEmailVerify cancelButton={cancelButton} />;
|
||||
}
|
||||
|
||||
// Try to acknowledge here so users don't see an empty email screen in the first run banner
|
||||
if (!emailCollectionAcknowledged) {
|
||||
acknowledgeEmail();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default FirstRunEmailCollection;
|
29
src/renderer/component/firstRun/index.js
Normal file
29
src/renderer/component/firstRun/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUser } from 'lbryinc';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import FirstRun from './view';
|
||||
|
||||
const select = state => ({
|
||||
emailCollectionAcknowledged: makeSelectClientSetting(SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED)(
|
||||
state
|
||||
),
|
||||
welcomeAcknowledged: makeSelectClientSetting(SETTINGS.NEW_USER_ACKNOWLEDGED)(state),
|
||||
firstRunComplete: makeSelectClientSetting(SETTINGS.FIRST_RUN_COMPLETED)(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
acknowledgeWelcome: () => {
|
||||
dispatch(doSetClientSetting(SETTINGS.NEW_USER_ACKNOWLEDGED, true));
|
||||
},
|
||||
completeFirstRun: () => {
|
||||
dispatch(doSetClientSetting(SETTINGS.FIRST_RUN_COMPLETED, true));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(FirstRun);
|
115
src/renderer/component/firstRun/view.jsx
Normal file
115
src/renderer/component/firstRun/view.jsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
// @flow
|
||||
import React, { PureComponent } from 'react';
|
||||
import posed from 'react-pose';
|
||||
import Button from 'component/button';
|
||||
import EmailCollection from 'component/emailCollection';
|
||||
import Native from 'native';
|
||||
|
||||
//
|
||||
// Animation for items inside banner
|
||||
// The height for items must be static (in banner.scss) so that we can reliably animate into the banner and be vertically centered
|
||||
//
|
||||
const spring = {
|
||||
type: 'spring',
|
||||
stiffness: 100,
|
||||
damping: 10,
|
||||
mass: 1,
|
||||
};
|
||||
|
||||
const Welcome = posed.div({
|
||||
hide: { opacity: 0, y: '310px', ...spring },
|
||||
show: { opacity: 1, ...spring },
|
||||
});
|
||||
|
||||
const Email = posed.div({
|
||||
hide: { opacity: 0, y: '0', ...spring },
|
||||
show: { opacity: 1, y: '-310px', ...spring, delay: 175 },
|
||||
});
|
||||
|
||||
const Help = posed.div({
|
||||
hide: { opacity: 0, y: '0', ...spring },
|
||||
show: { opacity: 1, y: '-620px', ...spring, delay: 175 },
|
||||
});
|
||||
|
||||
type Props = {
|
||||
welcomeAcknowledged: boolean,
|
||||
emailCollectionAcknowledged: boolean,
|
||||
firstRunComplete: boolean,
|
||||
acknowledgeWelcome: () => void,
|
||||
completeFirstRun: () => void,
|
||||
};
|
||||
|
||||
export default class FirstRun extends PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
welcomeAcknowledged,
|
||||
emailCollectionAcknowledged,
|
||||
firstRunComplete,
|
||||
acknowledgeWelcome,
|
||||
completeFirstRun,
|
||||
} = this.props;
|
||||
|
||||
if (firstRunComplete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const showWelcome = !welcomeAcknowledged;
|
||||
const showEmail = !emailCollectionAcknowledged && welcomeAcknowledged;
|
||||
const showHelp = !showWelcome && !showEmail;
|
||||
|
||||
return (
|
||||
<div className="banner banner--first-run">
|
||||
<img
|
||||
alt="Friendly gerbil"
|
||||
className="yrbl--first-run banner__item"
|
||||
src={Native.imagePath('gerbil-happy.png')}
|
||||
/>
|
||||
|
||||
<div className="banner__item">
|
||||
<div className="banner__item--static-for-animation">
|
||||
<Welcome className="banner__content" pose={showWelcome ? 'show' : 'hide'}>
|
||||
<div>
|
||||
<header className="card__header">
|
||||
<h1 className="card__title">{__('Hi There')}</h1>
|
||||
</header>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__('Using LBRY is like dating a centaur. Totally normal up top, and')}{' '}
|
||||
<em>{__('way different')}</em> {__('underneath.')}
|
||||
</p>
|
||||
<p>{__('Up top, LBRY is similar to popular media sites.')}</p>
|
||||
<p>
|
||||
{__(
|
||||
'Below, LBRY is controlled by users -- you -- via blockchain and decentralization.'
|
||||
)}
|
||||
</p>
|
||||
<div className="card__actions">
|
||||
<Button button="primary" onClick={acknowledgeWelcome} label={__("I'm In")} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Welcome>
|
||||
</div>
|
||||
<div className="banner__item--static-for-animation">
|
||||
<Email pose={showEmail ? 'show' : 'hide'}>
|
||||
<EmailCollection />
|
||||
</Email>
|
||||
</div>
|
||||
<div className="banner__item--static-for-animation">
|
||||
<Help pose={showHelp ? 'show' : 'hide'}>
|
||||
<header className="card__header">
|
||||
<h1 className="card__title">{__('You Are Awesome!')}</h1>
|
||||
</header>
|
||||
<div className="card__content">
|
||||
<p>{__("Check out some of the neat files below me. I'll see you around!")}</p>
|
||||
<div className="card__actions">
|
||||
<Button button="primary" onClick={completeFirstRun} label={__('See You Later')} />
|
||||
</div>
|
||||
</div>
|
||||
</Help>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -61,7 +61,7 @@ class SocialShare extends React.PureComponent<Props> {
|
|||
<div className="card__content">
|
||||
<label className="card__subtitle">{__('Web link')}</label>
|
||||
<CopyableText copyable={speechURL} />
|
||||
<div className="card__actions card__actions--center card__actions--top-space">
|
||||
<div className="card__actions card__actions--center">
|
||||
<ToolTip onComponent body={__('Facebook')}>
|
||||
<Button
|
||||
iconColor="blue"
|
||||
|
@ -95,7 +95,7 @@ class SocialShare extends React.PureComponent<Props> {
|
|||
<div className="card__content">
|
||||
<label className="card__subtitle">{__('LBRY App link')}</label>
|
||||
<CopyableText copyable={lbryURL} noSnackbar />
|
||||
<div className="card__actions card__actions--center card__actions--top-space">
|
||||
<div className="card__actions card__actions--center">
|
||||
<ToolTip onComponent body={__('Facebook')}>
|
||||
<Button
|
||||
iconColor="blue"
|
||||
|
|
|
@ -42,16 +42,14 @@ class UserEmailNew extends React.PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<p>
|
||||
{__("We'll let you know about LBRY updates, security issues, and great new content.")}
|
||||
</p>
|
||||
<header className="card__header">
|
||||
<h2 className="card__title">{__("Don't Miss Out")}</h2>
|
||||
<p className="card__subtitle">
|
||||
{__("We'll let you know about LBRY updates, security issues, and great new content.")}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<p>
|
||||
{__(
|
||||
'In addition, your email address will never be sold and you can unsubscribe at any time.'
|
||||
)}
|
||||
</p>
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<Form className="card__content" onSubmit={this.handleSubmit}>
|
||||
<FormRow>
|
||||
<FormField
|
||||
stretch
|
||||
|
@ -66,10 +64,13 @@ class UserEmailNew extends React.PureComponent<Props, State> {
|
|||
</FormRow>
|
||||
|
||||
<div className="card__actions">
|
||||
<Submit label="Submit" disabled={isPending} />
|
||||
<Submit label="Submit" disabled={isPending || !this.state.email} />
|
||||
{cancelButton}
|
||||
</div>
|
||||
</Form>
|
||||
<p className="help">
|
||||
{__('Your email address will never be sold and you can unsubscribe at any time.')}
|
||||
</p>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -50,27 +50,33 @@ class UserEmailVerify extends React.PureComponent<Props> {
|
|||
const { cancelButton, email } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
{__('An email was sent to')} {email}.{' '}
|
||||
{__('Follow the link and you will be good to go. This will update automatically.')}
|
||||
</p>
|
||||
<React.Fragment>
|
||||
<header className="card__header">
|
||||
<h2 className="card__title">{__('Waiting For Verification')}</h2>
|
||||
</header>
|
||||
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
label={__('Resend verification email')}
|
||||
onClick={this.handleResendVerificationEmail}
|
||||
/>
|
||||
{cancelButton}
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__('An email was sent to')} {email}.{' '}
|
||||
{__('Follow the link and you will be good to go. This will update automatically.')}
|
||||
</p>
|
||||
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
label={__('Resend verification email')}
|
||||
onClick={this.handleResendVerificationEmail}
|
||||
/>
|
||||
{cancelButton}
|
||||
</div>
|
||||
|
||||
<p className="help">
|
||||
{__('Email')} <Button button="link" href="mailto:help@lbry.io" label="help@lbry.io" />{' '}
|
||||
or join our <Button button="link" href="https://chat.lbry.io" label="chat" />{' '}
|
||||
{__('if you encounter any trouble verifying.')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p className="help">
|
||||
{__('Email')} <Button button="link" href="mailto:help@lbry.io" label="help@lbry.io" /> or
|
||||
join our <Button button="link" href="https://chat.lbry.io" label="chat" />{' '}
|
||||
{__('if you encounter any trouble verifying.')}
|
||||
</p>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
export const CREDIT_REQUIRED_ACKNOWLEDGED = 'credit_required_acknowledged';
|
||||
export const NEW_USER_ACKNOWLEDGED = 'welcome_acknowledged';
|
||||
export const EMAIL_COLLECTION_ACKNOWLEDGED = 'email_collection_acknowledged';
|
||||
export const FIRST_RUN_COMPLETED = 'first_run_completed';
|
||||
export const LANGUAGE = 'language';
|
||||
export const SHOW_NSFW = 'showNsfw';
|
||||
export const SHOW_UNAVAILABLE = 'showUnavailable';
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import * as settings from 'constants/settings';
|
||||
import { connect } from 'react-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { selectEmailToVerify, selectUser } from 'lbryinc';
|
||||
import ModalEmailCollection from './view';
|
||||
|
||||
const select = state => ({
|
||||
email: selectEmailToVerify(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => () => ({
|
||||
closeModal: () => {
|
||||
dispatch(doSetClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED, true));
|
||||
dispatch(doHideModal());
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(ModalEmailCollection);
|
|
@ -1,54 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import Button from 'component/button';
|
||||
import UserEmailNew from 'component/userEmailNew';
|
||||
import UserEmailVerify from 'component/userEmailVerify';
|
||||
|
||||
type Props = {
|
||||
closeModal: () => void,
|
||||
email: string,
|
||||
user: ?{ has_verified_email: boolean },
|
||||
};
|
||||
|
||||
class ModalEmailCollection extends React.PureComponent<Props> {
|
||||
getTitle() {
|
||||
// const { user } = this.props;
|
||||
//
|
||||
// if (user && user.email && !user.has_verified_email) {
|
||||
// return __('Awaiting Confirmation');
|
||||
// }
|
||||
|
||||
return __('Can We Stay In Touch?');
|
||||
}
|
||||
|
||||
renderInner() {
|
||||
const { closeModal, email, user } = this.props;
|
||||
|
||||
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
|
||||
if (user && !user.has_verified_email && !email) {
|
||||
return <UserEmailNew cancelButton={cancelButton} />;
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return <UserEmailVerify onModal cancelButton={cancelButton} />;
|
||||
}
|
||||
|
||||
return closeModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { user } = this.props;
|
||||
|
||||
// this shouldn't happen
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal type="custom" isOpen contentLabel="Email" title={this.getTitle()}>
|
||||
<section className="card__content">{this.renderInner()}</section>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalEmailCollection;
|
|
@ -16,7 +16,6 @@ import ModalTransactionFailed from 'modal/modalTransactionFailed';
|
|||
import ModalFileTimeout from 'modal/modalFileTimeout';
|
||||
import ModalAffirmPurchase from 'modal/modalAffirmPurchase';
|
||||
import ModalRevokeClaim from 'modal/modalRevokeClaim';
|
||||
import ModalEmailCollection from 'modal/modalEmailCollection';
|
||||
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
||||
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
||||
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
|
||||
|
@ -78,11 +77,10 @@ class ModalRouter extends React.PureComponent<Props, State> {
|
|||
return;
|
||||
}
|
||||
|
||||
const transitionModal = [
|
||||
this.checkShowWelcome,
|
||||
this.checkShowEmail,
|
||||
this.checkShowCreditIntro,
|
||||
].reduce((acc, func) => (!acc ? func.bind(this)(props) : acc), false);
|
||||
const transitionModal = [this.checkShowCreditIntro].reduce(
|
||||
(acc, func) => (!acc ? func.bind(this)(props) : acc),
|
||||
false
|
||||
);
|
||||
|
||||
if (
|
||||
transitionModal &&
|
||||
|
@ -96,30 +94,6 @@ class ModalRouter extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
checkShowWelcome(props: Props) {
|
||||
const { isWelcomeAcknowledged, user } = props;
|
||||
|
||||
if (!isWelcomeAcknowledged && user && !user.is_reward_approved && !user.is_identity_verified) {
|
||||
return MODALS.WELCOME;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
checkShowEmail(props: Props) {
|
||||
const { isEmailCollectionAcknowledged, isVerificationCandidate, user } = props;
|
||||
if (
|
||||
!isEmailCollectionAcknowledged &&
|
||||
isVerificationCandidate &&
|
||||
user &&
|
||||
!user.has_verified_email
|
||||
) {
|
||||
return MODALS.EMAIL_COLLECTION;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
checkShowCreditIntro(props: Props) {
|
||||
const { balance, page, isCreditIntroAcknowledged } = props;
|
||||
|
||||
|
@ -185,8 +159,6 @@ class ModalRouter extends React.PureComponent<Props, State> {
|
|||
return <ModalRevokeClaim {...modalProps} />;
|
||||
case MODALS.PHONE_COLLECTION:
|
||||
return <ModalPhoneCollection {...modalProps} />;
|
||||
case MODALS.EMAIL_COLLECTION:
|
||||
return <ModalEmailCollection {...modalProps} />;
|
||||
case MODALS.FIRST_SUBSCRIPTION:
|
||||
return <ModalFirstSubscription {...modalProps} />;
|
||||
case MODALS.SEND_TIP:
|
||||
|
|
|
@ -30,19 +30,6 @@ class AuthPage extends React.PureComponent<Props> {
|
|||
this.navigateIfAuthenticated(nextProps);
|
||||
}
|
||||
|
||||
getTitle() {
|
||||
const { email, isPending, user } = this.props;
|
||||
|
||||
if (isPending || (user && !user.has_verified_email && !email)) {
|
||||
return __('Human Proofing');
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return __('Awaiting Confirmation');
|
||||
} else if (user && !user.is_identity_verified && !user.is_reward_approved) {
|
||||
return __('Final Verification');
|
||||
}
|
||||
return __('Welcome to LBRY');
|
||||
}
|
||||
|
||||
navigateIfAuthenticated = (props: Props) => {
|
||||
const { isPending, user, pathAfterAuth, navigate } = props;
|
||||
if (
|
||||
|
@ -78,24 +65,18 @@ class AuthPage extends React.PureComponent<Props> {
|
|||
<Page>
|
||||
{useTemplate ? (
|
||||
<section className="card card--section">
|
||||
<header className="card__header card__header--flat">
|
||||
<h2 className="card__title">{this.getTitle()}</h2>
|
||||
</header>
|
||||
{innerContent}
|
||||
|
||||
<div className="card__content">
|
||||
{innerContent}
|
||||
|
||||
<p className="help">
|
||||
{`${__(
|
||||
'This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards and may be used to sync usage data across devices.'
|
||||
)} `}
|
||||
<Button
|
||||
button="link"
|
||||
onClick={() => navigate('/discover')}
|
||||
label={__('Return home.')}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<p className="help">
|
||||
{`${__(
|
||||
'This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards and may be used to sync usage data across devices.'
|
||||
)} `}
|
||||
<Button
|
||||
button="link"
|
||||
onClick={() => navigate('/discover')}
|
||||
label={__('Return home.')}
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
) : (
|
||||
innerContent
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
import React from 'react';
|
||||
import Page from 'component/page';
|
||||
import CategoryList from 'component/categoryList';
|
||||
import FirstRun from 'component/firstRun';
|
||||
|
||||
type Props = {
|
||||
fetchFeaturedUris: () => void,
|
||||
fetchRewardedContent: () => void,
|
||||
fetchRewards: () => void,
|
||||
fetchingFeaturedUris: boolean,
|
||||
featuredUris: {},
|
||||
};
|
||||
|
@ -59,6 +61,7 @@ class DiscoverPage extends React.PureComponent<Props> {
|
|||
const failedToLoad = !fetchingFeaturedUris && !hasContent;
|
||||
return (
|
||||
<Page noPadding isLoading={!hasContent && fetchingFeaturedUris}>
|
||||
<FirstRun />
|
||||
{hasContent &&
|
||||
Object.keys(featuredUris).map(
|
||||
category =>
|
||||
|
|
|
@ -10,24 +10,34 @@ function getLocalStorageSetting(setting, fallback) {
|
|||
const reducers = {};
|
||||
const defaultState = {
|
||||
clientSettings: {
|
||||
instantPurchaseEnabled: getLocalStorageSetting(SETTINGS.INSTANT_PURCHASE_ENABLED, false),
|
||||
instantPurchaseMax: getLocalStorageSetting(SETTINGS.INSTANT_PURCHASE_MAX, {
|
||||
[SETTINGS.INSTANT_PURCHASE_ENABLED]: getLocalStorageSetting(
|
||||
SETTINGS.INSTANT_PURCHASE_ENABLED,
|
||||
false
|
||||
),
|
||||
[SETTINGS.INSTANT_PURCHASE_MAX]: getLocalStorageSetting(SETTINGS.INSTANT_PURCHASE_MAX, {
|
||||
currency: 'LBC',
|
||||
amount: 0.1,
|
||||
}),
|
||||
showNsfw: getLocalStorageSetting(SETTINGS.SHOW_NSFW, false),
|
||||
showUnavailable: getLocalStorageSetting(SETTINGS.SHOW_UNAVAILABLE, true),
|
||||
welcome_acknowledged: getLocalStorageSetting(SETTINGS.NEW_USER_ACKNOWLEDGED, false),
|
||||
email_collection_acknowledged: getLocalStorageSetting(SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED),
|
||||
credit_required_acknowledged: false, // this needs to be re-acknowledged every run
|
||||
language: getLocalStorageSetting(SETTINGS.LANGUAGE, 'en'),
|
||||
theme: getLocalStorageSetting(SETTINGS.THEME, 'light'),
|
||||
themes: getLocalStorageSetting(SETTINGS.THEMES, []),
|
||||
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
||||
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false),
|
||||
resultCount: Number(getLocalStorageSetting(SETTINGS.RESULT_COUNT, 50)),
|
||||
autoDownload: getLocalStorageSetting(SETTINGS.AUTO_DOWNLOAD, true),
|
||||
osNotificationsEnabled: Boolean(
|
||||
[SETTINGS.SHOW_NSFW]: getLocalStorageSetting(SETTINGS.SHOW_NSFW, false),
|
||||
[SETTINGS.SHOW_UNAVAILABLE]: getLocalStorageSetting(SETTINGS.SHOW_UNAVAILABLE, true),
|
||||
[SETTINGS.NEW_USER_ACKNOWLEDGED]: getLocalStorageSetting(SETTINGS.NEW_USER_ACKNOWLEDGED, false),
|
||||
[SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED]: getLocalStorageSetting(
|
||||
SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED,
|
||||
false
|
||||
),
|
||||
[SETTINGS.FIRST_RUN_COMPLETED]: getLocalStorageSetting(SETTINGS.FIRST_RUN_COMPLETED, false),
|
||||
[SETTINGS.CREDIT_REQUIRED_ACKNOWLEDGED]: false, // this needs to be re-acknowledged every run
|
||||
[SETTINGS.LANGUAGE]: getLocalStorageSetting(SETTINGS.LANGUAGE, 'en'),
|
||||
[SETTINGS.THEME]: getLocalStorageSetting(SETTINGS.THEME, 'dark'),
|
||||
[SETTINGS.THEMES]: getLocalStorageSetting(SETTINGS.THEMES, []),
|
||||
[SETTINGS.AUTOMATIC_DARK_MODE_ENABLED]: getLocalStorageSetting(
|
||||
SETTINGS.AUTOMATIC_DARK_MODE_ENABLED,
|
||||
false
|
||||
),
|
||||
[SETTINGS.AUTOPLAY]: getLocalStorageSetting(SETTINGS.AUTOPLAY, false),
|
||||
[SETTINGS.RESULT_COUNT]: Number(getLocalStorageSetting(SETTINGS.RESULT_COUNT, 50)),
|
||||
[SETTINGS.AUTO_DOWNLOAD]: getLocalStorageSetting(SETTINGS.AUTO_DOWNLOAD, true),
|
||||
[SETTINGS.OS_NOTIFICATIONS_ENABLED]: Boolean(
|
||||
getLocalStorageSetting(SETTINGS.OS_NOTIFICATIONS_ENABLED, true)
|
||||
),
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
@import 'init/gui';
|
||||
@import 'component/animation';
|
||||
@import 'component/badge';
|
||||
@import 'component/banner';
|
||||
@import 'component/button';
|
||||
@import 'component/card';
|
||||
@import 'component/channel';
|
||||
|
@ -45,3 +46,4 @@
|
|||
@import 'component/toggle';
|
||||
@import 'component/tooltip';
|
||||
@import 'component/wunderbar';
|
||||
@import 'component/yrbl';
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
.badge--cost:not(.badge--large) {
|
||||
background-color: $lbry-yellow-2;
|
||||
color: $lbry-black;
|
||||
|
||||
html[data-theme='dark'] & {
|
||||
background-color: $lbry-yellow-3;
|
||||
|
|
30
src/renderer/scss/component/_banner.scss
Normal file
30
src/renderer/scss/component/_banner.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
.banner {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
background-color: $lbry-black;
|
||||
color: $lbry-white;
|
||||
}
|
||||
|
||||
.banner--first-run {
|
||||
height: 310px;
|
||||
|
||||
// Adjust this class inside other `.banner--xxx` styles for control over animation
|
||||
.banner__item--static-for-animation {
|
||||
height: 310px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.banner__item {
|
||||
&:not(:first-child) {
|
||||
margin-left: var(--spacing-vertical-large);
|
||||
}
|
||||
}
|
||||
|
||||
.banner__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
|
@ -81,7 +81,7 @@
|
|||
// C O N T E N T
|
||||
|
||||
.card__content {
|
||||
font-size: 1.15rem;
|
||||
font-size: 1.25rem;
|
||||
|
||||
p:not(:last-child) {
|
||||
margin-bottom: var(--spacing-vertical-medium);
|
||||
|
@ -174,9 +174,13 @@
|
|||
// S U B T I T L E
|
||||
|
||||
.card__subtitle {
|
||||
font-size: 1.25rem;
|
||||
font-size: 1.15rem;
|
||||
margin-bottom: var(--spacing-vertical-small);
|
||||
|
||||
p {
|
||||
margin-bottom: var(--spacing-vertical-small);
|
||||
}
|
||||
|
||||
.badge {
|
||||
bottom: -0.12rem;
|
||||
position: relative;
|
||||
|
|
|
@ -613,10 +613,10 @@
|
|||
|
||||
.media-group__header-navigation {
|
||||
display: flex;
|
||||
padding-right: var(--spacing-vertical-medium);
|
||||
padding-right: var(--spacing-vertical-large);
|
||||
|
||||
button:not(:last-of-type) {
|
||||
margin-right: var(--spacing-vertical-tiny);
|
||||
margin-right: var(--spacing-vertical-medium);
|
||||
}
|
||||
|
||||
svg {
|
||||
|
|
10
src/renderer/scss/component/_yrbl.scss
Normal file
10
src/renderer/scss/component/_yrbl.scss
Normal file
|
@ -0,0 +1,10 @@
|
|||
.yrbl {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.yrbl--first-run {
|
||||
align-self: center;
|
||||
height: 200px;
|
||||
width: auto;
|
||||
margin: 0 var(--spacing-vertical-large);
|
||||
}
|
|
@ -150,7 +150,6 @@ input {
|
|||
.card {
|
||||
.help {
|
||||
margin-bottom: 0;
|
||||
margin-top: var(--spacing-vertical-large);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +159,7 @@ input {
|
|||
color: $lbry-gray-5;
|
||||
display: block;
|
||||
padding: 1rem;
|
||||
margin-top: var(--spacing-vertical-large);
|
||||
margin-bottom: var(--spacing-vertical-large);
|
||||
|
||||
html[data-theme='dark'] & {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 265 KiB |
96
yarn.lock
96
yarn.lock
|
@ -101,6 +101,16 @@
|
|||
lodash "^4.2.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@emotion/is-prop-valid@^0.7.3":
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc"
|
||||
dependencies:
|
||||
"@emotion/memoize" "0.7.1"
|
||||
|
||||
"@emotion/memoize@0.7.1":
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
|
||||
|
||||
"@lbry/color@^1.0.2":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@lbry/color/-/color-1.0.3.tgz#ec22b2c48b0e358759528fb3bbe7ba468d4e41ca"
|
||||
|
@ -128,12 +138,33 @@
|
|||
node-fetch "^2.1.1"
|
||||
url-template "^2.0.8"
|
||||
|
||||
"@popmotion/easing@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@popmotion/easing/-/easing-1.0.1.tgz#48336aea29542113df10aeb81b4fd10f0b95f937"
|
||||
|
||||
"@popmotion/popcorn@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@popmotion/popcorn/-/popcorn-0.3.1.tgz#f0f33fbf7ff66f2cd0bf28be24bee0b1d46b65e8"
|
||||
dependencies:
|
||||
"@popmotion/easing" "^1.0.1"
|
||||
framesync "^4.0.1"
|
||||
hey-listen "^1.0.5"
|
||||
style-value-types "^3.0.7"
|
||||
|
||||
"@samverschueren/stream-to-observable@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
|
||||
dependencies:
|
||||
any-observable "^0.3.0"
|
||||
|
||||
"@types/invariant@^2.2.29":
|
||||
version "2.2.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.29.tgz#aa845204cd0a289f65d47e0de63a6a815e30cc66"
|
||||
|
||||
"@types/node@^10.0.5":
|
||||
version "10.12.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
|
||||
|
||||
"@types/node@^8.0.24":
|
||||
version "8.10.21"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.21.tgz#12b3f2359b27aa05a45d886c8ba1eb8d1a77e285"
|
||||
|
@ -4222,6 +4253,12 @@ fragment-cache@^0.2.1:
|
|||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
framesync@^4.0.0, framesync@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.0.1.tgz#ed7791baf0d266f58ab02000456f82cb384815bf"
|
||||
dependencies:
|
||||
hey-listen "^1.0.5"
|
||||
|
||||
fresh@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
|
@ -4667,6 +4704,10 @@ he@1.1.x:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
|
||||
hey-listen@^1.0.4, hey-listen@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.5.tgz#6d0a3a2f60177f65bc4404d571a00025bf5dc20e"
|
||||
|
||||
highlight.js@^9.3.0:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
||||
|
@ -7322,6 +7363,29 @@ pluralize@^7.0.0:
|
|||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
|
||||
|
||||
popmotion-pose@^3.4.0:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/popmotion-pose/-/popmotion-pose-3.4.1.tgz#e13e52ba9fe02051926ca6313a7615876f459990"
|
||||
dependencies:
|
||||
"@popmotion/easing" "^1.0.1"
|
||||
hey-listen "^1.0.5"
|
||||
popmotion "^8.5.0"
|
||||
pose-core "^2.0.0"
|
||||
style-value-types "^3.0.6"
|
||||
tslib "^1.9.1"
|
||||
|
||||
popmotion@^8.5.0:
|
||||
version "8.6.0"
|
||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-8.6.0.tgz#14edf50376fc2d656b59e0d46390896577818abb"
|
||||
dependencies:
|
||||
"@popmotion/easing" "^1.0.1"
|
||||
"@popmotion/popcorn" "^0.3.0"
|
||||
framesync "^4.0.0"
|
||||
hey-listen "^1.0.5"
|
||||
style-value-types "^3.0.6"
|
||||
stylefire "^2.3.4"
|
||||
tslib "^1.9.1"
|
||||
|
||||
portfinder@^1.0.9:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
|
||||
|
@ -7330,6 +7394,15 @@ portfinder@^1.0.9:
|
|||
debug "^2.2.0"
|
||||
mkdirp "0.5.x"
|
||||
|
||||
pose-core@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pose-core/-/pose-core-2.0.2.tgz#6a0bd1e7218e4bf30be9c26a30be8eeb5b8695df"
|
||||
dependencies:
|
||||
"@types/invariant" "^2.2.29"
|
||||
"@types/node" "^10.0.5"
|
||||
hey-listen "^1.0.5"
|
||||
tslib "^1.9.1"
|
||||
|
||||
posix-character-classes@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
|
@ -7907,6 +7980,15 @@ react-paginate@^5.2.1:
|
|||
dependencies:
|
||||
prop-types "^15.6.1"
|
||||
|
||||
react-pose@^4.0.5:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-pose/-/react-pose-4.0.5.tgz#056309b62e32ce0190f90ef35d7ade1b4c463d85"
|
||||
dependencies:
|
||||
"@emotion/is-prop-valid" "^0.7.3"
|
||||
hey-listen "^1.0.5"
|
||||
popmotion-pose "^3.4.0"
|
||||
tslib "^1.9.1"
|
||||
|
||||
react-redux@^5.0.3:
|
||||
version "5.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"
|
||||
|
@ -9260,6 +9342,18 @@ style-loader@^0.20.2:
|
|||
loader-utils "^1.1.0"
|
||||
schema-utils "^0.4.5"
|
||||
|
||||
style-value-types@^3.0.6, style-value-types@^3.0.7:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.0.7.tgz#6e7a22cc8b1a4465193268ed66ad5f2a82579054"
|
||||
|
||||
stylefire@^2.3.4:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/stylefire/-/stylefire-2.3.7.tgz#285b86a48f6c25bbdcccb5dafa26b9f578235bb5"
|
||||
dependencies:
|
||||
framesync "^4.0.0"
|
||||
hey-listen "^1.0.4"
|
||||
style-value-types "^3.0.6"
|
||||
|
||||
sumchecker@^1.2.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-1.3.1.tgz#79bb3b4456dd04f18ebdbc0d703a1d1daec5105d"
|
||||
|
@ -9592,7 +9686,7 @@ truncate-utf8-bytes@^1.0.0:
|
|||
dependencies:
|
||||
utf8-byte-length "^1.0.1"
|
||||
|
||||
tslib@^1.9.0:
|
||||
tslib@^1.9.0, tslib@^1.9.1:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
||||
|
||||
|
|
Loading…
Reference in a new issue