purchases page, cleanup on pages with <ClaimList />
This commit is contained in:
parent
ca5f54cbfd
commit
919f82ba94
32 changed files with 366 additions and 142 deletions
|
@ -132,7 +132,7 @@
|
||||||
"imagesloaded": "^4.1.4",
|
"imagesloaded": "^4.1.4",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#259317250af62391718ac0cb8b8e25f172dc4223",
|
"lbry-redux": "lbryio/lbry-redux#cd9c15567f2934ddc82de364d88b378ff04d5571",
|
||||||
"lbryinc": "lbryio/lbryinc#cc62a4eec10845cc0b31da7d0f27287cfa7c4866",
|
"lbryinc": "lbryio/lbryinc#cc62a4eec10845cc0b31da7d0f27287cfa7c4866",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
|
|
|
@ -26,7 +26,6 @@ type Props = {
|
||||||
// If using the default header, this is a unique ID needed to persist the state of the filter setting
|
// If using the default header, this is a unique ID needed to persist the state of the filter setting
|
||||||
persistedStorageKey?: string,
|
persistedStorageKey?: string,
|
||||||
showHiddenByUser: boolean,
|
showHiddenByUser: boolean,
|
||||||
headerLabel?: string | Node,
|
|
||||||
showUnresolvedClaims?: boolean,
|
showUnresolvedClaims?: boolean,
|
||||||
renderProperties: ?(Claim) => Node,
|
renderProperties: ?(Claim) => Node,
|
||||||
includeSupportAction?: boolean,
|
includeSupportAction?: boolean,
|
||||||
|
@ -51,7 +50,6 @@ export default function ClaimList(props: Props) {
|
||||||
page,
|
page,
|
||||||
id,
|
id,
|
||||||
showHiddenByUser,
|
showHiddenByUser,
|
||||||
headerLabel,
|
|
||||||
showUnresolvedClaims,
|
showUnresolvedClaims,
|
||||||
renderProperties,
|
renderProperties,
|
||||||
includeSupportAction,
|
includeSupportAction,
|
||||||
|
@ -105,12 +103,10 @@ export default function ClaimList(props: Props) {
|
||||||
<section
|
<section
|
||||||
className={classnames('claim-list', {
|
className={classnames('claim-list', {
|
||||||
'claim-list--small': type === 'small',
|
'claim-list--small': type === 'small',
|
||||||
'claim-list--card-body': isCardBody,
|
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{header !== false && (
|
{header !== false && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{headerLabel && <label className="claim-list__header-label">{headerLabel}</label>}
|
|
||||||
{header && (
|
{header && (
|
||||||
<div className={classnames('claim-list__header', { 'section__title--small': type === 'small' })}>
|
<div className={classnames('claim-list__header', { 'section__title--small': type === 'small' })}>
|
||||||
{header}
|
{header}
|
||||||
|
@ -139,6 +135,7 @@ export default function ClaimList(props: Props) {
|
||||||
<ul
|
<ul
|
||||||
className={classnames('ul--no-style', {
|
className={classnames('ul--no-style', {
|
||||||
card: !isCardBody,
|
card: !isCardBody,
|
||||||
|
'claim-list--card-body': isCardBody,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{sortedUris.map((uri, index) => (
|
{sortedUris.map((uri, index) => (
|
||||||
|
|
|
@ -13,6 +13,7 @@ import ClaimPreview from 'component/claimPreview';
|
||||||
import { toCapitalCase } from 'util/string';
|
import { toCapitalCase } from 'util/string';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
|
import Card from 'component/common/card';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uris: Array<string>,
|
uris: Array<string>,
|
||||||
|
@ -595,13 +596,18 @@ function ClaimListDiscover(props: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
{headerLabel && <label className="claim-list__header-label">{headerLabel}</label>}
|
||||||
|
<Card
|
||||||
|
title={header || defaultHeader}
|
||||||
|
titleActions={meta && <div className="card__actions--inline">{meta}</div>}
|
||||||
|
isBodyList
|
||||||
|
body={
|
||||||
|
<>
|
||||||
<ClaimList
|
<ClaimList
|
||||||
|
isCardBody
|
||||||
id={claimSearchCacheQuery}
|
id={claimSearchCacheQuery}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
uris={claimSearchResult}
|
uris={claimSearchResult}
|
||||||
header={header || defaultHeader}
|
|
||||||
headerLabel={headerLabel}
|
|
||||||
headerAltControls={meta}
|
|
||||||
onScrollBottom={handleScrollBottom}
|
onScrollBottom={handleScrollBottom}
|
||||||
page={page}
|
page={page}
|
||||||
pageSize={CS.PAGE_SIZE}
|
pageSize={CS.PAGE_SIZE}
|
||||||
|
@ -611,14 +617,11 @@ function ClaimListDiscover(props: Props) {
|
||||||
hideBlock={hideBlock}
|
hideBlock={hideBlock}
|
||||||
injectedItem={injectedItem}
|
injectedItem={injectedItem}
|
||||||
/>
|
/>
|
||||||
|
{loading &&
|
||||||
{loading && (
|
new Array(pageSize || CS.PAGE_SIZE).fill(1).map((x, i) => <ClaimPreview key={i} placeholder="loading" />)}
|
||||||
<div className="card">
|
</>
|
||||||
{new Array(pageSize || CS.PAGE_SIZE).fill(1).map((x, i) => (
|
}
|
||||||
<ClaimPreview key={i} placeholder="loading" />
|
/>
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
selectChannelIsBlocked,
|
selectChannelIsBlocked,
|
||||||
doFileGet,
|
doFileGet,
|
||||||
makeSelectReflectingClaimForUri,
|
makeSelectReflectingClaimForUri,
|
||||||
|
makeSelectClaimWasPurchased,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
|
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
|
||||||
import { selectShowMatureContent } from 'redux/selectors/settings';
|
import { selectShowMatureContent } from 'redux/selectors/settings';
|
||||||
|
@ -36,6 +37,7 @@ const select = (state, props) => ({
|
||||||
channelIsBlocked: props.uri && selectChannelIsBlocked(props.uri)(state),
|
channelIsBlocked: props.uri && selectChannelIsBlocked(props.uri)(state),
|
||||||
isSubscribed: props.uri && makeSelectIsSubscribed(props.uri, true)(state),
|
isSubscribed: props.uri && makeSelectIsSubscribed(props.uri, true)(state),
|
||||||
streamingUrl: props.uri && makeSelectStreamingUrlForUriWebProxy(props.uri)(state),
|
streamingUrl: props.uri && makeSelectStreamingUrlForUriWebProxy(props.uri)(state),
|
||||||
|
wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default function ClaimTags(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('file-properties', { 'file-properties--large': type === 'large' })}>
|
<div className={classnames('file-properties--small', { 'file-properties--large': type === 'large' })}>
|
||||||
{tagsToDisplay.map(tag => (
|
{tagsToDisplay.map(tag => (
|
||||||
<Tag key={tag} title={tag} name={tag} />
|
<Tag key={tag} title={tag} name={tag} />
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -13,6 +13,7 @@ type Props = {
|
||||||
showLBC?: boolean,
|
showLBC?: boolean,
|
||||||
fee?: boolean,
|
fee?: boolean,
|
||||||
badge?: boolean,
|
badge?: boolean,
|
||||||
|
className?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CreditAmount extends React.PureComponent<Props> {
|
class CreditAmount extends React.PureComponent<Props> {
|
||||||
|
@ -26,7 +27,18 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { amount, precision, showFullPrice, showFree, showPlus, isEstimate, fee, showLBC, badge } = this.props;
|
const {
|
||||||
|
amount,
|
||||||
|
precision,
|
||||||
|
showFullPrice,
|
||||||
|
showFree,
|
||||||
|
showPlus,
|
||||||
|
isEstimate,
|
||||||
|
fee,
|
||||||
|
showLBC,
|
||||||
|
badge,
|
||||||
|
className,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const minimumRenderableAmount = 10 ** (-1 * precision);
|
const minimumRenderableAmount = 10 ** (-1 * precision);
|
||||||
const fullPrice = formatFullPrice(amount, 2);
|
const fullPrice = formatFullPrice(amount, 2);
|
||||||
|
@ -64,13 +76,13 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
title={fullPrice}
|
title={fullPrice}
|
||||||
className={classnames({
|
className={classnames(className, {
|
||||||
badge,
|
badge,
|
||||||
'badge--cost': badge && amount > 0,
|
'badge--cost': badge && amount > 0,
|
||||||
'badge--free': badge && isFree,
|
'badge--free': badge && isFree,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{amountText}
|
<span>{amountText}</span>
|
||||||
|
|
||||||
{isEstimate ? (
|
{isEstimate ? (
|
||||||
<span className="credit-amount__estimate" title={__('This is an estimate and does not include data fees')}>
|
<span className="credit-amount__estimate" title={__('This is an estimate and does not include data fees')}>
|
||||||
|
|
|
@ -618,4 +618,9 @@ export const icons = {
|
||||||
viewBox: '0 0 60 60',
|
viewBox: '0 0 60 60',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
[ICONS.PURCHASED]: buildIcon(
|
||||||
|
<g>
|
||||||
|
<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ type Props = {
|
||||||
inheritStyle?: boolean,
|
inheritStyle?: boolean,
|
||||||
showLBC?: boolean,
|
showLBC?: boolean,
|
||||||
hideFree?: boolean, // hide the file price if it's free
|
hideFree?: boolean, // hide the file price if it's free
|
||||||
|
className?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePrice extends React.PureComponent<Props> {
|
class FilePrice extends React.PureComponent<Props> {
|
||||||
|
@ -38,7 +39,7 @@ class FilePrice extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { costInfo, showFullPrice, badge, inheritStyle, showLBC, hideFree } = this.props;
|
const { costInfo, showFullPrice, badge, inheritStyle, showLBC, hideFree, className } = this.props;
|
||||||
if (costInfo && (!costInfo.cost || (!costInfo.cost && hideFree))) {
|
if (costInfo && (!costInfo.cost || (!costInfo.cost && hideFree))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +53,7 @@ class FilePrice extends React.PureComponent<Props> {
|
||||||
amount={costInfo.cost}
|
amount={costInfo.cost}
|
||||||
isEstimate={!costInfo.includesData}
|
isEstimate={!costInfo.includesData}
|
||||||
showFullPrice={showFullPrice}
|
showFullPrice={showFullPrice}
|
||||||
|
className={className}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectFilePartlyDownloaded, makeSelectClaimIsMine } from 'lbry-redux';
|
import { makeSelectFilePartlyDownloaded, makeSelectClaimIsMine, makeSelectClaimWasPurchased } from 'lbry-redux';
|
||||||
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
||||||
import FileProperties from './view';
|
import FileProperties from './view';
|
||||||
|
|
||||||
|
@ -8,9 +8,7 @@ const select = (state, props) => ({
|
||||||
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
|
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
|
||||||
isNew: makeSelectIsNew(props.uri)(state),
|
isNew: makeSelectIsNew(props.uri)(state),
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
|
claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(select, null)(FileProperties);
|
||||||
select,
|
|
||||||
null
|
|
||||||
)(FileProperties);
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as icons from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
@ -14,18 +14,28 @@ type Props = {
|
||||||
isSubscribed: boolean,
|
isSubscribed: boolean,
|
||||||
isNew: boolean,
|
isNew: boolean,
|
||||||
small: boolean,
|
small: boolean,
|
||||||
|
claimWasPurchased: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FileProperties(props: Props) {
|
export default function FileProperties(props: Props) {
|
||||||
const { uri, downloaded, claimIsMine, isSubscribed, small = false } = props;
|
const { uri, downloaded, claimIsMine, claimWasPurchased, isSubscribed, small = false } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('file-properties', { 'file-properties--small': small })}>
|
<div
|
||||||
<FilePrice hideFree uri={uri} />
|
className={classnames('file-properties', {
|
||||||
|
'file-properties--small': small,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<VideoDuration uri={uri} />
|
<VideoDuration uri={uri} />
|
||||||
<FileType uri={uri} />
|
<FileType uri={uri} />
|
||||||
{isSubscribed && <Icon tooltip icon={icons.SUBSCRIBE} />}
|
{isSubscribed && <Icon tooltip icon={ICONS.SUBSCRIBE} />}
|
||||||
{!claimIsMine && downloaded && <Icon tooltip icon={icons.LIBRARY} />}
|
{!claimIsMine && downloaded && <Icon tooltip icon={ICONS.LIBRARY} />}
|
||||||
|
{claimWasPurchased ? (
|
||||||
|
<span className="file-properties__purchased">
|
||||||
|
<Icon icon={ICONS.PURCHASED} />
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<FilePrice hideFree uri={uri} badge={false} className="file-properties__not-purchased" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import DiscoverPage from 'page/discover';
|
||||||
import HomePage from 'page/home';
|
import HomePage from 'page/home';
|
||||||
import InvitedPage from 'page/invited';
|
import InvitedPage from 'page/invited';
|
||||||
import RewardsPage from 'page/rewards';
|
import RewardsPage from 'page/rewards';
|
||||||
import FileListDownloaded from 'page/fileListDownloaded';
|
|
||||||
import FileListPublished from 'page/fileListPublished';
|
import FileListPublished from 'page/fileListPublished';
|
||||||
import InvitePage from 'page/invite';
|
import InvitePage from 'page/invite';
|
||||||
import SearchPage from 'page/search';
|
import SearchPage from 'page/search';
|
||||||
|
@ -177,7 +176,6 @@ function AppRouter(props: Props) {
|
||||||
<Route path={`/$/${PAGES.INVITE}/:referrer`} exact component={InvitedPage} />
|
<Route path={`/$/${PAGES.INVITE}/:referrer`} exact component={InvitedPage} />
|
||||||
|
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.INVITE}`} component={InvitePage} />
|
<PrivateRoute {...props} path={`/$/${PAGES.INVITE}`} component={InvitePage} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.DOWNLOADED}`} component={FileListDownloaded} />
|
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.PUBLISHED}`} component={FileListPublished} />
|
<PrivateRoute {...props} path={`/$/${PAGES.PUBLISHED}`} component={FileListPublished} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.CREATOR_DASHBOARD}`} component={CreatorDashboard} />
|
<PrivateRoute {...props} path={`/$/${PAGES.CREATOR_DASHBOARD}`} component={CreatorDashboard} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.PUBLISH}`} component={PublishPage} />
|
<PrivateRoute {...props} path={`/$/${PAGES.PUBLISH}`} component={PublishPage} />
|
||||||
|
|
|
@ -3,7 +3,7 @@ export const MINIMUM_PUBLISH_BID = 0.00001;
|
||||||
export const CHANNEL_ANONYMOUS = 'anonymous';
|
export const CHANNEL_ANONYMOUS = 'anonymous';
|
||||||
export const CHANNEL_NEW = 'new';
|
export const CHANNEL_NEW = 'new';
|
||||||
export const PAGE_SIZE = 20;
|
export const PAGE_SIZE = 20;
|
||||||
export const PUBLISHES_PAGE_SIZE = 10;
|
export const MY_CLAIMS_PAGE_SIZE = 10;
|
||||||
export const PAGE_PARAM = 'page';
|
export const PAGE_PARAM = 'page';
|
||||||
export const PAGE_SIZE_PARAM = 'page_size';
|
export const PAGE_SIZE_PARAM = 'page_size';
|
||||||
|
|
||||||
|
|
|
@ -99,3 +99,4 @@ export const VALIDATED = 'Check';
|
||||||
export const SLIDERS = 'Sliders';
|
export const SLIDERS = 'Sliders';
|
||||||
export const SCIENCE = 'Science';
|
export const SCIENCE = 'Science';
|
||||||
export const ANALYTICS = 'BarChart2';
|
export const ANALYTICS = 'BarChart2';
|
||||||
|
export const PURCHASED = 'Key';
|
||||||
|
|
|
@ -6,7 +6,6 @@ exports.BACKUP = 'backup';
|
||||||
exports.CHANNEL = 'channel';
|
exports.CHANNEL = 'channel';
|
||||||
exports.DISCOVER = 'discover';
|
exports.DISCOVER = 'discover';
|
||||||
exports.HOME = 'home';
|
exports.HOME = 'home';
|
||||||
exports.DOWNLOADED = 'downloaded';
|
|
||||||
exports.HELP = 'help';
|
exports.HELP = 'help';
|
||||||
exports.LIBRARY = 'library';
|
exports.LIBRARY = 'library';
|
||||||
exports.INVITE = 'invite';
|
exports.INVITE = 'invite';
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FilePrice from 'component/filePrice';
|
import FilePrice from 'component/filePrice';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
import Card from 'component/common/card';
|
||||||
|
import I18nMessage from 'component/i18nMessage';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
|
@ -30,22 +33,29 @@ class ModalAffirmPurchase extends React.PureComponent<Props> {
|
||||||
uri,
|
uri,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const modalTitle = __('Confirm Purchase');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal type="card" isOpen contentLabel={modalTitle} onAborted={cancelPurchase}>
|
||||||
type="confirm"
|
<Card
|
||||||
isOpen
|
title={modalTitle}
|
||||||
title={__('Confirm Purchase')}
|
subtitle={
|
||||||
contentLabel={__('Confirm Purchase')}
|
<I18nMessage
|
||||||
onConfirmed={this.onAffirmPurchase}
|
tokens={{
|
||||||
onAborted={cancelPurchase}
|
claim_title: <strong>{title ? `"${title}"` : uri}</strong>,
|
||||||
|
amount: <FilePrice uri={uri} showFullPrice inheritStyle />,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<p className="section__subtitle">
|
This will purchase %claim_title% for %amount%.
|
||||||
{__('This will purchase')} <strong>{title ? `"${title}"` : uri}</strong> {__('for')}{' '}
|
</I18nMessage>
|
||||||
<strong>
|
}
|
||||||
<FilePrice uri={uri} showFullPrice inheritStyle showLBC={false} />
|
actions={
|
||||||
</strong>{' '}
|
<div className="section__actions">
|
||||||
{__('credits')}.
|
<Button button="primary" label={__('Confirm')} onClick={this.onAffirmPurchase} />
|
||||||
</p>
|
<Button button="link" label={__('Cancel')} onClick={cancelPurchase} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@ function ChannelsFollowingPage(props: Props) {
|
||||||
meta={
|
meta={
|
||||||
<Button
|
<Button
|
||||||
icon={ICONS.SEARCH}
|
icon={ICONS.SEARCH}
|
||||||
button="link"
|
button="alt"
|
||||||
label={__('Discover New Channels')}
|
label={__('Discover Channels')}
|
||||||
navigate={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`}
|
navigate={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectSearchDownloadUrlsForPage, makeSelectSearchDownloadUrlsCount, selectDownloadUrlsCount, selectIsFetchingFileList } from 'lbry-redux';
|
import {
|
||||||
|
makeSelectSearchDownloadUrlsForPage,
|
||||||
|
selectDownloadUrlsCount,
|
||||||
|
selectIsFetchingFileList,
|
||||||
|
doPurchaseList,
|
||||||
|
makeSelectMyPurchasesForPage,
|
||||||
|
selectIsFetchingMyPurchases,
|
||||||
|
selectMyPurchasesCount,
|
||||||
|
} from 'lbry-redux';
|
||||||
import FileListDownloaded from './view';
|
import FileListDownloaded from './view';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
|
|
||||||
|
@ -13,16 +21,17 @@ const select = (state, props) => {
|
||||||
page,
|
page,
|
||||||
history,
|
history,
|
||||||
query,
|
query,
|
||||||
allDownloadedUrlsCount: selectDownloadUrlsCount(state),
|
downloadedUrlsCount: selectDownloadUrlsCount(state),
|
||||||
downloadedUrls: makeSelectSearchDownloadUrlsForPage(query, page)(state),
|
myPurchasesCount: selectMyPurchasesCount(state),
|
||||||
downloadedUrlsCount: makeSelectSearchDownloadUrlsCount(query)(state),
|
myPurchases: makeSelectMyPurchasesForPage(query, page)(state),
|
||||||
fetching: selectIsFetchingFileList(state),
|
myDownloads: makeSelectSearchDownloadUrlsForPage(query, page)(state),
|
||||||
|
fetchingFileList: selectIsFetchingFileList(state),
|
||||||
|
fetchingMyPurchases: selectIsFetchingMyPurchases(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
connect(
|
connect(select, {
|
||||||
select,
|
doPurchaseList,
|
||||||
null
|
})(FileListDownloaded)
|
||||||
)(FileListDownloaded)
|
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import * as ICONS from 'constants/icons';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import ClaimList from 'component/claimList';
|
import ClaimList from 'component/claimList';
|
||||||
|
@ -6,24 +7,41 @@ import Paginate from 'component/common/paginate';
|
||||||
import { PAGE_SIZE } from 'constants/claim';
|
import { PAGE_SIZE } from 'constants/claim';
|
||||||
import { Form } from 'component/common/form-components/form';
|
import { Form } from 'component/common/form-components/form';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import * as ICONS from '../../constants/icons';
|
import { FormField } from 'component/common/form-components/form-field';
|
||||||
import { FormField } from '../../component/common/form-components/form-field';
|
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
|
import Card from 'component/common/card';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fetching: boolean,
|
fetchingFileList: boolean,
|
||||||
allDownloadedUrlsCount: number,
|
|
||||||
downloadedUrls: Array<string>,
|
downloadedUrls: Array<string>,
|
||||||
downloadedUrlsCount: ?number,
|
downloadedUrlsCount: ?number,
|
||||||
history: { replace: string => void },
|
history: { replace: string => void },
|
||||||
page: number,
|
|
||||||
query: string,
|
query: string,
|
||||||
|
doPurchaseList: () => void,
|
||||||
|
myDownloads: Array<string>,
|
||||||
|
myPurchases: Array<string>,
|
||||||
|
myPurchasesCount: ?number,
|
||||||
|
fetchingMyPurchases: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function FileListDownloaded(props: Props) {
|
const VIEW_DOWNLOADS = 'view_download';
|
||||||
const { fetching, history, query, allDownloadedUrlsCount, downloadedUrls, downloadedUrlsCount } = props;
|
const VIEW_PURCHASES = 'view_purchases';
|
||||||
const hasDownloads = allDownloadedUrlsCount > 0;
|
|
||||||
|
|
||||||
|
function FileListDownloaded(props: Props) {
|
||||||
|
const {
|
||||||
|
history,
|
||||||
|
query,
|
||||||
|
downloadedUrlsCount,
|
||||||
|
myPurchasesCount,
|
||||||
|
myPurchases,
|
||||||
|
myDownloads,
|
||||||
|
fetchingFileList,
|
||||||
|
fetchingMyPurchases,
|
||||||
|
doPurchaseList,
|
||||||
|
} = props;
|
||||||
|
const loading = fetchingFileList || fetchingMyPurchases;
|
||||||
|
const [viewMode, setViewMode] = React.useState(VIEW_PURCHASES);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
|
||||||
function handleInputChange(e) {
|
function handleInputChange(e) {
|
||||||
|
@ -34,13 +52,36 @@ function FileListDownloaded(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
doPurchaseList();
|
||||||
|
}, [doPurchaseList]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<Card
|
||||||
{hasDownloads ? (
|
title={
|
||||||
<React.Fragment>
|
<div>
|
||||||
<ClaimList
|
<Button
|
||||||
header={__('Your Library')}
|
icon={ICONS.LIBRARY}
|
||||||
headerAltControls={
|
button="alt"
|
||||||
|
label={__('All Downloads')}
|
||||||
|
className={classnames(`button-toggle`, {
|
||||||
|
'button-toggle--active': viewMode === VIEW_DOWNLOADS,
|
||||||
|
})}
|
||||||
|
onClick={() => setViewMode(VIEW_DOWNLOADS)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={ICONS.PURCHASED}
|
||||||
|
button="alt"
|
||||||
|
label={__('Your Purchases')}
|
||||||
|
className={classnames(`button-toggle`, {
|
||||||
|
'button-toggle--active': viewMode === VIEW_PURCHASES,
|
||||||
|
})}
|
||||||
|
onClick={() => setViewMode(VIEW_PURCHASES)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
titleActions={
|
||||||
|
<div className="card__actions--inline">
|
||||||
<Form onSubmit={() => {}} className="wunderbar--inline">
|
<Form onSubmit={() => {}} className="wunderbar--inline">
|
||||||
<Icon icon={ICONS.SEARCH} />
|
<Icon icon={ICONS.SEARCH} />
|
||||||
<FormField
|
<FormField
|
||||||
|
@ -52,27 +93,35 @@ function FileListDownloaded(props: Props) {
|
||||||
placeholder={__('Search')}
|
placeholder={__('Search')}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
persistedStorageKey="claim-list-downloaded"
|
isBodyList
|
||||||
empty={__('No results for %query%', { query })}
|
body={
|
||||||
uris={downloadedUrls}
|
<div>
|
||||||
loading={fetching}
|
<ClaimList
|
||||||
/>
|
isCardBody
|
||||||
<Paginate totalPages={Math.ceil(Number(downloadedUrlsCount) / Number(PAGE_SIZE))} loading={fetching} />
|
renderProperties={() => null}
|
||||||
</React.Fragment>
|
empty={
|
||||||
|
viewMode === VIEW_PURCHASES && !query ? (
|
||||||
|
<div>{__("You haven't purchased anything yet silly goose.")}</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="main--empty">
|
__('No results for %query%', { query })
|
||||||
<section className="card card--section">
|
)
|
||||||
<h2 className="card__title card__title--deprecated">
|
}
|
||||||
{__("You haven't downloaded anything from LBRY yet.")}
|
uris={viewMode === VIEW_PURCHASES ? myPurchases : myDownloads}
|
||||||
</h2>
|
loading={loading}
|
||||||
<div className="card__actions card__actions--center">
|
/>
|
||||||
<Button button="primary" navigate="/" label={__('Explore new content')} />
|
{!query && (
|
||||||
</div>
|
<Paginate
|
||||||
</section>
|
loading={loading}
|
||||||
</div>
|
totalPages={Math.ceil(
|
||||||
|
Number(viewMode === VIEW_PURCHASES ? myPurchasesCount : downloadedUrlsCount) / Number(PAGE_SIZE)
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ import { selectUploadCount } from 'lbryinc';
|
||||||
import { doCheckPendingPublishesApp } from 'redux/actions/publish';
|
import { doCheckPendingPublishesApp } from 'redux/actions/publish';
|
||||||
import FileListPublished from './view';
|
import FileListPublished from './view';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { PUBLISHES_PAGE_SIZE, PAGE_PARAM, PAGE_SIZE_PARAM } from 'constants/claim';
|
import { MY_CLAIMS_PAGE_SIZE, PAGE_PARAM, PAGE_SIZE_PARAM } from 'constants/claim';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const { search } = props.location;
|
const { search } = props.location;
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const page = Number(urlParams.get(PAGE_PARAM)) || '1';
|
const page = Number(urlParams.get(PAGE_PARAM)) || '1';
|
||||||
const pageSize = urlParams.get(PAGE_SIZE_PARAM) || String(PUBLISHES_PAGE_SIZE);
|
const pageSize = urlParams.get(PAGE_SIZE_PARAM) || String(MY_CLAIMS_PAGE_SIZE);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
page,
|
page,
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
selectDownloadUrlsCount,
|
||||||
|
selectIsFetchingFileList,
|
||||||
|
selectMyPurchases,
|
||||||
|
selectIsFetchingMyPurchases,
|
||||||
|
} from 'lbry-redux';
|
||||||
import LibraryPage from './view';
|
import LibraryPage from './view';
|
||||||
|
|
||||||
export default LibraryPage;
|
const select = state => ({
|
||||||
|
allDownloadedUrlsCount: selectDownloadUrlsCount(state),
|
||||||
|
fetchingFileList: selectIsFetchingFileList(state),
|
||||||
|
myPurchases: selectMyPurchases(state),
|
||||||
|
fetchingMyPurchases: selectIsFetchingMyPurchases(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(LibraryPage);
|
||||||
|
|
|
@ -1,12 +1,45 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Button from 'component/button';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
import Spinner from 'component/spinner';
|
||||||
import DownloadList from 'page/fileListDownloaded';
|
import DownloadList from 'page/fileListDownloaded';
|
||||||
|
import Yrbl from 'component/yrbl';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
allDownloadedUrlsCount: number,
|
||||||
|
myPurchases: Array<string>,
|
||||||
|
fetchingMyPurchases: boolean,
|
||||||
|
fetchingFileList: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
function LibraryPage(props: Props) {
|
||||||
|
const { allDownloadedUrlsCount, myPurchases, fetchingMyPurchases, fetchingFileList } = props;
|
||||||
|
const hasDownloads = allDownloadedUrlsCount > 0 || (myPurchases && myPurchases.length);
|
||||||
|
const loading = fetchingFileList || fetchingMyPurchases;
|
||||||
|
|
||||||
function LibraryPage() {
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<DownloadList />
|
{loading && !hasDownloads && (
|
||||||
|
<div className="main--empty">
|
||||||
|
<Spinner delayed />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && !hasDownloads && (
|
||||||
|
<div className="main--empty">
|
||||||
|
<Yrbl
|
||||||
|
title={__("You haven't downloaded anything from LBRY yet")}
|
||||||
|
subtitle={
|
||||||
|
<div className="section__actions">
|
||||||
|
<Button button="primary" navigate="/" label={__('Explore new content')} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasDownloads && <DownloadList />}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ function DiscoverPage() {
|
||||||
defaultTags={CS.TAGS_FOLLOWED}
|
defaultTags={CS.TAGS_FOLLOWED}
|
||||||
meta={
|
meta={
|
||||||
<Button
|
<Button
|
||||||
button="link"
|
button="alt"
|
||||||
icon={ICONS.EDIT}
|
icon={ICONS.EDIT}
|
||||||
label={__('Manage')}
|
label={__('Manage')}
|
||||||
requiresAuth={IS_WEB}
|
requiresAuth={IS_WEB}
|
||||||
|
|
|
@ -45,7 +45,8 @@ export const makeSelectIsPlayerFloating = (location: UrlLocation) =>
|
||||||
// If there is no floatingPlayer explicitly set, see if the playingUri can float
|
// If there is no floatingPlayer explicitly set, see if the playingUri can float
|
||||||
try {
|
try {
|
||||||
const { pathname } = location;
|
const { pathname } = location;
|
||||||
const pageUrl = buildURI(parseURI(pathname.slice(1).replace(/:/g, '#')));
|
const { streamName, streamClaimId, channelName, channelClaimId } = parseURI(pathname.slice(1).replace(/:/g, '#'));
|
||||||
|
const pageUrl = buildURI({ streamName, streamClaimId, channelName, channelClaimId });
|
||||||
const claimFromUrl = claimsByUri[pageUrl];
|
const claimFromUrl = claimsByUri[pageUrl];
|
||||||
const playingClaim = claimsByUri[playingUri];
|
const playingClaim = claimsByUri[playingUri];
|
||||||
return (claimFromUrl && claimFromUrl.claim_id) !== (playingClaim && playingClaim.claim_id);
|
return (claimFromUrl && claimFromUrl.claim_id) !== (playingClaim && playingClaim.claim_id);
|
||||||
|
|
|
@ -4,12 +4,15 @@
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: $breakpoint-small) {
|
.button--primary,
|
||||||
|
.button--secondary,
|
||||||
|
.button--alt,
|
||||||
|
.button--link {
|
||||||
&:focus {
|
&:focus {
|
||||||
@include focus;
|
@include focus;
|
||||||
z-index: 2;
|
z-index: 2; // Ensure focus box-shadow is always visible on every button side
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +51,10 @@
|
||||||
background-color: var(--color-button-primary-bg);
|
background-color: var(--color-button-primary-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
@include focus;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
padding: var(--spacing-medium) var(--spacing-small);
|
padding: var(--spacing-medium) var(--spacing-small);
|
||||||
}
|
}
|
||||||
|
@ -124,6 +131,7 @@ svg + .button__label,
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
background-color: var(--color-primary-alt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,30 @@
|
||||||
background-color: var(--color-card-background);
|
background-color: var(--color-card-background);
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: var(--spacing-medium);
|
padding: var(--spacing-medium);
|
||||||
padding-bottom: var(--spacing-small);
|
padding-bottom: var(--spacing-small);
|
||||||
margin-top: var(--spacing-medium);
|
margin-top: var(--spacing-medium);
|
||||||
|
color: var(--color-text-subtitle);
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
color: var(--color-text-subtitle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.claim-search__dropdown {
|
.claim-search__dropdown {
|
||||||
padding: 0 var(--spacing-medium);
|
padding: 0 var(--spacing-medium);
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
|
font-size: var(--font-body);
|
||||||
|
background-color: var(--color-card-background);
|
||||||
|
width: var(--option-select-width);
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
background-color: var(--color-card-background);
|
|
||||||
width: var(--option-select-width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.claim-search__dropdown--selected {
|
.claim-search__dropdown--selected {
|
||||||
|
@ -51,13 +53,11 @@
|
||||||
|
|
||||||
.claim-search__extra {
|
.claim-search__extra {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.claim-search__top {
|
.claim-search__top {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
color: var(--color-text-help);
|
color: var(--color-text-help);
|
||||||
margin-left: var(--spacing-small);
|
margin-left: var(--spacing-medium);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
& > *:not(:last-child) {
|
& > *:not(:last-child) {
|
||||||
|
@ -20,12 +20,68 @@
|
||||||
font-size: var(--font-xsmall);
|
font-size: var(--font-xsmall);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: var(--font-xsmall);
|
||||||
|
}
|
||||||
|
|
||||||
& > *:not(:last-child) {
|
& > *:not(:last-child) {
|
||||||
margin-right: var(--spacing-miniscule);
|
margin-right: var(--spacing-miniscule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-properties__purchased {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: var(--spacing-xsmall);
|
||||||
|
color: var(--color-gray-5);
|
||||||
|
|
||||||
|
span,
|
||||||
|
svg {
|
||||||
|
position: relative;
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
left: -0.4rem;
|
||||||
|
right: -5rem;
|
||||||
|
height: 1.75rem;
|
||||||
|
transform: skew(20deg);
|
||||||
|
background-color: var(--color-purchased);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-properties__not-purchased {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--color-purchased-text);
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: relative;
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
left: 0;
|
||||||
|
right: -5rem;
|
||||||
|
height: 1.75rem;
|
||||||
|
background-color: var(--color-purchased-alt);
|
||||||
|
border: 2px solid var(--color-purchased);
|
||||||
|
transform: skew(20deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.file-properties--large {
|
.file-properties--large {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-bottom: var(--spacing-large);
|
margin-bottom: var(--spacing-large);
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
input-submit {
|
input-submit {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='number'] {
|
input[type='number'] {
|
||||||
|
|
|
@ -71,3 +71,9 @@
|
||||||
.pagination__item--selected {
|
.pagination__item--selected {
|
||||||
background-color: var(--color-button-secondary-bg);
|
background-color: var(--color-button-secondary-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.paginate-channel {
|
||||||
|
width: 5rem;
|
||||||
|
border-top-left-radius: var(--border-radius);
|
||||||
|
border-bottom-left-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ p {
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
|
|
||||||
li {
|
li {
|
||||||
list-style-position: outside;
|
list-style-position: outside;
|
||||||
margin: var(--spacing-xsmall) var(--spacing-medium);
|
margin: var(--spacing-xsmall) var(--spacing-medium);
|
||||||
|
@ -218,8 +217,10 @@ img {
|
||||||
color: var(--color-text-empty);
|
color: var(--color-text-empty);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty--centered {
|
.empty--centered {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
padding: calc(var(--spacing-large) * 3) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-code {
|
.qr-code {
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
--color-comment-menu-hovering: #e0e0e0;
|
--color-comment-menu-hovering: #e0e0e0;
|
||||||
--color-notice: #58563b;
|
--color-notice: #58563b;
|
||||||
--color-error: #61373f;
|
--color-error: #61373f;
|
||||||
|
--color-purchased: #ffd580;
|
||||||
|
--color-purchased-alt: #ffd5804a;
|
||||||
|
--color-purchased-text: #eeeeee;
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
--color-text: #eeeeee;
|
--color-text: #eeeeee;
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
--color-comment-menu: #e0e0e0;
|
--color-comment-menu: #e0e0e0;
|
||||||
--color-comment-menu-hovering: #6a6a6a;
|
--color-comment-menu-hovering: #6a6a6a;
|
||||||
--color-notice: #fef3ca;
|
--color-notice: #fef3ca;
|
||||||
|
--color-purchased: #ffd580;
|
||||||
|
--color-purchased-alt: #ffebc2;
|
||||||
|
--color-purchased-text: var(--color-gray-5);
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
--color-follow-bg: #ffd4da;
|
--color-follow-bg: #ffd4da;
|
||||||
|
|
|
@ -6178,9 +6178,9 @@ lazy-val@^1.0.4:
|
||||||
yargs "^13.2.2"
|
yargs "^13.2.2"
|
||||||
zstd-codec "^0.1.1"
|
zstd-codec "^0.1.1"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#259317250af62391718ac0cb8b8e25f172dc4223:
|
lbry-redux@lbryio/lbry-redux#cd9c15567f2934ddc82de364d88b378ff04d5571:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/259317250af62391718ac0cb8b8e25f172dc4223"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/cd9c15567f2934ddc82de364d88b378ff04d5571"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue