Merge pull request #2221 from lbryio/invite
First run changes for invite page
This commit is contained in:
commit
fbb9c9fd35
45 changed files with 447 additions and 438 deletions
|
@ -1,12 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { doToast } from 'lbry-redux';
|
||||
import Address from './view';
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{
|
||||
doToast,
|
||||
}
|
||||
)(Address);
|
|
@ -1,54 +0,0 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import { clipboard } from 'electron';
|
||||
import { FormRow } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
address: string,
|
||||
doToast: ({ message: string }) => void,
|
||||
};
|
||||
|
||||
export default class Address extends React.PureComponent<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.input = null;
|
||||
}
|
||||
|
||||
input: ?HTMLInputElement;
|
||||
|
||||
render() {
|
||||
const { address, doToast } = this.props;
|
||||
|
||||
return (
|
||||
<FormRow verticallyCentered stretch>
|
||||
<input
|
||||
className="input-copyable form-field__input"
|
||||
readOnly
|
||||
value={address || ''}
|
||||
ref={input => {
|
||||
this.input = input;
|
||||
}}
|
||||
onFocus={() => {
|
||||
if (this.input) {
|
||||
this.input.select();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
noPadding
|
||||
button="secondary"
|
||||
icon={ICONS.CLIPBOARD}
|
||||
onClick={() => {
|
||||
clipboard.writeText(address);
|
||||
doToast({
|
||||
message: __('Address copied'),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</FormRow>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,23 +2,31 @@
|
|||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
|
||||
type IconProps = {
|
||||
size: number,
|
||||
color: string,
|
||||
};
|
||||
|
||||
// Returns a react component
|
||||
const buildIcon = iconStrokes => ({ size = 24, color = 'currentColor', ...otherProps }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width={size}
|
||||
height={size}
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...otherProps}
|
||||
>
|
||||
{iconStrokes}
|
||||
</svg>
|
||||
);
|
||||
const buildIcon = iconStrokes => (props: IconProps) => {
|
||||
const { size = 24, color = 'currentColor', ...otherProps } = props;
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width={size}
|
||||
height={size}
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...otherProps}
|
||||
>
|
||||
{iconStrokes}
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const customIcons = {
|
||||
[ICONS.ARROW_LEFT]: buildIcon(
|
||||
|
@ -37,7 +45,7 @@ export const customIcons = {
|
|||
<polyline strokeLinejoin="round" points="13 4 21 12 13 20" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.EYE]: buildIcon(
|
||||
[ICONS.VIEW]: buildIcon(
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path
|
||||
d="M2, 12 C2, 12 5, 5 12, 5 C19, 5 22, 12 22, 12 C22, 12 19, 19 12, 19 C5, 19 2, 12 2, 12 Z"
|
||||
|
@ -93,4 +101,13 @@ export const customIcons = {
|
|||
/>
|
||||
</g>
|
||||
),
|
||||
[ICONS.PUBLISHED]: buildIcon(
|
||||
<g fill="none" fillRule="evenodd" strokeLinecap="round">
|
||||
<path
|
||||
d="M8, 18 L5, 18 L5, 18 C2.790861, 18 1, 16.209139 1, 14 C1, 11.790861 2.790861, 10 5, 10 C5.35840468, 10 5.70579988, 10.0471371 6.03632437, 10.1355501 C6.01233106, 9.92702603 6, 9.71495305 6, 9.5 C6, 6.46243388 8.46243388, 4 11.5, 4 C14.0673313, 4 16.2238156, 5.7590449 16.8299648, 8.1376465 C17.2052921, 8.04765874 17.5970804, 8 18, 8 C20.7614237, 8 23, 10.2385763 23, 13 C23, 15.7614237 20.7614237, 18 18, 18 L16, 18, L8, 18"
|
||||
strokeLinejoin="round"
|
||||
transform="scale(1, 1.2) translate(0, -2)"
|
||||
/>
|
||||
</g>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ type Props = {
|
|||
icon?: boolean,
|
||||
direction: string,
|
||||
onComponent?: boolean, // extra padding to account for button/form field size
|
||||
alwaysVisible?: boolean, // should tooltip stay open, guide callbacks will close it manually
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -18,6 +19,7 @@ type State = {
|
|||
class ToolTip extends React.PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
direction: 'bottom',
|
||||
alwaysVisible: false,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
|
@ -88,7 +90,7 @@ class ToolTip extends React.PureComponent<Props, State> {
|
|||
|
||||
render() {
|
||||
const { direction } = this.state;
|
||||
const { children, label, body, icon, onComponent } = this.props;
|
||||
const { children, label, body, icon, onComponent, alwaysVisible } = this.props;
|
||||
|
||||
const tooltipContent = children || label;
|
||||
const bodyLength = body.length;
|
||||
|
@ -106,6 +108,7 @@ class ToolTip extends React.PureComponent<Props, State> {
|
|||
'tooltip--bottom': direction === 'bottom',
|
||||
'tooltip--left': direction === 'left',
|
||||
'tooltip--on-component': onComponent,
|
||||
'tooltip--always-visible': alwaysVisible,
|
||||
})}
|
||||
>
|
||||
{tooltipContent}
|
||||
|
@ -113,7 +116,7 @@ class ToolTip extends React.PureComponent<Props, State> {
|
|||
ref={ref => {
|
||||
this.tooltip = ref;
|
||||
}}
|
||||
className={classnames('tooltip__body', {
|
||||
className={classnames('card tooltip__body', {
|
||||
'tooltip__body--short': isShortDescription,
|
||||
})}
|
||||
>
|
||||
|
|
36
src/renderer/component/common/yrbl.jsx
Normal file
36
src/renderer/component/common/yrbl.jsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Native from 'native';
|
||||
|
||||
type Props = {
|
||||
title: string,
|
||||
subtitle: string,
|
||||
type: string,
|
||||
};
|
||||
|
||||
const yrblTypes = {
|
||||
happy: 'gerbil-happy.png',
|
||||
sad: 'gerbil-sad.png',
|
||||
};
|
||||
|
||||
export default class extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
type: 'happy',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { title, subtitle, type } = this.props;
|
||||
|
||||
const image = yrblTypes[type];
|
||||
|
||||
return (
|
||||
<div className="yrbl-wrap">
|
||||
<img alt="Friendly gerbil" className="yrbl" src={Native.imagePath(image)} />
|
||||
<div className="card__content">
|
||||
<h2 className="card__title">{title}</h2>
|
||||
<p className="card__subtitle">{subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import Button from 'component/button';
|
|||
|
||||
type Props = {
|
||||
copyable: string,
|
||||
snackMessage: ?string,
|
||||
doToast: ({ message: string }) => void,
|
||||
};
|
||||
|
||||
|
@ -20,7 +21,7 @@ export default class CopyableText extends React.PureComponent<Props> {
|
|||
input: ?HTMLInputElement;
|
||||
|
||||
render() {
|
||||
const { copyable, doToast } = this.props;
|
||||
const { copyable, doToast, snackMessage } = this.props;
|
||||
|
||||
return (
|
||||
<FormRow verticallyCentered stretch>
|
||||
|
@ -45,7 +46,7 @@ export default class CopyableText extends React.PureComponent<Props> {
|
|||
onClick={() => {
|
||||
clipboard.writeText(copyable);
|
||||
doToast({
|
||||
message: __('Text copied'),
|
||||
message: snackMessage || __('Text copied'),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -34,7 +34,7 @@ class ExternalLink extends React.PureComponent<Props> {
|
|||
element = (
|
||||
<Button
|
||||
button="link"
|
||||
iconRight={ICONS.EXTERNAL_LINK}
|
||||
iconRight={ICONS.EXTERNAL}
|
||||
title={title || href}
|
||||
label={children}
|
||||
className="btn--external-link"
|
||||
|
|
|
@ -20,7 +20,7 @@ type Props = {
|
|||
class FileActions extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { fileInfo, uri, openModal, claimIsMine, claimId } = this.props;
|
||||
const showDelete = (claimIsMine || (fileInfo && Object.keys(fileInfo).length > 0)) ;
|
||||
const showDelete = claimIsMine || (fileInfo && Object.keys(fileInfo).length > 0);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
@ -28,7 +28,7 @@ class FileActions extends React.PureComponent<Props> {
|
|||
<Tooltip onComponent body={__('Delete this file')}>
|
||||
<Button
|
||||
button="alt"
|
||||
icon={ICONS.TRASH}
|
||||
icon={ICONS.DELETE}
|
||||
description={__('Delete')}
|
||||
onClick={() => openModal(MODALS.CONFIRM_FILE_REMOVE, { uri })}
|
||||
/>
|
||||
|
|
|
@ -132,7 +132,7 @@ class FileCard extends React.PureComponent<Props> {
|
|||
<div className="media__properties">
|
||||
<FilePrice hideFree uri={uri} />
|
||||
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||
{isSubscribed && <Icon icon={icons.HEART} />}
|
||||
{isSubscribed && <Icon icon={icons.SUBSCRIPTION} />}
|
||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||
{isNew && <span className="badge badge--alert">{__('NEW')}</span>}
|
||||
</div>
|
||||
|
|
|
@ -97,7 +97,7 @@ class FileDownloadLink extends React.PureComponent<Props> {
|
|||
} else if (fileInfo && fileInfo.download_path) {
|
||||
return (
|
||||
<ToolTip onComponent body={__('Open file')}>
|
||||
<Button button="alt" iconColor="green" icon={ICONS.LOCAL} onClick={() => openFile()} />
|
||||
<Button button="alt" iconColor="green" icon={ICONS.EXTERNAL} onClick={() => openFile()} />
|
||||
</ToolTip>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ class FileTile extends React.PureComponent<Props> {
|
|||
<div className={classnames('media__properties', { card__subtitle: size === 'large' })}>
|
||||
<FilePrice hideFree uri={uri} />
|
||||
{isNew && <span className="badge badge--alert icon">{__('NEW')}</span>}
|
||||
{isSubscribed && <Icon icon={ICONS.HEART} />}
|
||||
{isSubscribed && <Icon icon={ICONS.SUBSCRIPTION} />}
|
||||
{isRewardContent && <Icon iconColor="red" icon={ICONS.FEATURED} />}
|
||||
{isDownloaded && <Icon icon={ICONS.LOCAL} />}
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@ class VideoPlayButton extends React.PureComponent<Props> {
|
|||
const disabled = isLoading || fileInfo === undefined;
|
||||
const doesPlayback = ['audio', 'video'].indexOf(mediaType) !== -1;
|
||||
const label = doesPlayback ? __('Play') : __('View');
|
||||
const icon = doesPlayback ? ICONS.PLAY : ICONS.EYE;
|
||||
const icon = doesPlayback ? ICONS.PLAY : ICONS.VIEW;
|
||||
return (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as ICONS from 'constants/icons';
|
|||
import React from 'react';
|
||||
import Icon from 'component/common/icon';
|
||||
import RewardLink from 'component/rewardLink';
|
||||
import Yrbl from 'component/common/yrbl';
|
||||
import { rewards } from 'lbryinc';
|
||||
|
||||
type Props = {
|
||||
|
@ -22,6 +23,18 @@ class InviteList extends React.PureComponent<Props> {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (!invitees.length) {
|
||||
return (
|
||||
<Yrbl
|
||||
type="happy"
|
||||
title={__('Power To The People')}
|
||||
subtitle={__(
|
||||
'LBRY is powered by the users. More users, more power… and with great power comes great responsibility.'
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="card card--section">
|
||||
<header className="card__header">
|
||||
|
@ -29,43 +42,37 @@ class InviteList extends React.PureComponent<Props> {
|
|||
</header>
|
||||
|
||||
<div className="card__content">
|
||||
{invitees.length === 0 && (
|
||||
<span className="empty">{__("You haven't invited anyone.")} </span>
|
||||
)}
|
||||
{invitees.length > 0 && (
|
||||
<table className="table table--stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__('Invitee Email')}</th>
|
||||
<th className="text-center">{__('Invite Status')}</th>
|
||||
<th className="text-center">{__('Reward')}</th>
|
||||
<table className="table table--stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__('Invitee Email')}</th>
|
||||
<th className="text-center">{__('Invite Status')}</th>
|
||||
<th className="text-center">{__('Reward')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{invitees.map(invitee => (
|
||||
<tr key={invitee.email}>
|
||||
<td>{invitee.email}</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_accepted ? (
|
||||
<Icon icon={ICONS.COMPLETED} />
|
||||
) : (
|
||||
<span className="empty">{__('unused')}</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_reward_claimed && <Icon icon={ICONS.COMPLETED} />}
|
||||
{!invitee.invite_reward_claimed && invitee.invite_reward_claimable ? (
|
||||
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
|
||||
) : (
|
||||
<span className="empty">{__('unclaimable')}</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{invitees.map(invitee => (
|
||||
<tr key={invitee.email}>
|
||||
<td>{invitee.email}</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_accepted ? (
|
||||
<Icon icon={ICONS.CHECK} />
|
||||
) : (
|
||||
<span className="empty">{__('unused')}</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_reward_claimed ? (
|
||||
<Icon icon={ICONS.CHECK} />
|
||||
) : invitee.invite_reward_claimable ? (
|
||||
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
|
||||
) : (
|
||||
<span className="empty">{__('unclaimable')}</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="help">
|
||||
{__(
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
// I'll come back to this
|
||||
/* eslint-disable */
|
||||
// @flow
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import CreditAmount from 'component/common/credit-amount';
|
||||
import Button from 'component/button';
|
||||
import { Form, FormRow, FormField, Submit } from 'component/common/form';
|
||||
|
||||
class FormInviteNew extends React.PureComponent {
|
||||
type FormProps = {
|
||||
inviteNew: string => void,
|
||||
errorMessage: ?string,
|
||||
isPending: boolean,
|
||||
};
|
||||
|
||||
type FormState = {
|
||||
email: string,
|
||||
};
|
||||
|
||||
class FormInviteNew extends React.PureComponent<FormProps, FormState> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
|
@ -14,7 +22,7 @@ class FormInviteNew extends React.PureComponent {
|
|||
email: '',
|
||||
};
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleEmailChanged(event) {
|
||||
|
@ -56,16 +64,16 @@ class FormInviteNew extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
class InviteNew extends React.PureComponent {
|
||||
type Props = {
|
||||
errorMessage: ?string,
|
||||
inviteNew: string => void,
|
||||
isPending: boolean,
|
||||
rewardAmount: number,
|
||||
};
|
||||
|
||||
class InviteNew extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
errorMessage,
|
||||
invitesRemaining,
|
||||
inviteNew,
|
||||
inviteStatusIsPending,
|
||||
isPending,
|
||||
rewardAmount,
|
||||
} = this.props;
|
||||
const { errorMessage, inviteNew, isPending, rewardAmount } = this.props;
|
||||
|
||||
return (
|
||||
<section className="card card--section">
|
||||
|
@ -73,18 +81,10 @@ class InviteNew extends React.PureComponent {
|
|||
<h2 className="card__title">{__('Invite a Friend')}</h2>
|
||||
|
||||
<p className="card__subtitle">
|
||||
{__("Or an enemy. Or your cousin Jerry, who you're kind of unsure about.")}
|
||||
{__('When your friends start using LBRY, the network gets stronger!')}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/*
|
||||
<div className="card__content">
|
||||
{invitesRemaining > 0 &&
|
||||
<p>{__("You have %s invites remaining.", invitesRemaining)}</p>}
|
||||
{invitesRemaining <= 0 &&
|
||||
<p className="empty">{__("You have no invites.")}</p>}
|
||||
</div> */}
|
||||
|
||||
<div className="card__content">
|
||||
<FormInviteNew
|
||||
errorMessage={errorMessage}
|
||||
|
@ -106,4 +106,4 @@ class InviteNew extends React.PureComponent {
|
|||
}
|
||||
|
||||
export default InviteNew;
|
||||
/* eslint-enable */
|
||||
/* eslint-enable react/no-multi-comp */
|
||||
|
|
|
@ -41,7 +41,7 @@ const RewardTile = (props: Props) => {
|
|||
{reward.reward_type !== rewards.TYPE_REFERRAL &&
|
||||
(claimed ? (
|
||||
<span>
|
||||
<Icon icon={ICONS.CHECK} /> {__('Reward claimed.')}
|
||||
<Icon icon={ICONS.COMPLETED} /> {__('Reward claimed.')}
|
||||
</span>
|
||||
) : (
|
||||
<RewardLink button reward_type={reward.reward_type} />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectCurrentPage, selectCurrentParams } from 'lbry-redux';
|
||||
import { selectCurrentPage, selectCurrentParams, doToast } from 'lbry-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import Router from './view';
|
||||
|
||||
|
@ -10,5 +10,5 @@ const select = state => ({
|
|||
|
||||
export default connect(
|
||||
select,
|
||||
{ doOpenModal }
|
||||
{ doOpenModal, doToast }
|
||||
)(Router);
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
|||
import QRCode from 'component/common/qr-code';
|
||||
import { FormRow } from 'component/common/form';
|
||||
import * as statuses from 'constants/shape_shift';
|
||||
import Address from 'component/address';
|
||||
import CopyableText from 'component/copyableText';
|
||||
import Button from 'component/button';
|
||||
import type { Dispatch, ThunkAction } from 'types/redux';
|
||||
import type { Action } from 'redux/actions/shape_shift';
|
||||
|
@ -96,7 +96,7 @@ class ActiveShapeShift extends React.PureComponent<Props> {
|
|||
{shiftDepositAddress && (
|
||||
<FormRow verticallyCentered padded>
|
||||
<QRCode value={shiftDepositAddress} paddingRight />
|
||||
<Address address={shiftDepositAddress} showCopyButton padded />
|
||||
<CopyableText copyable={shiftDepositAddress} />
|
||||
</FormRow>
|
||||
)}
|
||||
</div>
|
||||
|
@ -134,12 +134,13 @@ class ActiveShapeShift extends React.PureComponent<Props> {
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
{shiftState === statuses.NO_DEPOSITS && shiftReturnAddress && (
|
||||
<div className="help">
|
||||
{__("If the transaction doesn't go through, ShapeShift will return your")}{' '}
|
||||
{shiftCoinType} {__('back to')} {shiftReturnAddress}
|
||||
</div>
|
||||
)}
|
||||
{shiftState === statuses.NO_DEPOSITS &&
|
||||
shiftReturnAddress && (
|
||||
<div className="help">
|
||||
{__("If the transaction doesn't go through, ShapeShift will return your")}{' '}
|
||||
{shiftCoinType} {__('back to')} {shiftReturnAddress}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import classnames from 'classnames';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
|
||||
type SideBarLink = {
|
||||
label: string,
|
||||
|
@ -9,6 +10,7 @@ type SideBarLink = {
|
|||
active: boolean,
|
||||
icon: ?string,
|
||||
subLinks: Array<SideBarLink>,
|
||||
guide: ?string,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
|
@ -19,71 +21,86 @@ type Props = {
|
|||
unreadSubscriptionTotal: number,
|
||||
};
|
||||
|
||||
const SideBar = (props: Props) => {
|
||||
const { navLinks, unreadSubscriptionTotal } = props;
|
||||
class SideBar extends React.PureComponent<Props> {
|
||||
renderNavLink(navLink: SideBarLink) {
|
||||
const { label, path, active, subLinks = [], icon, guide } = navLink;
|
||||
|
||||
return (
|
||||
<nav className="navigation">
|
||||
<div className="navigation__links">
|
||||
{navLinks.primary.map(({ label, path, active, icon }) => (
|
||||
<Button
|
||||
icon={icon}
|
||||
className={classnames('navigation__link', {
|
||||
'navigation__link--active': active,
|
||||
})}
|
||||
key={path}
|
||||
label={
|
||||
path === '/subscriptions' && unreadSubscriptionTotal
|
||||
? `${label} (${unreadSubscriptionTotal})`
|
||||
: label
|
||||
}
|
||||
navigate={path}
|
||||
/>
|
||||
))}
|
||||
const inner = (
|
||||
<li
|
||||
className={classnames('navigation__link', {
|
||||
'navigation__link--active': active,
|
||||
})}
|
||||
key={label}
|
||||
>
|
||||
<Button icon={icon} label={label} navigate={path} />
|
||||
|
||||
<ul>
|
||||
<li className="navigation__link navigation__link--title">Account</li>
|
||||
{
|
||||
// The sublinks should be animated on open close
|
||||
// Removing it because the current implementation with CSSTransitionGroup
|
||||
// was really slow and looked pretty bad. Possible fix is upgrading to v2
|
||||
// Not sure if that has better performance
|
||||
}
|
||||
{!!subLinks.length &&
|
||||
active && (
|
||||
<ul key="0" className="navigation__link-items">
|
||||
{subLinks.map(({ active: subLinkActive, label: subLabel, path: subPath }) => (
|
||||
<li
|
||||
className={classnames('navigation__link-item', {
|
||||
'navigation__link-item--active': subLinkActive,
|
||||
})}
|
||||
key={subPath}
|
||||
>
|
||||
{subPath ? (
|
||||
<Button label={subLabel} navigate={subPath} />
|
||||
) : (
|
||||
<span>{subLabel}</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
|
||||
{navLinks.secondary.map(({ label, path, active, subLinks = [], icon }) => (
|
||||
<li
|
||||
return guide ? (
|
||||
<Tooltip key={guide} alwaysVisible direction="right" body={guide}>
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
inner
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navLinks, unreadSubscriptionTotal } = this.props;
|
||||
|
||||
return (
|
||||
<nav className="navigation">
|
||||
<div className="navigation__links">
|
||||
{navLinks.primary.map(({ label, path, active, icon }) => (
|
||||
<Button
|
||||
icon={icon}
|
||||
className={classnames('navigation__link', {
|
||||
'navigation__link--active': active,
|
||||
})}
|
||||
key={label}
|
||||
>
|
||||
<Button icon={icon} label={label} navigate={path} />
|
||||
|
||||
{
|
||||
// The sublinks should be animated on open close
|
||||
// Removing it because the current implementation with CSSTransitionGroup
|
||||
// was really slow and looked pretty bad. Possible fix is upgrading to v2
|
||||
// Not sure if that has better performance
|
||||
key={path}
|
||||
label={
|
||||
path === '/subscriptions' && unreadSubscriptionTotal
|
||||
? `${label} (${unreadSubscriptionTotal})`
|
||||
: label
|
||||
}
|
||||
{!!subLinks.length &&
|
||||
active && (
|
||||
<ul key="0" className="navigation__link-items">
|
||||
{subLinks.map(({ active: subLinkActive, label: subLabel, path: subPath }) => (
|
||||
<li
|
||||
className={classnames('navigation__link-item', {
|
||||
'navigation__link-item--active': subLinkActive,
|
||||
})}
|
||||
key={subPath}
|
||||
>
|
||||
{subPath ? (
|
||||
<Button label={subLabel} navigate={subPath} />
|
||||
) : (
|
||||
<span>{subLabel}</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
navigate={path}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
<ul>
|
||||
<li className="navigation__link navigation__link--title">Account</li>
|
||||
{navLinks.secondary.map(this.renderNavLink)}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SideBar;
|
||||
|
|
|
@ -82,7 +82,7 @@ class SocialShare extends React.PureComponent<Props> {
|
|||
</ToolTip>
|
||||
<ToolTip onComponent body={__('View on Spee.ch')}>
|
||||
<Button
|
||||
icon={ICONS.GLOBE}
|
||||
icon={ICONS.WEB}
|
||||
iconColor="blue"
|
||||
button="alt"
|
||||
label={__('')}
|
||||
|
|
|
@ -32,8 +32,12 @@ class LoadScreen extends React.PureComponent<Props> {
|
|||
{error ? (
|
||||
<Fragment>
|
||||
<h3>{__('Uh oh. Sean must have messed something up. Try refreshing to fix it.')}</h3>
|
||||
<div className="card__actions">
|
||||
<Button label="Refresh" button="alt" onClick={() => window.location.reload()} />
|
||||
<div className="load-screen__actions">
|
||||
<Button
|
||||
label="Refresh"
|
||||
className="btn--load-screen"
|
||||
onClick={() => window.location.reload()}
|
||||
/>
|
||||
</div>
|
||||
<div className="load-screen__help">
|
||||
<p>
|
||||
|
|
|
@ -43,7 +43,7 @@ export default (props: Props) => {
|
|||
return (
|
||||
<Button
|
||||
iconColor="red"
|
||||
icon={isSubscribed ? undefined : ICONS.HEART}
|
||||
icon={isSubscribed ? undefined : ICONS.SUBSCRIPTION}
|
||||
button={buttonStyle || 'alt'}
|
||||
label={subscriptionLabel}
|
||||
onClick={e => {
|
||||
|
|
|
@ -33,7 +33,7 @@ export default class MarkAsRead extends PureComponent<Props> {
|
|||
<Button
|
||||
noPadding
|
||||
button="inverse"
|
||||
icon={ICONS.CHECK_SIMPLE}
|
||||
icon={ICONS.COMPLETE}
|
||||
label={label}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
|
|
|
@ -29,7 +29,7 @@ class TransactionListItem extends React.PureComponent<Props> {
|
|||
if (type === txnTypes.TIP) {
|
||||
return <Button icon={ICONS.UNLOCK} onClick={this.abandonClaim} title={__('Unlock Tip')} />;
|
||||
}
|
||||
return <Button icon={ICONS.TRASH} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
|
||||
return <Button icon={ICONS.DELETE} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
|
||||
}
|
||||
|
||||
abandonClaim() {
|
||||
|
|
|
@ -59,7 +59,7 @@ class TransactionListRecent extends React.PureComponent<Props> {
|
|||
button="primary"
|
||||
navigate="/history"
|
||||
label={__('Full History')}
|
||||
icon={icons.CLOCK}
|
||||
icon={icons.HISTORY}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -118,7 +118,7 @@ class UserVerify extends React.PureComponent<Props> {
|
|||
<Button
|
||||
href="https://chat.lbry.io"
|
||||
button="primary"
|
||||
icon={icons.MESSAGE}
|
||||
icon={icons.CHAT}
|
||||
label={__('Join LBRY Chat')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import ViewOnWebButton from './view';
|
||||
|
||||
export default ViewOnWebButton;
|
|
@ -1,30 +0,0 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
claimId: ?string,
|
||||
claimName: ?string,
|
||||
};
|
||||
|
||||
export default (props: Props) => {
|
||||
const { claimId, claimName } = props;
|
||||
|
||||
if (claimId && claimName) {
|
||||
const speechURL = claimName.startsWith('@')
|
||||
? `${claimName}:${claimId}`
|
||||
: `${claimId}/${claimName}`;
|
||||
|
||||
return (
|
||||
<Button
|
||||
icon={ICONS.GLOBE}
|
||||
button="alt"
|
||||
label={__('Share')}
|
||||
href={`https://spee.ch/${speechURL}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
|
@ -2,7 +2,7 @@
|
|||
import * as icons from 'constants/icons';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import Address from 'component/address';
|
||||
import CopyableText from 'component/copyableText';
|
||||
import QRCode from 'component/common/qr-code';
|
||||
|
||||
type Props = {
|
||||
|
@ -58,7 +58,7 @@ class WalletAddress extends React.PureComponent<Props, State> {
|
|||
</header>
|
||||
|
||||
<div className="card__content">
|
||||
<Address address={receiveAddress} showCopyButton />
|
||||
<CopyableText copyable={receiveAddress} snackMessage={__('Address copied.')} />
|
||||
</div>
|
||||
|
||||
<div className="card__content">
|
||||
|
|
|
@ -43,9 +43,9 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
getSuggestionIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case 'file':
|
||||
return ICONS.LOCAL;
|
||||
return ICONS.FILE;
|
||||
case 'channel':
|
||||
return ICONS.AT_SIGN;
|
||||
return ICONS.CHANNEL;
|
||||
default:
|
||||
return ICONS.SEARCH;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
// React Feather
|
||||
// React Feather icons
|
||||
// https://github.com/carmelopullara/react-feather
|
||||
// Note: Icons should be named for their purpose, rather than the actual icon.
|
||||
// The goal being to reduce multiple uses of the same icon for different purposes.
|
||||
//
|
||||
export const FEATURED = 'Award';
|
||||
export const LOCAL = 'Folder';
|
||||
export const ALERT = 'AlertCircle';
|
||||
|
@ -7,32 +11,32 @@ export const ARROW_LEFT = 'ChevronLeft';
|
|||
export const ARROW_RIGHT = 'ChevronRight';
|
||||
export const DOWNLOAD = 'Download';
|
||||
export const UPLOAD = 'UploadCloud';
|
||||
export const PUBLISHED = 'Cloud';
|
||||
export const CLOSE = 'X';
|
||||
export const EDIT = 'Edit3';
|
||||
export const TRASH = 'Trash';
|
||||
export const DELETE = 'Trash';
|
||||
export const REPORT = 'Flag';
|
||||
export const OPEN = 'BookOpen';
|
||||
export const HELP = 'HelpCircle';
|
||||
export const MESSAGE = 'MessageCircle';
|
||||
export const SEND = 'Send';
|
||||
export const CHAT = 'MessageCircle';
|
||||
export const SEARCH = 'Search';
|
||||
export const COMPASS = 'Compass';
|
||||
export const AT_SIGN = 'AtSign';
|
||||
export const CHANNEL = 'AtSign';
|
||||
export const REFRESH = 'RefreshCw';
|
||||
export const CLOCK = 'Clock';
|
||||
export const HISTORY = 'Clock';
|
||||
export const HOME = 'Home';
|
||||
export const PHONE = 'Phone';
|
||||
export const CHECK = 'CheckCircle';
|
||||
export const HEART = 'Heart';
|
||||
export const COMPLETE = 'Check';
|
||||
export const COMPLETED = 'CheckCircle';
|
||||
export const SUBSCRIPTION = 'Heart';
|
||||
export const UNLOCK = 'Unlock';
|
||||
export const CHECK_SIMPLE = 'Check';
|
||||
export const GLOBE = 'Globe';
|
||||
export const EXTERNAL_LINK = 'ExternalLink';
|
||||
export const GIFT = 'Gift';
|
||||
export const EYE = 'Eye';
|
||||
export const WEB = 'Globe';
|
||||
export const SHARE = 'Share2';
|
||||
export const EXTERNAL = 'ExternalLink';
|
||||
export const TIP = 'Gift';
|
||||
export const VIEW = 'Eye';
|
||||
export const PLAY = 'Play';
|
||||
export const FACEBOOK = 'Facebook';
|
||||
export const TWITTER = 'Twitter';
|
||||
export const CREDIT_CARD = 'CreditCard';
|
||||
export const WALLET = 'CreditCard';
|
||||
export const SETTINGS = 'Settings';
|
||||
export const USERS = 'Users';
|
||||
export const INVITE = 'Users';
|
||||
export const FILE = 'File';
|
||||
|
|
20
src/renderer/constants/pages.js
Normal file
20
src/renderer/constants/pages.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
export const AUTH = 'auth';
|
||||
export const BACKUP = 'backup';
|
||||
export const CHANNEL = 'channel';
|
||||
export const DISCOVER = 'discover';
|
||||
export const DOWNLOADED = 'downloaded';
|
||||
export const HELP = 'help';
|
||||
export const HISTORY = 'history';
|
||||
export const INVITE = 'invite';
|
||||
export const PUBLISH = 'publish';
|
||||
export const PUBLISHED = 'published';
|
||||
export const GET_CREDITS = 'getcredits';
|
||||
export const REPORT = 'report';
|
||||
export const REWARDS = 'rewards';
|
||||
export const SEND = 'send';
|
||||
export const SETTINGS = 'settings';
|
||||
export const SHOW = 'show';
|
||||
export const WALLET = 'wallet';
|
||||
export const SUBSCRIPTIONS = 'subscriptions';
|
||||
export const SEARCH = 'search';
|
||||
export const USER_HISTORY = 'user_history';
|
|
@ -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 INVITE_ACKNOWLEDGED = 'invite_acknowledged';
|
||||
export const LANGUAGE = 'language';
|
||||
export const SHOW_NSFW = 'showNsfw';
|
||||
export const SHOW_UNAVAILABLE = 'showUnavailable';
|
||||
|
|
|
@ -95,7 +95,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
<SubscribeButton uri={`lbry://${permanentUrl}`} channelName={name} />
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.GLOBE}
|
||||
icon={icons.SHARE}
|
||||
label={__('Share Channel')}
|
||||
onClick={() =>
|
||||
openModal(MODALS.SOCIAL_SHARE, { uri, speechShareable: true, isChannel: true })
|
||||
|
|
|
@ -216,14 +216,14 @@ class FilePage extends React.Component<Props> {
|
|||
{!claimIsMine && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.GIFT}
|
||||
icon={icons.TIP}
|
||||
label={__('Send a tip')}
|
||||
onClick={() => openModal(MODALS.SEND_TIP, { uri })}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.GLOBE}
|
||||
icon={icons.SHARE}
|
||||
label={__('Share')}
|
||||
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, speechShareable })}
|
||||
/>
|
||||
|
|
|
@ -151,7 +151,7 @@ class HelpPage extends React.PureComponent<Props, State> {
|
|||
<Button
|
||||
button="primary"
|
||||
label={__('Join Our Chat')}
|
||||
icon={icons.MESSAGE}
|
||||
icon={icons.CHAT}
|
||||
href="https://chat.lbry.io"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
doFetchInviteStatus,
|
||||
selectUserInviteStatusFailed,
|
||||
selectUserInviteStatusIsPending,
|
||||
} from 'lbryinc';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import InvitePage from './view';
|
||||
|
||||
const select = state => ({
|
||||
isFailed: selectUserInviteStatusFailed(state),
|
||||
isPending: selectUserInviteStatusIsPending(state),
|
||||
inviteAcknowledged: makeSelectClientSetting(state)(SETTINGS.INVITE_ACKNOWLEDGED),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchInviteStatus: () => dispatch(doFetchInviteStatus()),
|
||||
acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import InviteNew from 'component/inviteNew';
|
||||
import InviteList from 'component/inviteList';
|
||||
import Page from 'component/page';
|
||||
|
||||
class InvitePage extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.props.fetchInviteStatus();
|
||||
type Props = {
|
||||
isPending: boolean,
|
||||
isFailed: boolean,
|
||||
inviteAcknowledged: boolean,
|
||||
acknowledgeInivte: () => void,
|
||||
fetchInviteStatus: () => void,
|
||||
};
|
||||
|
||||
class InvitePage extends React.PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const { fetchInviteStatus, inviteAcknowledged, acknowledgeInivte } = this.props;
|
||||
fetchInviteStatus();
|
||||
|
||||
if (!inviteAcknowledged) {
|
||||
acknowledgeInivte();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -43,17 +43,18 @@ export default (props: Props) => {
|
|||
<Button button="primary" label={__('Explore')} onClick={doShowSuggestedSubs} />
|
||||
</div>
|
||||
)}
|
||||
{showSuggested && numberOfSubscriptions > 0 && (
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={onFinish}
|
||||
label={`${__('View your')} ${numberOfSubscriptions} ${
|
||||
numberOfSubscriptions > 1 ? __('subscribed channels') : __('subscribed channel')
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showSuggested &&
|
||||
numberOfSubscriptions > 0 && (
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={onFinish}
|
||||
label={`${__('View your')} ${numberOfSubscriptions} ${
|
||||
numberOfSubscriptions > 1 ? __('subscribed channels') : __('subscribed channel')
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showSuggested && !loadingSuggested && <SuggestedSubscriptions />}
|
||||
|
|
|
@ -9,10 +9,10 @@ import FileList from 'component/fileList';
|
|||
import { FormField } from 'component/common/form';
|
||||
import FileCard from 'component/fileCard';
|
||||
import { parseURI } from 'lbry-redux';
|
||||
import Native from 'native';
|
||||
import SuggestedSubscriptions from 'component/subscribeSuggested';
|
||||
import MarkAsRead from 'component/subscribeMarkAsRead';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
import Yrbl from 'component/common/yrbl';
|
||||
|
||||
type Props = {
|
||||
viewMode: ViewMode,
|
||||
|
@ -79,17 +79,11 @@ export default (props: Props) => {
|
|||
|
||||
{!hasSubscriptions && (
|
||||
<Fragment>
|
||||
<div className="yrbl-wrap">
|
||||
<img
|
||||
alt="Sad gerbil"
|
||||
className="subscriptions__gerbil"
|
||||
src={Native.imagePath('gerbil-sad.png')}
|
||||
/>
|
||||
<div className="card__content">
|
||||
<h2 className="card__title">{__('Oh no! What happened to your subscriptions?')}</h2>
|
||||
<p className="card__subtitle">{__('These channels look pretty cool.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Yrbl
|
||||
type="sad"
|
||||
title={__('Oh no! What happened to your subscriptions?')}
|
||||
subtitle={__('These channels look pretty cool.')}
|
||||
/>
|
||||
<SuggestedSubscriptions />
|
||||
</Fragment>
|
||||
)}
|
||||
|
@ -133,17 +127,10 @@ export default (props: Props) => {
|
|||
})
|
||||
) : (
|
||||
<Fragment>
|
||||
<div className="yrbl-wrap">
|
||||
<img
|
||||
alt="Friendly gerbil"
|
||||
className="subscriptions__gerbil"
|
||||
src={Native.imagePath('gerbil-happy.png')}
|
||||
/>
|
||||
<div className="card__content">
|
||||
<h2 className="card__title">{__('All caught up!')}</h2>
|
||||
<p className="card__subtitle">{__('You might like the channels below.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Yrbl
|
||||
title={__('All caught up!')}
|
||||
subtitle={__('You might like the channels below.')}
|
||||
/>
|
||||
<SuggestedSubscriptions />
|
||||
</Fragment>
|
||||
)}
|
||||
|
|
|
@ -25,6 +25,7 @@ const defaultState = {
|
|||
SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED,
|
||||
false
|
||||
),
|
||||
[SETTINGS.INVITE_ACKNOWLEDGED]: getLocalStorageSetting(SETTINGS.INVITE_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'),
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { createSelector } from 'reselect';
|
||||
import { selectCurrentPage, selectHistoryStack } from 'lbry-redux';
|
||||
import * as icons from 'constants/icons';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
|
||||
export const selectState = state => state.app || {};
|
||||
|
||||
|
@ -97,18 +100,29 @@ export const selectUpgradeTimer = createSelector(selectState, state => state.che
|
|||
export const selectNavLinks = createSelector(
|
||||
selectCurrentPage,
|
||||
selectHistoryStack,
|
||||
(currentPage, historyStack) => {
|
||||
makeSelectClientSetting(SETTINGS.FIRST_RUN_COMPLETED),
|
||||
makeSelectClientSetting(SETTINGS.INVITE_ACKNOWLEDGED),
|
||||
(currentPage, historyStack, firstRunCompleted, inviteAcknowledged) => {
|
||||
// Determine if any links should show a tooltip for a guided tour
|
||||
// It will only show one at a time, in the order they are set.
|
||||
const guidedTourItem = [
|
||||
{
|
||||
page: PAGES.INVITE,
|
||||
hasBeenCompleted: inviteAcknowledged,
|
||||
guide: 'Check this out!',
|
||||
},
|
||||
// Add more items below for tooltip guides that will happen after a user has completed the invite guide
|
||||
].filter(({ hasBeenCompleted }) => !hasBeenCompleted)[0];
|
||||
|
||||
const isWalletPage = page =>
|
||||
page === 'wallet' ||
|
||||
page === 'send' ||
|
||||
page === 'getcredits' ||
|
||||
page === 'rewards' ||
|
||||
page === 'history' ||
|
||||
page === 'backup';
|
||||
|
||||
const isMyLbryPage = page =>
|
||||
page === 'downloaded' || page === 'published' || page === 'user_history';
|
||||
page === PAGES.WALLET ||
|
||||
page === PAGES.SEND ||
|
||||
page === PAGES.GET_CREDITS ||
|
||||
page === PAGES.REWARDS ||
|
||||
page === PAGES.HISTORY ||
|
||||
page === PAGES.BACKUP;
|
||||
|
||||
const isCurrentlyWalletPage = isWalletPage(currentPage);
|
||||
const previousStack = historyStack.slice().reverse();
|
||||
|
||||
const getPreviousSubLinkPath = checkIfValidPage => {
|
||||
|
@ -127,124 +141,92 @@ export const selectNavLinks = createSelector(
|
|||
|
||||
// Gets the last active sublink in a section
|
||||
const getActiveSublink = category => {
|
||||
if (category === 'wallet') {
|
||||
if (category === PAGES.WALLET) {
|
||||
const previousPath = getPreviousSubLinkPath(isWalletPage);
|
||||
return previousPath || '/wallet';
|
||||
} else if (category === 'myLbry') {
|
||||
const previousPath = getPreviousSubLinkPath(isMyLbryPage);
|
||||
return previousPath || '/downloaded';
|
||||
return previousPath || `/${PAGES.WALLET}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const isCurrentlyWalletPage = isWalletPage(currentPage);
|
||||
const isCurrentlyMyLbryPage = isMyLbryPage(currentPage);
|
||||
// Is this path the first unacknowledged item in the guided tour list
|
||||
const getGuideIfNecessary = page => {
|
||||
if (!firstRunCompleted) {
|
||||
return null;
|
||||
}
|
||||
return guidedTourItem && guidedTourItem.page === page ? guidedTourItem.guide : null;
|
||||
};
|
||||
|
||||
const buildLink = (label, page) => ({
|
||||
label,
|
||||
path: `/${page}`,
|
||||
active: currentPage === page,
|
||||
guide: getGuideIfNecessary(page),
|
||||
});
|
||||
|
||||
const walletSubLinks = [
|
||||
{
|
||||
label: 'Overview',
|
||||
path: '/wallet',
|
||||
active: currentPage === 'wallet',
|
||||
...buildLink('Overview', PAGES.WALLET),
|
||||
},
|
||||
{
|
||||
label: 'Send & Receive',
|
||||
path: '/send',
|
||||
active: currentPage === 'send',
|
||||
...buildLink('Send & Receive', PAGES.SEND),
|
||||
},
|
||||
{
|
||||
label: 'Transactions',
|
||||
path: '/history',
|
||||
active: currentPage === 'history',
|
||||
...buildLink('Transactions', PAGES.HISTORY),
|
||||
},
|
||||
{
|
||||
label: 'Get Credits',
|
||||
path: '/getcredits',
|
||||
active: currentPage === 'getcredits',
|
||||
...buildLink('Get Credits', PAGES.GET_CREDITS),
|
||||
},
|
||||
{
|
||||
label: 'Rewards',
|
||||
path: '/rewards',
|
||||
active: currentPage === 'rewards',
|
||||
...buildLink('Rewards', PAGES.REWARDS),
|
||||
},
|
||||
{
|
||||
label: 'Backup',
|
||||
path: '/backup',
|
||||
active: currentPage === 'backup',
|
||||
},
|
||||
];
|
||||
|
||||
const myLbrySubLinks = [
|
||||
{
|
||||
label: 'Downloads',
|
||||
path: '/downloaded',
|
||||
active: currentPage === 'downloaded',
|
||||
},
|
||||
{
|
||||
label: 'Publishes',
|
||||
path: '/published',
|
||||
active: currentPage === 'published',
|
||||
},
|
||||
{
|
||||
label: 'History',
|
||||
path: '/user_history',
|
||||
active: currentPage === 'user_history',
|
||||
...buildLink('Backup', PAGES.BACKUP),
|
||||
},
|
||||
];
|
||||
|
||||
const navLinks = {
|
||||
primary: [
|
||||
{
|
||||
label: 'Explore',
|
||||
path: '/discover',
|
||||
active: currentPage === 'discover',
|
||||
icon: icons.HOME,
|
||||
...buildLink('Explore', PAGES.DISCOVER),
|
||||
icon: ICONS.HOME,
|
||||
},
|
||||
{
|
||||
label: 'Subscriptions',
|
||||
path: '/subscriptions',
|
||||
active: currentPage === 'subscriptions',
|
||||
icon: icons.HEART,
|
||||
...buildLink('Subscriptions', PAGES.SUBSCRIPTIONS),
|
||||
icon: ICONS.SUBSCRIPTION,
|
||||
},
|
||||
],
|
||||
secondary: [
|
||||
{
|
||||
label: 'Wallet',
|
||||
icon: icons.CREDIT_CARD,
|
||||
icon: ICONS.WALLET,
|
||||
subLinks: walletSubLinks,
|
||||
path: isCurrentlyWalletPage ? '/wallet' : getActiveSublink('wallet'),
|
||||
path: isCurrentlyWalletPage ? `/${PAGES.WALLET}` : getActiveSublink(PAGES.WALLET),
|
||||
active: isWalletPage(currentPage),
|
||||
},
|
||||
{
|
||||
label: 'My LBRY',
|
||||
icon: icons.LOCAL,
|
||||
subLinks: myLbrySubLinks,
|
||||
path: isCurrentlyMyLbryPage ? '/downloaded' : getActiveSublink('myLbry'),
|
||||
active: isMyLbryPage(currentPage),
|
||||
...buildLink('Invite', PAGES.INVITE),
|
||||
icon: ICONS.INVITE,
|
||||
},
|
||||
{
|
||||
label: 'Invite',
|
||||
icon: icons.USERS,
|
||||
path: '/invite',
|
||||
active: currentPage === 'invite',
|
||||
...buildLink('Downloads', PAGES.DOWNLOADED),
|
||||
icon: ICONS.LOCAL,
|
||||
},
|
||||
{
|
||||
label: 'Publish',
|
||||
icon: icons.UPLOAD,
|
||||
path: '/publish',
|
||||
active: currentPage === 'publish',
|
||||
...buildLink('Publishes', PAGES.PUBLISHED),
|
||||
icon: ICONS.PUBLISHED,
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: icons.SETTINGS,
|
||||
path: '/settings',
|
||||
active: currentPage === 'settings',
|
||||
...buildLink('History', PAGES.USER_HISTORY),
|
||||
icon: ICONS.HISTORY,
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
path: '/help',
|
||||
icon: icons.HELP,
|
||||
active: currentPage === 'help',
|
||||
...buildLink('Settings', PAGES.SETTINGS),
|
||||
icon: ICONS.SETTINGS,
|
||||
},
|
||||
{
|
||||
...buildLink('Help', PAGES.HELP),
|
||||
icon: ICONS.HELP,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -68,3 +68,8 @@
|
|||
font-size: 14px;
|
||||
padding-top: $spacing-vertical;
|
||||
}
|
||||
|
||||
.load-screen__actions {
|
||||
font-size: 1.2em;
|
||||
margin-top: var(--spacing-vertical-medium);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,8 @@
|
|||
// The gerbil is tied to subscriptions currently, but this style should move to it's own file once
|
||||
// the gerbil is added in more places with different layouts
|
||||
.subscriptions__gerbil {
|
||||
}
|
||||
|
||||
.subscriptions__suggested {
|
||||
animation: expand 0.2s;
|
||||
left: -2rem;
|
||||
position: relative;
|
||||
width: calc(100% + 4rem);
|
||||
}
|
||||
|
||||
.yrbl-wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
margin-bottom: var(--spacing-vertical-large);
|
||||
|
||||
img {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
.tooltip {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
&:not(:hover) {
|
||||
.tooltip__body {
|
||||
visibility: hidden;
|
||||
}
|
||||
.tooltip__body {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -15,17 +14,20 @@
|
|||
}
|
||||
|
||||
.tooltip__body {
|
||||
background-color: $lbry-gray-5;
|
||||
border-radius: 8px;
|
||||
color: $lbry-white;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: $lbry-black;
|
||||
font-weight: 400;
|
||||
padding: var(--spacing-vertical-small);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
white-space: pre-wrap;
|
||||
width: 200px;
|
||||
z-index: 1;
|
||||
box-shadow: 5px 5px 5px rgba($lbry-black, 0.15);
|
||||
|
||||
html[data-theme='dark'] & {
|
||||
border: 1px solid #2f2f2f;
|
||||
background-color: $lbry-gray-1;
|
||||
}
|
||||
|
||||
&::after {
|
||||
width: 0;
|
||||
|
@ -37,12 +39,18 @@
|
|||
position: absolute;
|
||||
}
|
||||
|
||||
&--short {
|
||||
&.tooltip__body--short {
|
||||
width: 130px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip--always-visible {
|
||||
.tooltip__body {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip--bottom .tooltip__body {
|
||||
top: 90%;
|
||||
left: 50%;
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
.yrbl-wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
margin-bottom: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
.yrbl {
|
||||
height: 300px;
|
||||
margin-right: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
.yrbl--first-run {
|
||||
align-self: center;
|
||||
height: 200px;
|
||||
height: 250px;
|
||||
width: auto;
|
||||
margin: 0 var(--spacing-vertical-large);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue