Merge branch 'master' into fix-viewer

This commit is contained in:
Baltazar Gomez 2018-08-03 13:00:37 -06:00 committed by GitHub
commit 605136ac64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 394 additions and 200 deletions

View file

@ -38,6 +38,7 @@
"import/prefer-default-export": 0,
"no-return-assign": 0,
"react/require-default-props": 0,
"react/jsx-closing-tag-location": 0
"react/jsx-closing-tag-location": 0,
"jsx-a11y/no-noninteractive-element-to-interactive-role": 0
}
}

2
.gitignore vendored
View file

@ -5,4 +5,4 @@
yarn-error.log
package-lock.json
.idea/
/build/daemon.ver
/build/daemon*

View file

@ -1,6 +1,6 @@
{
"name": "LBRY",
"version": "0.23.0",
"version": "0.23.1",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [
"lbry"

View file

@ -1,4 +1,4 @@
import { app, BrowserWindow, dialog, screen } from 'electron';
import { app, BrowserWindow, dialog, shell, screen } from 'electron';
import isDev from 'electron-is-dev';
import windowStateKeeper from 'electron-window-state';
@ -124,5 +124,10 @@ export default appState => {
window = null;
});
window.webContents.on('new-window', (event, url) => {
event.preventDefault();
shell.openExternal(url);
});
return window;
};

View file

@ -11,9 +11,10 @@ type Props = {
showPlus: boolean,
isEstimate?: boolean,
large?: boolean,
plain?: boolean,
showLBC?: boolean,
fee?: boolean,
noStyle?: boolean,
inheritStyle?: boolean,
filePage?: boolean,
};
class CreditAmount extends React.PureComponent<Props> {
@ -22,6 +23,7 @@ class CreditAmount extends React.PureComponent<Props> {
showFree: false,
showFullPrice: false,
showPlus: false,
showLBC: true,
};
render() {
@ -33,9 +35,10 @@ class CreditAmount extends React.PureComponent<Props> {
showPlus,
large,
isEstimate,
plain,
noStyle,
fee,
showLBC,
inheritStyle,
filePage,
} = this.props;
const minimumRenderableAmount = 10 ** (-1 * precision);
@ -62,7 +65,7 @@ class CreditAmount extends React.PureComponent<Props> {
amountText = `+${amountText}`;
}
if (!plain) {
if (showLBC) {
amountText = `${amountText} ${__('LBC')}`;
}
@ -78,8 +81,8 @@ class CreditAmount extends React.PureComponent<Props> {
'credit-amount--free': !large && isFree,
'credit-amount--cost': !large && !isFree,
'credit-amount--large': large,
'credit-amount--plain': plain,
'credit-amount--no-style': noStyle,
'credit-amount--inherit': inheritStyle,
'credit-amount--file-page': filePage,
})}
>
{amountText}

View file

@ -4,7 +4,7 @@ import ReactDOMServer from 'react-dom/server';
import classnames from 'classnames';
import MarkdownPreview from 'component/common/markdown-preview';
import SimpleMDE from 'react-simplemde-editor';
import 'simplemde/dist/simplemde.min.css';
import 'simplemde/dist/simplemde.min.css'; // eslint-disable-line import/no-extraneous-dependencies
import Toggle from 'react-toggle';
import { openEditorMenu, stopContextMenu } from 'util/contextMenu';
@ -24,6 +24,7 @@ type Props = {
stretch?: boolean,
affixClass?: string, // class applied to prefix/postfix label
useToggle?: boolean,
firstInList?: boolean, // at the top of a list, no padding top
};
export class FormField extends React.PureComponent<Props> {
@ -41,6 +42,7 @@ export class FormField extends React.PureComponent<Props> {
stretch,
affixClass,
useToggle,
firstInList,
...inputProps
} = this.props;
@ -103,6 +105,7 @@ export class FormField extends React.PureComponent<Props> {
<div
className={classnames('form-field__input', {
'form-field--auto-height': type === 'markdown',
'form-field--first-item': firstInList,
})}
>
{prefix && (

View file

@ -92,9 +92,8 @@ class FileCard extends React.PureComponent<Props> {
onContextMenu={handleContextMenu}
>
<CardMedia thumbnail={thumbnail} />
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
<div className="card__title-identity">
<div className="card__title--small">
<div className="card__title--small card__title--file-card">
<TruncatedText lines={3}>{title}</TruncatedText>
</div>
<div className="card__subtitle">
@ -103,13 +102,12 @@ class FileCard extends React.PureComponent<Props> {
) : (
<React.Fragment>
<UriIndicator uri={uri} link />
<div>
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
{fileInfo && <Icon icon={icons.LOCAL} />}
</div>
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
{fileInfo && <Icon icon={icons.LOCAL} />}
</React.Fragment>
)}
</div>
{showPrice && <FilePrice uri={uri} />}
</div>
</section>
);

View file

@ -9,6 +9,10 @@ type Props = {
uri: string,
fetching: boolean,
claim: ?{},
// below props are just passed to <CreditAmount />
filePage?: boolean,
inheritStyle?: boolean,
showLBC?: boolean,
};
class FilePrice extends React.PureComponent<Props> {
@ -33,13 +37,16 @@ class FilePrice extends React.PureComponent<Props> {
};
render() {
const { costInfo, showFullPrice } = this.props;
const { costInfo, showFullPrice, filePage, inheritStyle, showLBC } = this.props;
return costInfo ? (
<CreditAmount
showFree
filePage={filePage}
inheritStyle={inheritStyle}
showLBC={showLBC}
amount={costInfo.cost}
isEstimate={!costInfo.includesData}
showFree
showFullPrice={showFullPrice}
/>
) : null;

View file

@ -11,7 +11,6 @@ import classnames from 'classnames';
import FilePrice from 'component/filePrice';
type Props = {
fullWidth: boolean, // removes the max-width css
showUri: boolean,
showLocal: boolean,
obscureNsfw: boolean,
@ -28,13 +27,15 @@ type Props = {
updatePublishForm: ({}) => void,
hideNoResult: boolean, // don't show the tile if there is no claim at this uri
displayHiddenMessage?: boolean,
displayDescription?: boolean,
small?: boolean,
};
class FileTile extends React.PureComponent<Props> {
static defaultProps = {
showUri: false,
showLocal: false,
fullWidth: false,
displayDescription: true,
};
componentDidMount() {
@ -57,13 +58,14 @@ class FileTile extends React.PureComponent<Props> {
showUri,
obscureNsfw,
claimIsMine,
fullWidth,
showLocal,
isDownloaded,
clearPublish,
updatePublishForm,
hideNoResult,
displayHiddenMessage,
displayDescription,
small,
} = this.props;
const shouldHide = !claimIsMine && obscureNsfw && metadata && metadata.nsfw;
@ -96,7 +98,7 @@ class FileTile extends React.PureComponent<Props> {
return !name && hideNoResult ? null : (
<section
className={classnames('file-tile card--link', {
'file-tile--fullwidth': fullWidth,
'file-tile--small': small,
})}
onClick={onClick}
onKeyUp={onClick}
@ -108,20 +110,29 @@ class FileTile extends React.PureComponent<Props> {
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
{!isResolvingUri && (
<React.Fragment>
<div className="card__title--small card__title--file">
<TruncatedText lines={2}>{title || name}</TruncatedText>
<div
className={classnames({
'card__title--file': !small,
'card__title--x-small': small,
})}
>
<TruncatedText lines={3}>{title || name}</TruncatedText>
</div>
<div className="card__subtitle">
<div
className={classnames('card__subtitle', {
'card__subtitle--x-small': small,
})}
>
{showUri ? uri : channel || __('Anonymous')}
{isRewardContent && <Icon icon={icons.FEATURED} />}
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
</div>
<div className="card__subtext card__subtext--small">
<TruncatedText lines={3}>{description}</TruncatedText>
</div>
<div className="card__subtitle-price">
<FilePrice uri={uri} />
</div>
<FilePrice uri={uri} />
{displayDescription && (
<div className="card__subtext card__subtext--small">
<TruncatedText lines={3}>{description}</TruncatedText>
</div>
)}
{!name && (
<React.Fragment>
{__('This location is unused.')}{' '}

View file

@ -12,6 +12,7 @@ type Props = {
noPadding: ?boolean,
extraPadding: ?boolean,
notContained: ?boolean, // No max-width, but keep the padding
forContent: ?boolean,
loading: ?boolean,
};
@ -71,15 +72,24 @@ class Page extends React.PureComponent<Props, State> {
loaderTimeout: ?TimeoutID;
render() {
const { pageTitle, children, noPadding, extraPadding, notContained, loading } = this.props;
const {
pageTitle,
children,
noPadding,
extraPadding,
notContained,
loading,
forContent,
} = this.props;
const { showLoader } = this.state;
return (
<main
className={classnames('main', {
'main--contained': !notContained && !noPadding && !extraPadding,
'main--contained': !notContained && !noPadding && !extraPadding && !forContent,
'main--no-padding': noPadding,
'main--extra-padding': extraPadding,
'main--for-content': forContent,
})}
>
{pageTitle && (

View file

@ -53,7 +53,7 @@ type Props = {
clearPublish: () => void,
resolveUri: string => void,
scrollToTop: () => void,
prepareEdit: ({}) => void,
prepareEdit: ({ }) => void,
resetThumbnailStatus: () => void,
};
@ -345,6 +345,13 @@ class PublishForm extends React.PureComponent<Props> {
<div className="card__title">{__('Content')}</div>
<div className="card__subtitle">
{isStillEditing ? __('Editing a claim') : __('What are you publishing?')}
{' '}{__(
'Read our'
)}{' '}
<Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '}
{__(
'to learn more.'
)}
</div>
{(filePath || !!editingURI) && (
<div className="card-media__internal-links">
@ -402,12 +409,12 @@ class PublishForm extends React.PureComponent<Props> {
{uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
__('Enter a URL for your thumbnail.')
) : (
<React.Fragment>
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
{__('Recommended size: 800x450 (16:9)')}
</React.Fragment>
)}
<React.Fragment>
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
{__('Recommended size: 800x450 (16:9)')}
</React.Fragment>
)}
</div>
<SelectThumbnail
thumbnailPath={thumbnailPath}
@ -482,7 +489,7 @@ class PublishForm extends React.PureComponent<Props> {
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
? ''
: `${channel}/`
}`}
}`}
type="text"
name="content_name"
placeholder="myname"

View file

@ -0,0 +1,22 @@
import * as settings from 'constants/settings';
import { connect } from 'react-redux';
import { doFetchClaimsByChannel } from 'redux/actions/content';
import { makeSelectClaimsInChannelForCurrentPage } from 'lbry-redux';
import { doSetClientSetting } from 'redux/actions/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import RecommendedVideos from './view';
const select = (state, props) => ({
claimsInChannel: makeSelectClaimsInChannelForCurrentPage(props.channelUri)(state),
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
});
const perform = dispatch => ({
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
setAutoplay: value => dispatch(doSetClientSetting(settings.AUTOPLAY, value)),
});
export default connect(
select,
perform
)(RecommendedVideos);

View file

@ -0,0 +1,76 @@
// @flow
import React from 'react';
import FileTile from 'component/fileTile';
import { FormRow, FormField } from 'component/common/form';
import ToolTip from 'component/common/tooltip';
import type { Claim } from 'types/claim';
import { buildURI, parseURI } from 'lbry-redux';
type Props = {
uri: string,
channelUri: ?string,
claimsInChannel: ?Array<Claim>,
autoplay: boolean,
setAutoplay: boolean => void,
fetchClaims: (string, number) => void,
};
export default class RecommendedContent extends React.PureComponent<Props> {
componentDidMount() {
const { channelUri, fetchClaims, claimsInChannel } = this.props;
if (channelUri && !claimsInChannel) {
fetchClaims(channelUri, 1);
}
}
render() {
const { claimsInChannel, autoplay, uri, setAutoplay } = this.props;
let recommendedContent;
if (claimsInChannel) {
recommendedContent = claimsInChannel.filter(claim => {
const { name, claim_id: claimId, channel_name: channelName, value } = claim;
const { isChannel } = parseURI(uri);
// The uri may include the channel name
const recommendedUri =
isChannel && value && value.publisherSignature
? buildURI({
contentName: name,
claimName: channelName,
claimId: value.publisherSignature.certificateId,
})
: buildURI({ claimName: name, claimId });
return recommendedUri !== uri;
});
}
return (
<section className="card__list--recommended">
<FormRow>
<ToolTip onComponent body={__('Automatically download and play free content.')}>
<FormField
useToggle
firstInList
name="autoplay"
type="checkbox"
prefix={__('Autoplay')}
checked={autoplay}
onChange={e => setAutoplay(e.target.checked)}
/>
</ToolTip>
</FormRow>
{recommendedContent &&
recommendedContent.map(({ permanent_url: permanentUrl }) => (
<FileTile
small
displayDescription={false}
key={permanentUrl}
uri={`lbry://${permanentUrl}`}
/>
))}
</section>
);
}
}

View file

@ -31,7 +31,7 @@ class RewardSummary extends React.Component<Props> {
<React.Fragment>
{__('You have')}
&nbsp;
<CreditAmount noStyle amount={unclaimedRewardAmount} precision={8} />
<CreditAmount inheritStyle amount={unclaimedRewardAmount} precision={8} />
&nbsp;
{__('in unclaimed rewards')}.
</React.Fragment>

View file

@ -18,6 +18,7 @@ type Props = {
type State = {
thumbnailError: boolean,
thumbnailErrorImage: string,
};
class SelectThumbnail extends React.PureComponent<Props, State> {
@ -26,6 +27,7 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
this.state = {
thumbnailError: false,
thumbnailErrorImage: 'no-thumbnail.png',
};
(this: any).handleThumbnailChange = this.handleThumbnailChange.bind(this);
@ -36,7 +38,7 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
const newThumbnail = e.target.value.replace(' ', '');
updatePublishForm({ thumbnail: newThumbnail });
this.setState({ thumbnailError: false });
this.setState({ thumbnailError: false, thumbnailErrorImage: 'no-thumbnail.png' });
}
render() {
@ -49,9 +51,9 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
thumbnailPath,
resetThumbnailStatus,
} = this.props;
const { thumbnailError } = this.state;
const { thumbnailError, thumbnailErrorImage } = this.state;
const thumbnailSrc =
!thumbnail || thumbnailError ? Native.imagePath('no-thumbnail.png') : thumbnail;
!thumbnail || thumbnailError ? Native.imagePath(thumbnailErrorImage) : thumbnail;
return (
<div className="card__content">
@ -62,7 +64,11 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
className="column__item thumbnail-preview"
alt={__('Thumbnail Preview')}
onError={() => {
this.setState({ thumbnailError: true });
this.setState({
thumbnailError: true,
thumbnailErrorImage:
thumbnail && thumbnail.length > 0 ? 'broken.png' : 'no-thumbnail.png',
});
}}
/>
<div className="column__item">

View file

@ -6,8 +6,8 @@ import DateTime from 'component/dateTime';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
import * as txnTypes from 'constants/transaction_types';
import type { Transaction } from '../view';
import * as ICONS from 'constants/icons';
import type { Transaction } from '../view';
type Props = {
transaction: Transaction,
@ -25,12 +25,6 @@ class TransactionListItem extends React.PureComponent<Props> {
(this: any).abandonClaim = this.abandonClaim.bind(this);
}
abandonClaim() {
const { txid, nout } = this.props.transaction;
this.props.revokeClaim(txid, nout);
}
getLink(type: string) {
if (type === txnTypes.TIP) {
return <Button icon={ICONS.UNLOCK} onClick={this.abandonClaim} title={__('Unlock Tip')} />;
@ -38,10 +32,14 @@ class TransactionListItem extends React.PureComponent<Props> {
return <Button icon={ICONS.TRASH} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
}
capitalize(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
abandonClaim() {
const { txid, nout } = this.props.transaction;
this.props.revokeClaim(txid, nout);
}
capitalize = (string: string) => string.charAt(0).toUpperCase() + string.slice(1);
render() {
const { reward, transaction, isRevokeable } = this.props;
const { amount, claim_id: claimId, claim_name: name, date, fee, txid, type } = transaction;
@ -55,12 +53,12 @@ class TransactionListItem extends React.PureComponent<Props> {
return (
<tr>
<td>
<CreditAmount amount={amount} plain noStyle showPlus precision={8} />
<CreditAmount inheritStyle showPlus amount={amount} precision={8} />
<br />
{fee !== 0 && (
<span className="table__item-label">
<CreditAmount plain noStyle fee amount={fee} precision={8} />
<CreditAmount inheritStyle fee amount={fee} precision={8} />
</span>
)}
</td>

View file

@ -18,7 +18,7 @@ export default (props: Props) => {
<Button
icon={icons.GLOBE}
button="alt"
label={__('View on Web')}
label={__('Share')}
href={`http://spee.ch/${speechURL}`}
/>
) : null;

View file

@ -31,7 +31,7 @@ class ModalAffirmPurchase extends React.PureComponent {
>
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
<strong>
<FilePrice uri={uri} showFullPrice look="plain" />
<FilePrice uri={uri} showFullPrice inheritStyle showLBC={false} />
</strong>{' '}
{__('credits')}.
</Modal>

View file

@ -1,9 +1,23 @@
// @flow
import React from 'react';
import { ipcRenderer } from 'electron';
import { Modal } from 'modal/modal';
import Button from 'component/button';
class ModalAutoUpdateDownloaded extends React.PureComponent {
type Props = {
closeModal: any => any,
declineAutoUpdate: () => any,
};
class ModalAutoUpdateDownloaded extends React.PureComponent<Props> {
constructor(props: ModalProps) {
super(props);
this.state = {
disabled: false,
};
}
render() {
const { closeModal, declineAutoUpdate } = this.props;
@ -14,7 +28,9 @@ class ModalAutoUpdateDownloaded extends React.PureComponent {
contentLabel={__('Update Downloaded')}
confirmButtonLabel={__('Use it Now')}
abortButtonLabel={__('Upgrade on Close')}
confirmButtonDisabled={this.state.disabled}
onConfirmed={() => {
this.setState({ disabled: true });
ipcRenderer.send('autoUpdateAccepted');
}}
onAborted={() => {

View file

@ -14,14 +14,12 @@ import Button from 'component/button';
import SubscribeButton from 'component/subscribeButton';
import ViewOnWebButton from 'component/viewOnWebButton';
import Page from 'component/page';
import * as settings from 'constants/settings';
import type { Claim } from 'types/claim';
import type { Subscription } from 'types/subscription';
import FileDownloadLink from 'component/fileDownloadLink';
import classnames from 'classnames';
import { FormField, FormRow } from 'component/common/form';
import ToolTip from 'component/common/tooltip';
import getMediaType from 'util/getMediaType';
import RecommendedContent from 'component/recommendedContent';
type Props = {
claim: Claim,
@ -37,14 +35,12 @@ type Props = {
rewardedContentClaimIds: Array<string>,
obscureNsfw: boolean,
claimIsMine: boolean,
autoplay: boolean,
costInfo: ?{},
navigate: (string, ?{}) => void,
openModal: ({ id: string }, { uri: string }) => void,
fetchFileInfo: string => void,
fetchCostInfo: string => void,
prepareEdit: ({}, string) => void,
setClientSetting: (string, boolean | string) => void,
checkSubscription: ({ channelName: string, uri: string }) => void,
subscriptions: Array<Subscription>,
};
@ -63,12 +59,6 @@ class FilePage extends React.Component<Props> {
'application',
];
constructor(props: Props) {
super(props);
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
}
componentDidMount() {
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
@ -89,10 +79,6 @@ class FilePage extends React.Component<Props> {
}
}
onAutoplayChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(settings.AUTOPLAY, event.target.checked);
}
checkSubscription = (props: Props) => {
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
props.checkSubscription({
@ -120,7 +106,6 @@ class FilePage extends React.Component<Props> {
claimIsMine,
prepareEdit,
navigate,
autoplay,
costInfo,
fileInfo,
} = this.props;
@ -161,99 +146,79 @@ class FilePage extends React.Component<Props> {
}
return (
<Page extraPadding>
{!claim || !metadata ? (
<section>
<span className="empty">{__('Empty claim or metadata info.')}</span>
</section>
) : (
<section className="card">
{showFile && (
<FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />
)}
{!showFile &&
(thumbnail ? (
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
) : (
<div
className={classnames('content__empty', {
'content__empty--nsfw': shouldObscureThumbnail,
})}
>
<div className="card__media-text">
{__("Sorry, looks like we can't preview this file.")}
</div>
</div>
))}
<div className="card__content">
<div className="card__title-identity--file">
<h1 className="card__title card__title--file">{title}</h1>
<div className="card__title-identity-icons">
{isRewardContent && (
<Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />
)}
<FilePrice uri={normalizeURI(uri)} />
<Page forContent>
<section className="content__wrapper">
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
{!showFile &&
(thumbnail ? (
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
) : (
<div
className={classnames('content__empty', {
'content__empty--nsfw': shouldObscureThumbnail,
})}
>
<div className="card__media-text">
{__("Sorry, looks like we can't preview this file.")}
</div>
</div>
<span className="card__subtitle card__subtitle--file">
{__('Published on')}&nbsp;
<DateTime block={height} show={DateTime.SHOW_DATE} />
</span>
{metadata.nsfw && <div>NSFW</div>}
<div className="card__channel-info">
<UriIndicator uri={uri} link />
</div>
<div className="card__actions card__actions--no-margin card__actions--between">
<div className="card__actions">
{claimIsMine ? (
<Button
button="primary"
icon={icons.EDIT}
label={__('Edit')}
onClick={() => {
prepareEdit(claim, editUri);
navigate('/publish');
}}
/>
) : (
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
)}
{!claimIsMine && (
<Button
button="alt"
icon={icons.GIFT}
label={__('Enjoy this? Send a tip')}
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
/>
)}
{speechSharable && (
<ViewOnWebButton claimId={claim.claim_id} claimName={claim.name} />
)}
</div>
))}
<div className="card__actions">
<FileDownloadLink uri={uri} />
<FileActions uri={uri} claimId={claim.claim_id} />
</div>
<div className="card__content">
<div className="card__title-identity--file">
<h1 className="card__title card__title--file">{title}</h1>
<div className="card__title-identity-icons">
{isRewardContent && <Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />}
<FilePrice filePage uri={normalizeURI(uri)} />
</div>
<FormRow padded>
<ToolTip onComponent body={__('Automatically download and play free content.')}>
<FormField
useToggle
name="autoplay"
type="checkbox"
postfix={__('Autoplay')}
checked={autoplay}
onChange={this.onAutoplayChange}
</div>
<span className="card__subtitle card__subtitle--file">
{__('Published on')}&nbsp;
<DateTime block={height} show={DateTime.SHOW_DATE} />
</span>
{metadata.nsfw && <div>NSFW</div>}
<div className="card__channel-info">
<UriIndicator uri={uri} link />
</div>
<div className="card__actions card__actions--no-margin card__actions--between">
<div className="card__actions">
{claimIsMine ? (
<Button
button="primary"
icon={icons.EDIT}
label={__('Edit')}
onClick={() => {
prepareEdit(claim, editUri);
navigate('/publish');
}}
/>
</ToolTip>
</FormRow>
) : (
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
)}
{!claimIsMine && (
<Button
button="alt"
icon={icons.GIFT}
label={__('Send a tip')}
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
/>
)}
{speechSharable && (
<ViewOnWebButton claimId={claim.claim_id} claimName={claim.name} />
)}
</div>
<div className="card__actions">
<FileDownloadLink uri={uri} />
<FileActions uri={uri} claimId={claim.claim_id} />
</div>
</div>
<div className="card__content--extra-padding">
<FileDetails uri={uri} />
</div>
</section>
)}
</div>
</section>
<RecommendedContent uri={uri} channelUri={`lbry://${subscriptionUri}`} />
</Page>
);
}

View file

@ -73,7 +73,7 @@ class SearchPage extends React.PureComponent<Props> {
<Icon icon={icons.HELP} />
</ToolTip>
</div>
<FileTile fullWidth showUri displayHiddenMessage uri={normalizeURI(query)} />
<FileTile showUri displayHiddenMessage uri={normalizeURI(query)} />
</React.Fragment>
)}
<FileListSearch query={query} />

View file

@ -120,7 +120,7 @@ export const doUploadThumbnail = (filePath: string, nsfw: boolean) => (dispatch:
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError('Upload failed')
: uploadError(json.message)
)
.catch(err => uploadError(err.message));
};

View file

@ -74,7 +74,7 @@ export const shapeShiftInit = () => (dispatch: Dispatch): ThunkAction => {
let supportedCoins = [];
Object.keys(coinData).forEach(symbol => {
if (coinData[symbol].status === SHAPESHIFT_STATUSES.UNAVAILABLE) {
if (coinData[symbol].status === SHAPESHIFT_STATUSES.AVAILABLE) {
supportedCoins.push(coinData[symbol]);
}
});

View file

@ -204,6 +204,12 @@ p {
padding-right: 100px;
}
.main--for-content {
padding: $spacing-width * 2/3;
display: flex;
justify-content: center;
}
.page__header {
padding: $spacing-vertical * 2/3;
padding-bottom: 0;
@ -251,11 +257,10 @@ p {
}
.credit-amount {
border-radius: 5px;
font-family: 'metropolis-bold';
font-size: 10px;
padding: 5px;
white-space: nowrap;
padding: $spacing-vertical * 1/6 0;
}
.credit-amount--large {
@ -263,30 +268,36 @@ p {
font-size: 36px;
}
.credit-amount--file-page {
border-radius: 5px;
padding: 5px;
}
.credit-amount--free {
color: var(--color-dark-blue);
background-color: var(--color-secondary);
color: var(--color-secondary);
&.credit-amount--file-page {
color: var(--color-dark-blue);
background-color: var(--color-secondary);
}
}
.credit-amount--cost {
color: var(--color-black);
background-color: var(--color-yellow);
color: var(--color-yellow);
&.credit-amount--file-page {
color: var(--color-black);
background-color: var(--color-yellow);
}
}
.credit-amount--plain {
.credit-amount--inherit {
background-color: inherit;
color: inherit;
font-weight: inherit;
font-size: inherit;
}
.credit-amount.credit-amount--no-style {
padding: 0;
font-size: inherit;
font-weight: inherit;
color: inherit;
background-color: transparent;
font-family: 'metropolis-medium';
padding: 0;
}
.divider__horizontal {

View file

@ -9,7 +9,7 @@ $large-breakpoint: 1921px;
:root {
/* Widths & spacings */
--side-nav-width: 220px;
--side-nav-width: 190px;
--side-nav-width-m: 240px;
--side-nav-width-l: 320px;
--font-size-subtext-multiple: 0.92;
@ -155,9 +155,14 @@ $large-breakpoint: 1921px;
--success-msg-border: var(--color-green-blue);
--success-msg-bg: var(--color-green-light);
/* File Tile Card */
--file-tile--media-height: 125px;
--file-tile--media-width: calc(125px * (16 / 9));
/* File */
--file-tile-media-height: 125px;
--file-tile-media-width: calc(125px * (16 / 9));
--file-tile-media-height-small: 60px;
--file-tile-media-width-small: calc(60px * (16 / 9));
--file-page-min-width: 400px;
--recommended-content-width: 300px;
--recommended-content-width-medium: 400px;
/* Modal */
--modal-width: 440px;

View file

@ -38,7 +38,6 @@
@media only screen and (min-width: $medium-breakpoint) {
font-size: 14px;
padding-top: 4px;
}
}
}
@ -114,13 +113,17 @@
.card__title--small {
font-size: 14px;
line-height: 18px;
padding-top: $spacing-vertical / 3;
@media only screen and (min-width: $large-breakpoint) {
font-size: 16px;
}
}
.card__title--x-small {
font-size: 12px;
line-height: 12px;
}
.card__title--file {
font-family: 'metropolis-bold';
font-size: 28px;
@ -130,25 +133,36 @@
font-size: 18px;
}
.card__title--file-card {
padding-top: $spacing-vertical * 1/3;
}
.card__subtitle {
margin: 0;
font-size: 14px;
font-family: 'metropolis-medium';
color: var(--card-text-color);
display: flex;
align-items: center;
.icon {
margin-top: $spacing-vertical * 1/6;
&:not(:first-of-type) {
margin: 0 $spacing-vertical * 1/3;
}
margin: 0 0 0 $spacing-vertical * 1/3;
}
}
.card__subtitle--x-small {
font-size: 12px;
}
.card__subtitle-price {
padding-top: $spacing-vertical * 1/3;
}
.card__title--small + .card__subtitle,
.card__title--x-small + .card__subtitle {
padding-top: $spacing-vertical * 1/3;
}
.card__meta {
color: var(--color-help);
font-size: 14px;
@ -312,7 +326,11 @@
.card-row__scroll-btns {
display: flex;
padding-right: $spacing-width;
padding-right: $spacing-width * 1/3;
@media (min-width: $medium-breakpoint) {
padding-right: $spacing-width;
}
}
.card-row__scrollhouse {
@ -401,6 +419,15 @@
}
}
.card__list--recommended {
flex: 0 0 var(--recommended-content-width);
padding-left: $spacing-width;
@media (min-width: $medium-breakpoint) {
flex: 0 0 var(--recommended-content-width-medium);
}
}
.card__success-msg {
border-left: 2px solid var(--success-msg-border);
color: var(--success-msg-color);

View file

@ -1,3 +1,8 @@
.content__wrapper {
max-width: var(--card-max-width);
flex: 1 0 var(--file-page-min-width);
}
.content__embedded {
background-color: var(--color-black);
width: 100%;

View file

@ -22,11 +22,11 @@
.file-tile {
display: flex;
margin-top: $spacing-vertical;
padding-top: $spacing-vertical;
.card__media {
height: var(--file-tile--media-height);
flex: 0 0 var(--file-tile--media-width);
height: var(--file-tile-media-height);
flex: 0 0 var(--file-tile-media-width);
}
.card__subtitle {
@ -34,8 +34,13 @@
}
}
.file-tile--fullwidth {
max-width: none;
.file-tile.file-tile--small {
padding-top: $spacing-vertical * 2/3;
.card__media {
height: var(--file-tile-media-height-small);
flex: 0 0 var(--file-tile-media-width-small);
}
}
.file-tile__info {

View file

@ -51,6 +51,10 @@
width: 100%;
}
.form-field__input.form-field--first-item {
padding: 0;
}
.form-field__input {
display: flex;
padding-top: $spacing-vertical / 3;

View file

@ -6,9 +6,13 @@
z-index: 1;
justify-content: space-between;
align-items: center;
padding: 0 $spacing-width;
padding: 0 $spacing-width * 1/3;
background-color: var(--color-bg);
box-shadow: var(--box-shadow-header);
@media (min-width: $medium-breakpoint) {
padding: 0 $spacing-width;
}
}
.header__navigation {

View file

@ -1,7 +1,7 @@
.nav {
width: var(--side-nav-width);
background-color: var(--nav-bg-color);
padding: $spacing-width;
padding: $spacing-width * 1/3;
color: var(--nav-color);
hr {
@ -11,8 +11,13 @@
margin: $spacing-vertical $spacing-vertical * 2/3;
}
@media (min-width: $medium-breakpoint) {
padding-left: $spacing-width;
width: calc(var(--side-nav-width) * 1.2);
}
@media (min-width: $large-breakpoint) {
width: calc(var(--side-nav-width) * 1.1);
width: calc(var(--side-nav-width) * 1.4);
}
}

BIN
static/img/broken.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB