Add go to page navigation to channel pagination options #1166

Merged
miikkatu merged 2 commits from channel-pagination-go-to-page into master 2018-03-30 19:17:27 +02:00
17 changed files with 137 additions and 87 deletions
Showing only changes of commit 92ea289766 - Show all commits

View file

@ -33,6 +33,7 @@
"printWidth": 100, "printWidth": 100,
"singleQuote": true "singleQuote": true
}], }],
"func-names": ["warn", "as-needed"] "func-names": ["warn", "as-needed"],
"jsx-a11y/label-has-for": 0
} }
} }

View file

@ -74,7 +74,11 @@ export class FormField extends React.PureComponent<Props> {
{error} {error}
</label> </label>
)} )}
<div className="form-field__input"> <div
className={classnames('form-field__input', {
'form-field--auto-height': type === 'markdown',
})}
>
{prefix && ( {prefix && (
<label htmlFor={name} className="form-field__prefix"> <label htmlFor={name} className="form-field__prefix">
{prefix} {prefix}

View file

@ -1,21 +1,17 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import lbry from 'lbry'; import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI';
import { isNameValid, buildURI, regexInvalidURI, parseURI } from 'lbryURI';
import { Form, FormField, FormRow, FormFieldPrice, Submit } from 'component/common/form'; import { Form, FormField, FormRow, FormFieldPrice, Submit } from 'component/common/form';
import Button from 'component/button'; import Button from 'component/button';
import Modal from 'modal/modal';
import ChannelSection from 'component/selectChannel'; import ChannelSection from 'component/selectChannel';
import Icon from 'component/common/icon';
import classnames from 'classnames'; import classnames from 'classnames';
import type { PublishParams, UpdatePublishFormData } from 'redux/reducers/publish'; import type { PublishParams, UpdatePublishFormData } from 'redux/reducers/publish';
import FileSelector from 'component/common/file-selector'; import FileSelector from 'component/common/file-selector';
import { COPYRIGHT, OTHER } from 'constants/licenses';
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
import * as icons from 'constants/icons';
import BidHelpText from './internal/bid-help-text'; import BidHelpText from './internal/bid-help-text';
import LicenseType from './internal/license-type'; import LicenseType from './internal/license-type';
import { COPYRIGHT, OTHER } from 'constants/licenses';
import { MINIMUM_PUBLISH_BID } from 'constants/claim';
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
import * as icons from 'constants/icons';
type Props = { type Props = {
publish: PublishParams => void, publish: PublishParams => void,
@ -292,7 +288,6 @@ class PublishForm extends React.PureComponent<Props> {
submitLabel = !publishing ? __('Publish') : __('Publishing...'); submitLabel = !publishing ? __('Publish') : __('Publishing...');
} }
console.log('this.props', this.props);
return ( return (
<Form onSubmit={this.handlePublish}> <Form onSubmit={this.handlePublish}>
<section className={classnames('card card--section')}> <section className={classnames('card card--section')}>

View file

@ -1,18 +1,31 @@
// I'll come back to this // @flow
/* eslint-disable */ import * as React from 'react';
import React from 'react'; import { FormField, Form, FormRow, Submit } from 'component/common/form';
import { Form, FormRow, Submit } from 'component/common/form';
class UserEmailNew extends React.PureComponent { type Props = {
constructor(props) { cancelButton: React.Node,
super(props); errorMessage: ?string,
isPending: boolean,
addUserEmail: string => void,
};
type State = {
email: string,
};
class UserEmailNew extends React.PureComponent<Props, State> {
constructor() {
super();
this.state = { this.state = {
email: '', email: '',
}; };
(this: any).handleSubmit = this.handleSubmit.bind(this);
(this: any).handleEmailChanged = this.handleEmailChanged.bind(this);
} }
handleEmailChanged(event) { handleEmailChanged(event: SyntheticInputEvent<*>) {
this.setState({ this.setState({
email: event.target.value, email: event.target.value,
}); });
@ -20,7 +33,8 @@ class UserEmailNew extends React.PureComponent {
handleSubmit() { handleSubmit() {
const { email } = this.state; const { email } = this.state;
this.props.addUserEmail(email); const { addUserEmail } = this.props;
addUserEmail(email);
} }
render() { render() {
@ -32,19 +46,20 @@ class UserEmailNew extends React.PureComponent {
{__("We'll let you know about LBRY updates, security issues, and great new content.")} {__("We'll let you know about LBRY updates, security issues, and great new content.")}
</p> </p>
<p>{__("We'll never sell your email, and you can unsubscribe at any time.")}</p> <p>{__("We'll never sell your email, and you can unsubscribe at any time.")}</p>
<Form onSubmit={this.handleSubmit.bind(this)}> <Form onSubmit={this.handleSubmit}>
<FormRow <FormRow>
type="text" <FormField
stretch
type="email"
label="Email" label="Email"
placeholder="youremail@example.org" placeholder="youremail@example.org"
name="email" name="email"
value={this.state.email} value={this.state.email}
errorMessage={errorMessage} error={errorMessage}
onChange={event => { onChange={this.handleEmailChanged}
this.handleEmailChanged(event);
}}
/> />
<div className="form-row-submit"> </FormRow>
<div className="card__actions">
<Submit label="Submit" disabled={isPending} /> <Submit label="Submit" disabled={isPending} />
{cancelButton} {cancelButton}
</div> </div>
@ -55,4 +70,3 @@ class UserEmailNew extends React.PureComponent {
} }
export default UserEmailNew; export default UserEmailNew;
/* eslint-enable */

View file

@ -1,10 +1,11 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { normalizeURI } from 'lbryURI';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import Autocomplete from './internal/autocomplete';
import { parseQueryParams } from 'util/query_params'; import { parseQueryParams } from 'util/query_params';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import Autocomplete from './internal/autocomplete';
type Props = { type Props = {
updateSearchQuery: string => void, updateSearchQuery: string => void,

View file

@ -76,7 +76,7 @@ export class Modal extends React.PureComponent<ModalProps> {
/> />
{type === 'confirm' ? ( {type === 'confirm' ? (
<Button <Button
button="alt" button="link"
label={abortButtonLabel} label={abortButtonLabel}
disabled={abortButtonDisabled} disabled={abortButtonDisabled}
onClick={onAborted} onClick={onAborted}

View file

@ -1,21 +1,29 @@
// @flow
import React from 'react'; import React from 'react';
import { Modal } from 'modal/modal'; import { Modal } from 'modal/modal';
import Button from 'component/button'; import Button from 'component/button';
import UserEmailNew from 'component/userEmailNew'; import UserEmailNew from 'component/userEmailNew';
import UserEmailVerify from 'component/userEmailVerify'; import UserEmailVerify from 'component/userEmailVerify';
class ModalEmailCollection extends React.PureComponent { type Props = {
closeModal: () => void,
email: string,
user: ?{ has_verified_email: boolean },
};
class ModalEmailCollection extends React.PureComponent<Props> {
renderInner() { renderInner() {
const { closeModal, email, user } = this.props; const { closeModal, email, user } = this.props;
const cancelButton = <Button button="text" onClick={closeModal} label={__('Not Now')} />; const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
if (!user.has_verified_email && !email) { if (user && !user.has_verified_email && !email) {
return <UserEmailNew cancelButton={cancelButton} />; return <UserEmailNew cancelButton={cancelButton} />;
} else if (!user.has_verified_email) { } else if (user && !user.has_verified_email) {
return <UserEmailVerify cancelButton={cancelButton} />; return <UserEmailVerify cancelButton={cancelButton} />;
} }
closeModal();
return closeModal();
} }
render() { render() {

View file

@ -23,9 +23,8 @@ class ModalSendTip extends React.PureComponent<Props> {
closeModal(); closeModal();
}} }}
> >
<p> <p>{__('Your file has been published to LBRY at the address')}</p>
{__('Your file has been published to LBRY at the address')} <code>{uri}</code>! <p className="card__success-msg">{uri}</p>
</p>
<p> <p>
{__( {__(
'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.' 'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.'

View file

@ -1,3 +1,4 @@
// @flow
import React from 'react'; import React from 'react';
import BusyIndicator from 'component/common/busy-indicator'; import BusyIndicator from 'component/common/busy-indicator';
import Button from 'component/button'; import Button from 'component/button';
@ -6,29 +7,31 @@ import UserEmailVerify from 'component/userEmailVerify';
import UserVerify from 'component/userVerify'; import UserVerify from 'component/userVerify';
import Page from 'component/page'; import Page from 'component/page';
export class AuthPage extends React.PureComponent { type Props = {
isPending: boolean,
email: string,
// Not sure why it isn't recognizing that we are using this prop type
// Something to do with how we are passing all the props through probably
pathAfterAuth: string, // eslint-disable-line react/no-unused-prop-types
user: ?{
has_verified_email: boolean,
is_reward_approved: boolean,
is_identity_verified: boolean,
},
navigate: (string, ?{}) => void,
};
export class AuthPage extends React.PureComponent<Props> {
componentWillMount() { componentWillMount() {
this.navigateIfAuthenticated(this.props); this.navigateIfAuthenticated(this.props);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps: Props) {
this.navigateIfAuthenticated(nextProps); this.navigateIfAuthenticated(nextProps);
} }
navigateIfAuthenticated(props) {
const { isPending, user } = props;
if (
!isPending &&
user &&
user.has_verified_email &&
(user.is_reward_approved || user.is_identity_verified)
) {
props.navigate(props.pathAfterAuth);
}
}
getTitle() { getTitle() {
const { email, isPending, isVerificationCandidate, user } = this.props; const { email, isPending, user } = this.props;
if (isPending || (user && !user.has_verified_email && !email)) { if (isPending || (user && !user.has_verified_email && !email)) {
return __('Human Proofing'); return __('Human Proofing');
@ -40,8 +43,20 @@ export class AuthPage extends React.PureComponent {
return __('Welcome to LBRY'); return __('Welcome to LBRY');
} }
navigateIfAuthenticated = (props: Props) => {
const { isPending, user, pathAfterAuth, navigate } = props;
if (
!isPending &&
user &&
user.has_verified_email &&
(user.is_reward_approved || user.is_identity_verified)
) {
navigate(pathAfterAuth);
}
};
renderMain() { renderMain() {
const { email, isPending, isVerificationCandidate, user } = this.props; const { email, isPending, user } = this.props;
if (isPending) { if (isPending) {
return [<BusyIndicator message={__('Authenticating')} />, true]; return [<BusyIndicator message={__('Authenticating')} />, true];
@ -56,7 +71,7 @@ export class AuthPage extends React.PureComponent {
} }
render() { render() {
const { email, user, isPending, navigate } = this.props; const { navigate } = this.props;
const [innerContent, useTemplate] = this.renderMain(); const [innerContent, useTemplate] = this.renderMain();
return ( return (
@ -72,7 +87,11 @@ export class AuthPage extends React.PureComponent {
{`${__( {`${__(
'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.' '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 onClick={() => navigate('/discover')} label={__('Return home')} />. <Button
button="link"
onClick={() => navigate('/discover')}
label={__('Return home.')}
/>
</div> </div>
</div> </div>
</section> </section>

View file

@ -12,7 +12,7 @@ type Props = {
class BackupPage extends React.PureComponent<Props> { class BackupPage extends React.PureComponent<Props> {
render() { render() {
const { daemonSettings } = this.props; const { daemonSettings } = this.props;
const { lbryum_wallet_dir } = daemonSettings; const { lbryum_wallet_dir: lbryumWalletDir } = daemonSettings;
const noDaemonSettings = Object.keys(daemonSettings).length === 0; const noDaemonSettings = Object.keys(daemonSettings).length === 0;
@ -35,24 +35,16 @@ class BackupPage extends React.PureComponent<Props> {
'Currently, there is no automatic wallet backup. If you lose access to these files, you will lose your credits permanently.' 'Currently, there is no automatic wallet backup. If you lose access to these files, you will lose your credits permanently.'
)} )}
</p> </p>
</div>
<div className="card__content">
<p> <p>
{__( {__(
'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:' 'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:'
)} )}
</p> </p>
<div className="card__content"> <p className="card__success-msg">{lbryumWalletDir}</p>
<code>{lbryum_wallet_dir}</code>
</div>
</div>
<div className="card__content">
<p> <p>
<strong>
{__( {__(
'Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place.' 'Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place.'
)} )}
</strong>
</p> </p>
<p> <p>
For more details on backing up and best practices,{' '} For more details on backing up and best practices,{' '}

View file

@ -18,7 +18,7 @@ class DiscoverPage extends React.PureComponent<Props> {
const { featuredUris, fetchingFeaturedUris } = this.props; const { featuredUris, fetchingFeaturedUris } = this.props;
const hasContent = typeof featuredUris === 'object' && Object.keys(featuredUris).length; const hasContent = typeof featuredUris === 'object' && Object.keys(featuredUris).length;
const failedToLoad = !fetchingFeaturedUris && !hasContent; const failedToLoad = !fetchingFeaturedUris && !hasContent;
// lbry://fortnite-top-stream-moments-nickatnydte#27395875d68e9d3e53be46edf36d622aa8284441
return ( return (
<Page noPadding isLoading={!hasContent && fetchingFeaturedUris}> <Page noPadding isLoading={!hasContent && fetchingFeaturedUris}>
{hasContent && {hasContent &&

View file

@ -81,12 +81,13 @@ class RewardsPage extends React.PureComponent {
if (!daemonSettings.share_usage_data) { if (!daemonSettings.share_usage_data) {
return ( return (
<div className="card__content empty"> <div className="card card--section">
<div className="card__title">{__('Disabled')}</div>
<p> <p>
{__( {__(
'Rewards are currently disabled for your account. Turn on diagnostic data sharing, in' 'Rewards are currently disabled for your account. Turn on diagnostic data sharing, in'
)}{' '} )}{' '}
<Button onClick={() => navigate('/settings')} label="Settings" /> <Button button="link" onClick={() => navigate('/settings')} label="Settings" />
{__(', in order to re-enable them.')} {__(', in order to re-enable them.')}
</p> </p>
</div> </div>

View file

@ -138,6 +138,7 @@ dd {
p { p {
font-family: 'metropolis-medium'; font-family: 'metropolis-medium';
padding: $spacing-vertical * 1/3 0;
} }
.page { .page {

View file

@ -31,6 +31,9 @@ $large-breakpoint: 1760px;
--color-light-blue: #49b2e2; --color-light-blue: #49b2e2;
--color-red: #e2495e; --color-red: #e2495e;
--color-yellow: #fbd55e; --color-yellow: #fbd55e;
--color-green: #399483;
--color-green-light: #effbe4;
--color-green-blue: #2ec1a8;
--color-divider: #e3e3e3; --color-divider: #e3e3e3;
--text-color: var(--color-black); --text-color: var(--color-black);
@ -123,6 +126,9 @@ $large-breakpoint: 1760px;
--card-radius: 2px; --card-radius: 2px;
--card-margin: $spacing-vertical * 2/3; --card-margin: $spacing-vertical * 2/3;
--card-wallet-color: var(--text-color-inverse); --card-wallet-color: var(--text-color-inverse);
--success-msg-color: var(--color-green);
--success-msg-border: var(--color-green-blue);
--success-msg-bg: var(--color-green-light);
/* File Tile Card */ /* File Tile Card */
--file-tile--media-size: 60px; --file-tile--media-size: 60px;

View file

@ -114,7 +114,7 @@ button:disabled {
text-transform: uppercase; text-transform: uppercase;
} }
.btn:not(.btn--no-padding):not(.btn--link) { .btn:not(.btn--no-padding):not(.btn--link):not(.btn--no-style) {
.btn__content { .btn__content {
padding: 0 8px; padding: 0 8px;
display: flex; display: flex;

View file

@ -282,7 +282,7 @@
} }
.card:last-of-type { .card:last-of-type {
margin-right: $spacing-vertical * 2/3; margin-right: $spacing-width;
} }
} }
@ -336,12 +336,8 @@
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
overflow: visible; overflow: visible;
// -- three cards on a screen // 35 px to handle to padding between cards
// -- minus 12px for 1/3 of the page padding (36px) width: calc((100% / 3) - 35px);
// -- minus 20px for the card's margin
// Ideally we should be able to use $spacing-width / 3, but I'm not sure
// how inside the calc function
width: calc((100% / 3) - 12px - 20px);
} }
.card:not(:first-of-type) { .card:not(:first-of-type) {
@ -354,11 +350,20 @@
@media only screen and (min-width: $medium-breakpoint) { @media only screen and (min-width: $medium-breakpoint) {
.card { .card {
width: calc((100% / 4) - 12px - 20px); // 31 px to handle to padding between cards
width: calc((100% / 4) - 31px);
} }
} }
} }
.card__success-msg {
border-left: 2px solid var(--success-msg-border);
color: var(--success-msg-color);
background-color: var(--success-msg-bg);
padding: $spacing-vertical * 1/3;
margin: $spacing-vertical * 1/3 0;
}
.card__media--autothumb { .card__media--autothumb {
color: red !important; color: red !important;
} }

View file

@ -51,6 +51,10 @@
input.paginate-channel { input.paginate-channel {
width: 35px; width: 35px;
} }
&.form-field--auto-height {
height: auto;
}
} }
.form-field__help, .form-field__help,