recommended content v1 #1817
25 changed files with 343 additions and 183 deletions
|
@ -38,6 +38,7 @@
|
||||||
"import/prefer-default-export": 0,
|
"import/prefer-default-export": 0,
|
||||||
"no-return-assign": 0,
|
"no-return-assign": 0,
|
||||||
"react/require-default-props": 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
2
.gitignore
vendored
|
@ -5,4 +5,4 @@
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.idea/
|
.idea/
|
||||||
/build/daemon.ver
|
/build/daemon*
|
|
@ -11,9 +11,10 @@ type Props = {
|
||||||
showPlus: boolean,
|
showPlus: boolean,
|
||||||
isEstimate?: boolean,
|
isEstimate?: boolean,
|
||||||
large?: boolean,
|
large?: boolean,
|
||||||
plain?: boolean,
|
showLBC?: boolean,
|
||||||
fee?: boolean,
|
fee?: boolean,
|
||||||
noStyle?: boolean,
|
inheritStyle?: boolean,
|
||||||
|
filePage?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CreditAmount extends React.PureComponent<Props> {
|
class CreditAmount extends React.PureComponent<Props> {
|
||||||
|
@ -22,6 +23,7 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
showFree: false,
|
showFree: false,
|
||||||
showFullPrice: false,
|
showFullPrice: false,
|
||||||
showPlus: false,
|
showPlus: false,
|
||||||
|
showLBC: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -33,9 +35,10 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
showPlus,
|
showPlus,
|
||||||
large,
|
large,
|
||||||
isEstimate,
|
isEstimate,
|
||||||
plain,
|
|
||||||
noStyle,
|
|
||||||
fee,
|
fee,
|
||||||
|
showLBC,
|
||||||
|
inheritStyle,
|
||||||
|
filePage,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const minimumRenderableAmount = 10 ** (-1 * precision);
|
const minimumRenderableAmount = 10 ** (-1 * precision);
|
||||||
|
@ -62,7 +65,7 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
amountText = `+${amountText}`;
|
amountText = `+${amountText}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!plain) {
|
if (showLBC) {
|
||||||
amountText = `${amountText} ${__('LBC')}`;
|
amountText = `${amountText} ${__('LBC')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +81,8 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
'credit-amount--free': !large && isFree,
|
'credit-amount--free': !large && isFree,
|
||||||
'credit-amount--cost': !large && !isFree,
|
'credit-amount--cost': !large && !isFree,
|
||||||
'credit-amount--large': large,
|
'credit-amount--large': large,
|
||||||
'credit-amount--plain': plain,
|
'credit-amount--inherit': inheritStyle,
|
||||||
'credit-amount--no-style': noStyle,
|
'credit-amount--file-page': filePage,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{amountText}
|
{amountText}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import ReactDOMServer from 'react-dom/server';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import MarkdownPreview from 'component/common/markdown-preview';
|
import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
import SimpleMDE from 'react-simplemde-editor';
|
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 Toggle from 'react-toggle';
|
||||||
import { openEditorMenu } from 'util/contextMenu';
|
import { openEditorMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ type Props = {
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
affixClass?: string, // class applied to prefix/postfix label
|
affixClass?: string, // class applied to prefix/postfix label
|
||||||
useToggle?: boolean,
|
useToggle?: boolean,
|
||||||
|
firstInList?: boolean, // at the top of a list, no padding top
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormField extends React.PureComponent<Props> {
|
export class FormField extends React.PureComponent<Props> {
|
||||||
|
@ -41,6 +42,7 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
stretch,
|
stretch,
|
||||||
affixClass,
|
affixClass,
|
||||||
useToggle,
|
useToggle,
|
||||||
|
firstInList,
|
||||||
...inputProps
|
...inputProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -108,6 +110,7 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
<div
|
<div
|
||||||
className={classnames('form-field__input', {
|
className={classnames('form-field__input', {
|
||||||
'form-field--auto-height': type === 'markdown',
|
'form-field--auto-height': type === 'markdown',
|
||||||
|
'form-field--first-item': firstInList,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{prefix && (
|
{prefix && (
|
||||||
|
|
|
@ -92,9 +92,8 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
>
|
>
|
||||||
<CardMedia thumbnail={thumbnail} />
|
<CardMedia thumbnail={thumbnail} />
|
||||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
|
||||||
<div className="card__title-identity">
|
<div className="card__title-identity">
|
||||||
<div className="card__title--small">
|
<div className="card__title--small card__title--file-card">
|
||||||
<TruncatedText lines={3}>{title}</TruncatedText>
|
<TruncatedText lines={3}>{title}</TruncatedText>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtitle">
|
<div className="card__subtitle">
|
||||||
|
@ -103,13 +102,12 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
) : (
|
) : (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<UriIndicator uri={uri} link />
|
<UriIndicator uri={uri} link />
|
||||||
<div>
|
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||||
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{showPrice && <FilePrice uri={uri} />}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,6 +9,10 @@ type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
fetching: boolean,
|
fetching: boolean,
|
||||||
claim: ?{},
|
claim: ?{},
|
||||||
|
// below props are just passed to <CreditAmount />
|
||||||
|
filePage?: boolean,
|
||||||
|
inheritStyle?: boolean,
|
||||||
|
showLBC?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePrice extends React.PureComponent<Props> {
|
class FilePrice extends React.PureComponent<Props> {
|
||||||
|
@ -33,13 +37,16 @@ class FilePrice extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { costInfo, showFullPrice } = this.props;
|
const { costInfo, showFullPrice, filePage, inheritStyle, showLBC } = this.props;
|
||||||
|
|
||||||
return costInfo ? (
|
return costInfo ? (
|
||||||
<CreditAmount
|
<CreditAmount
|
||||||
|
showFree
|
||||||
|
filePage={filePage}
|
||||||
|
inheritStyle={inheritStyle}
|
||||||
|
showLBC={showLBC}
|
||||||
amount={costInfo.cost}
|
amount={costInfo.cost}
|
||||||
isEstimate={!costInfo.includesData}
|
isEstimate={!costInfo.includesData}
|
||||||
showFree
|
|
||||||
showFullPrice={showFullPrice}
|
showFullPrice={showFullPrice}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
|
|
|
@ -11,7 +11,6 @@ import classnames from 'classnames';
|
||||||
import FilePrice from 'component/filePrice';
|
import FilePrice from 'component/filePrice';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fullWidth: boolean, // removes the max-width css
|
|
||||||
showUri: boolean,
|
showUri: boolean,
|
||||||
showLocal: boolean,
|
showLocal: boolean,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
|
@ -28,13 +27,15 @@ type Props = {
|
||||||
updatePublishForm: ({}) => void,
|
updatePublishForm: ({}) => void,
|
||||||
hideNoResult: boolean, // don't show the tile if there is no claim at this uri
|
hideNoResult: boolean, // don't show the tile if there is no claim at this uri
|
||||||
displayHiddenMessage?: boolean,
|
displayHiddenMessage?: boolean,
|
||||||
|
displayDescription?: boolean,
|
||||||
|
small?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileTile extends React.PureComponent<Props> {
|
class FileTile extends React.PureComponent<Props> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
showUri: false,
|
showUri: false,
|
||||||
showLocal: false,
|
showLocal: false,
|
||||||
fullWidth: false,
|
displayDescription: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -57,13 +58,14 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
showUri,
|
showUri,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
fullWidth,
|
|
||||||
showLocal,
|
showLocal,
|
||||||
isDownloaded,
|
isDownloaded,
|
||||||
clearPublish,
|
clearPublish,
|
||||||
updatePublishForm,
|
updatePublishForm,
|
||||||
hideNoResult,
|
hideNoResult,
|
||||||
displayHiddenMessage,
|
displayHiddenMessage,
|
||||||
|
displayDescription,
|
||||||
|
small,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const shouldHide = !claimIsMine && obscureNsfw && metadata && metadata.nsfw;
|
const shouldHide = !claimIsMine && obscureNsfw && metadata && metadata.nsfw;
|
||||||
|
@ -96,7 +98,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
return !name && hideNoResult ? null : (
|
return !name && hideNoResult ? null : (
|
||||||
<section
|
<section
|
||||||
className={classnames('file-tile card--link', {
|
className={classnames('file-tile card--link', {
|
||||||
'file-tile--fullwidth': fullWidth,
|
'file-tile--small': small,
|
||||||
})}
|
})}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onKeyUp={onClick}
|
onKeyUp={onClick}
|
||||||
|
@ -108,20 +110,29 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
|
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
|
||||||
{!isResolvingUri && (
|
{!isResolvingUri && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="card__title--small card__title--file">
|
<div
|
||||||
<TruncatedText lines={2}>{title || name}</TruncatedText>
|
className={classnames({
|
||||||
|
'card__title--file': !small,
|
||||||
|
'card__title--x-small': small,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<TruncatedText lines={3}>{title || name}</TruncatedText>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtitle">
|
<div
|
||||||
|
className={classnames('card__subtitle', {
|
||||||
|
'card__subtitle--x-small': small,
|
||||||
|
})}
|
||||||
|
>
|
||||||
{showUri ? uri : channel || __('Anonymous')}
|
{showUri ? uri : channel || __('Anonymous')}
|
||||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||||
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
|
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtext card__subtext--small">
|
<FilePrice uri={uri} />
|
||||||
<TruncatedText lines={3}>{description}</TruncatedText>
|
{displayDescription && (
|
||||||
</div>
|
<div className="card__subtext card__subtext--small">
|
||||||
<div className="card__subtitle-price">
|
<TruncatedText lines={3}>{description}</TruncatedText>
|
||||||
<FilePrice uri={uri} />
|
</div>
|
||||||
</div>
|
)}
|
||||||
{!name && (
|
{!name && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('This location is unused.')}{' '}
|
{__('This location is unused.')}{' '}
|
||||||
|
|
|
@ -12,6 +12,7 @@ type Props = {
|
||||||
noPadding: ?boolean,
|
noPadding: ?boolean,
|
||||||
extraPadding: ?boolean,
|
extraPadding: ?boolean,
|
||||||
notContained: ?boolean, // No max-width, but keep the padding
|
notContained: ?boolean, // No max-width, but keep the padding
|
||||||
|
forContent: ?boolean,
|
||||||
loading: ?boolean,
|
loading: ?boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,15 +72,24 @@ class Page extends React.PureComponent<Props, State> {
|
||||||
loaderTimeout: ?TimeoutID;
|
loaderTimeout: ?TimeoutID;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { pageTitle, children, noPadding, extraPadding, notContained, loading } = this.props;
|
const {
|
||||||
|
pageTitle,
|
||||||
|
children,
|
||||||
|
noPadding,
|
||||||
|
extraPadding,
|
||||||
|
notContained,
|
||||||
|
loading,
|
||||||
|
forContent,
|
||||||
|
} = this.props;
|
||||||
const { showLoader } = this.state;
|
const { showLoader } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
className={classnames('main', {
|
className={classnames('main', {
|
||||||
'main--contained': !notContained && !noPadding && !extraPadding,
|
'main--contained': !notContained && !noPadding && !extraPadding && !forContent,
|
||||||
'main--no-padding': noPadding,
|
'main--no-padding': noPadding,
|
||||||
'main--extra-padding': extraPadding,
|
'main--extra-padding': extraPadding,
|
||||||
|
'main--for-content': forContent,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{pageTitle && (
|
{pageTitle && (
|
||||||
|
|
22
src/renderer/component/recommendedContent/index.js
Normal file
22
src/renderer/component/recommendedContent/index.js
Normal 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);
|
76
src/renderer/component/recommendedContent/view.jsx
Normal file
76
src/renderer/component/recommendedContent/view.jsx
Normal 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 => {
|
||||||
This will be moved into a selector when I add recommended content from search results (my next PR) This will be moved into a selector when I add recommended content from search results (my next PR)
👍 👍
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ class RewardSummary extends React.Component<Props> {
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('You have')}
|
{__('You have')}
|
||||||
|
|
||||||
<CreditAmount noStyle amount={unclaimedRewardAmount} precision={8} />
|
<CreditAmount inheritStyle amount={unclaimedRewardAmount} precision={8} />
|
||||||
|
|
||||||
{__('in unclaimed rewards')}.
|
{__('in unclaimed rewards')}.
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -6,8 +6,8 @@ import DateTime from 'component/dateTime';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { buildURI } from 'lbry-redux';
|
import { buildURI } from 'lbry-redux';
|
||||||
import * as txnTypes from 'constants/transaction_types';
|
import * as txnTypes from 'constants/transaction_types';
|
||||||
import type { Transaction } from '../view';
|
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
|
import type { Transaction } from '../view';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
|
@ -25,12 +25,6 @@ class TransactionListItem extends React.PureComponent<Props> {
|
||||||
(this: any).abandonClaim = this.abandonClaim.bind(this);
|
(this: any).abandonClaim = this.abandonClaim.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
abandonClaim() {
|
|
||||||
const { txid, nout } = this.props.transaction;
|
|
||||||
|
|
||||||
this.props.revokeClaim(txid, nout);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLink(type: string) {
|
getLink(type: string) {
|
||||||
if (type === txnTypes.TIP) {
|
if (type === txnTypes.TIP) {
|
||||||
return <Button icon={ICONS.UNLOCK} onClick={this.abandonClaim} title={__('Unlock 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')} />;
|
return <Button icon={ICONS.TRASH} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
capitalize(string: string) {
|
abandonClaim() {
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
const { txid, nout } = this.props.transaction;
|
||||||
|
|
||||||
|
this.props.revokeClaim(txid, nout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capitalize = (string: string) => string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { reward, transaction, isRevokeable } = this.props;
|
const { reward, transaction, isRevokeable } = this.props;
|
||||||
const { amount, claim_id: claimId, claim_name: name, date, fee, txid, type } = transaction;
|
const { amount, claim_id: claimId, claim_name: name, date, fee, txid, type } = transaction;
|
||||||
|
@ -55,12 +53,12 @@ class TransactionListItem extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<CreditAmount amount={amount} plain noStyle showPlus precision={8} />
|
<CreditAmount inheritStyle showPlus amount={amount} precision={8} />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{fee !== 0 && (
|
{fee !== 0 && (
|
||||||
<span className="table__item-label">
|
<span className="table__item-label">
|
||||||
<CreditAmount plain noStyle fee amount={fee} precision={8} />
|
<CreditAmount inheritStyle fee amount={fee} precision={8} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -18,7 +18,7 @@ export default (props: Props) => {
|
||||||
<Button
|
<Button
|
||||||
icon={icons.GLOBE}
|
icon={icons.GLOBE}
|
||||||
button="alt"
|
button="alt"
|
||||||
label={__('View on Web')}
|
label={__('Share')}
|
||||||
href={`http://spee.ch/${speechURL}`}
|
href={`http://spee.ch/${speechURL}`}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ModalAffirmPurchase extends React.PureComponent {
|
||||||
>
|
>
|
||||||
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
<FilePrice uri={uri} showFullPrice look="plain" />
|
<FilePrice uri={uri} showFullPrice inheritStyle showLBC={false} />
|
||||||
</strong>{' '}
|
</strong>{' '}
|
||||||
{__('credits')}.
|
{__('credits')}.
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -14,14 +14,12 @@ import Button from 'component/button';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
import ViewOnWebButton from 'component/viewOnWebButton';
|
import ViewOnWebButton from 'component/viewOnWebButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import * as settings from 'constants/settings';
|
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
import type { Subscription } from 'types/subscription';
|
import type { Subscription } from 'types/subscription';
|
||||||
import FileDownloadLink from 'component/fileDownloadLink';
|
import FileDownloadLink from 'component/fileDownloadLink';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { FormField, FormRow } from 'component/common/form';
|
|
||||||
import ToolTip from 'component/common/tooltip';
|
|
||||||
import getMediaType from 'util/getMediaType';
|
import getMediaType from 'util/getMediaType';
|
||||||
|
import RecommendedContent from 'component/recommendedContent';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: Claim,
|
claim: Claim,
|
||||||
|
@ -37,14 +35,12 @@ type Props = {
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
autoplay: boolean,
|
|
||||||
costInfo: ?{},
|
costInfo: ?{},
|
||||||
navigate: (string, ?{}) => void,
|
navigate: (string, ?{}) => void,
|
||||||
openModal: ({ id: string }, { uri: string }) => void,
|
openModal: ({ id: string }, { uri: string }) => void,
|
||||||
fetchFileInfo: string => void,
|
fetchFileInfo: string => void,
|
||||||
fetchCostInfo: string => void,
|
fetchCostInfo: string => void,
|
||||||
prepareEdit: ({}, string) => void,
|
prepareEdit: ({}, string) => void,
|
||||||
setClientSetting: (string, boolean | string) => void,
|
|
||||||
checkSubscription: ({ channelName: string, uri: string }) => void,
|
checkSubscription: ({ channelName: string, uri: string }) => void,
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
};
|
};
|
||||||
|
@ -62,12 +58,6 @@ class FilePage extends React.Component<Props> {
|
||||||
'application',
|
'application',
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
|
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
|
||||||
|
|
||||||
|
@ -88,10 +78,6 @@ class FilePage extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onAutoplayChange(event: SyntheticInputEvent<*>) {
|
|
||||||
this.props.setClientSetting(settings.AUTOPLAY, event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkSubscription = (props: Props) => {
|
checkSubscription = (props: Props) => {
|
||||||
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
||||||
props.checkSubscription({
|
props.checkSubscription({
|
||||||
|
@ -119,7 +105,6 @@ class FilePage extends React.Component<Props> {
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
prepareEdit,
|
prepareEdit,
|
||||||
navigate,
|
navigate,
|
||||||
autoplay,
|
|
||||||
costInfo,
|
costInfo,
|
||||||
fileInfo,
|
fileInfo,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -160,99 +145,79 @@ class FilePage extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page extraPadding>
|
<Page forContent>
|
||||||
{!claim || !metadata ? (
|
<section className="content__wrapper">
|
||||||
<section>
|
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
|
||||||
<span className="empty">{__('Empty claim or metadata info.')}</span>
|
{!showFile &&
|
||||||
</section>
|
(thumbnail ? (
|
||||||
) : (
|
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||||
<section className="card">
|
) : (
|
||||||
{showFile && (
|
<div
|
||||||
<FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />
|
className={classnames('content__empty', {
|
||||||
)}
|
'content__empty--nsfw': shouldObscureThumbnail,
|
||||||
{!showFile &&
|
})}
|
||||||
(thumbnail ? (
|
>
|
||||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
<div className="card__media-text">
|
||||||
) : (
|
{__("Sorry, looks like we can't preview this file.")}
|
||||||
<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)} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="card__subtitle card__subtitle--file">
|
))}
|
||||||
{__('Published on')}
|
|
||||||
<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">
|
<div className="card__content">
|
||||||
<FileDownloadLink uri={uri} />
|
<div className="card__title-identity--file">
|
||||||
<FileActions uri={uri} claimId={claim.claim_id} />
|
<h1 className="card__title card__title--file">{title}</h1>
|
||||||
</div>
|
<div className="card__title-identity-icons">
|
||||||
|
{isRewardContent && <Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />}
|
||||||
|
<FilePrice filePage uri={normalizeURI(uri)} />
|
||||||
</div>
|
</div>
|
||||||
<FormRow padded>
|
</div>
|
||||||
<ToolTip onComponent body={__('Automatically download and play free content.')}>
|
<span className="card__subtitle card__subtitle--file">
|
||||||
<FormField
|
{__('Published on')}
|
||||||
useToggle
|
<DateTime block={height} show={DateTime.SHOW_DATE} />
|
||||||
name="autoplay"
|
</span>
|
||||||
type="checkbox"
|
{metadata.nsfw && <div>NSFW</div>}
|
||||||
postfix={__('Autoplay')}
|
<div className="card__channel-info">
|
||||||
checked={autoplay}
|
<UriIndicator uri={uri} link />
|
||||||
onChange={this.onAutoplayChange}
|
</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>
|
||||||
<div className="card__content--extra-padding">
|
<div className="card__content--extra-padding">
|
||||||
<FileDetails uri={uri} />
|
<FileDetails uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
)}
|
</section>
|
||||||
|
<RecommendedContent uri={uri} channelUri={`lbry://${subscriptionUri}`} />
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ class SearchPage extends React.PureComponent<Props> {
|
||||||
<Icon icon={icons.HELP} />
|
<Icon icon={icons.HELP} />
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</div>
|
</div>
|
||||||
<FileTile fullWidth showUri displayHiddenMessage uri={normalizeURI(query)} />
|
<FileTile showUri displayHiddenMessage uri={normalizeURI(query)} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
<FileListSearch query={query} />
|
<FileListSearch query={query} />
|
||||||
|
|
|
@ -203,6 +203,12 @@ p {
|
||||||
padding-right: 100px;
|
padding-right: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main--for-content {
|
||||||
|
padding: $spacing-width * 2/3;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.page__header {
|
.page__header {
|
||||||
padding: $spacing-vertical * 2/3;
|
padding: $spacing-vertical * 2/3;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
@ -250,11 +256,10 @@ p {
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-amount {
|
.credit-amount {
|
||||||
border-radius: 5px;
|
|
||||||
font-family: 'metropolis-bold';
|
font-family: 'metropolis-bold';
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
padding: 5px;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
padding: $spacing-vertical * 1/6 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-amount--large {
|
.credit-amount--large {
|
||||||
|
@ -262,30 +267,36 @@ p {
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.credit-amount--file-page {
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.credit-amount--free {
|
.credit-amount--free {
|
||||||
color: var(--color-dark-blue);
|
color: var(--color-secondary);
|
||||||
background-color: var(--color-secondary);
|
|
||||||
|
&.credit-amount--file-page {
|
||||||
|
color: var(--color-dark-blue);
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-amount--cost {
|
.credit-amount--cost {
|
||||||
color: var(--color-black);
|
color: var(--color-yellow);
|
||||||
background-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;
|
background-color: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: inherit;
|
font-weight: inherit;
|
||||||
font-size: 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';
|
font-family: 'metropolis-medium';
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider__horizontal {
|
.divider__horizontal {
|
||||||
|
|
|
@ -9,7 +9,7 @@ $large-breakpoint: 1921px;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Widths & spacings */
|
/* Widths & spacings */
|
||||||
--side-nav-width: 220px;
|
--side-nav-width: 190px;
|
||||||
--side-nav-width-m: 240px;
|
--side-nav-width-m: 240px;
|
||||||
--side-nav-width-l: 320px;
|
--side-nav-width-l: 320px;
|
||||||
--font-size-subtext-multiple: 0.92;
|
--font-size-subtext-multiple: 0.92;
|
||||||
|
@ -153,9 +153,14 @@ $large-breakpoint: 1921px;
|
||||||
--success-msg-border: var(--color-green-blue);
|
--success-msg-border: var(--color-green-blue);
|
||||||
--success-msg-bg: var(--color-green-light);
|
--success-msg-bg: var(--color-green-light);
|
||||||
|
|
||||||
/* File Tile Card */
|
/* File */
|
||||||
--file-tile--media-height: 125px;
|
--file-tile-media-height: 125px;
|
||||||
--file-tile--media-width: calc(125px * (16 / 9));
|
--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 */
|
||||||
--modal-width: 440px;
|
--modal-width: 440px;
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
@media only screen and (min-width: $medium-breakpoint) {
|
@media only screen and (min-width: $medium-breakpoint) {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 4px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,13 +113,17 @@
|
||||||
.card__title--small {
|
.card__title--small {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
padding-top: $spacing-vertical / 3;
|
|
||||||
|
|
||||||
@media only screen and (min-width: $large-breakpoint) {
|
@media only screen and (min-width: $large-breakpoint) {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card__title--x-small {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.card__title--file {
|
.card__title--file {
|
||||||
font-family: 'metropolis-bold';
|
font-family: 'metropolis-bold';
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
|
@ -130,25 +133,36 @@
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card__title--file-card {
|
||||||
|
padding-top: $spacing-vertical * 1/3;
|
||||||
|
}
|
||||||
|
|
||||||
.card__subtitle {
|
.card__subtitle {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'metropolis-medium';
|
font-family: 'metropolis-medium';
|
||||||
color: var(--card-text-color);
|
color: var(--card-text-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-top: $spacing-vertical * 1/6;
|
margin: 0 0 0 $spacing-vertical * 1/3;
|
||||||
|
|
||||||
&:not(:first-of-type) {
|
|
||||||
margin: 0 $spacing-vertical * 1/3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card__subtitle--x-small {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.card__subtitle-price {
|
.card__subtitle-price {
|
||||||
padding-top: $spacing-vertical * 1/3;
|
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 {
|
.card__meta {
|
||||||
color: var(--color-help);
|
color: var(--color-help);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -312,7 +326,11 @@
|
||||||
|
|
||||||
.card-row__scroll-btns {
|
.card-row__scroll-btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-right: $spacing-width;
|
padding-right: $spacing-width * 1/3;
|
||||||
|
|
||||||
|
@media (min-width: $medium-breakpoint) {
|
||||||
|
padding-right: $spacing-width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-row__scrollhouse {
|
.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 {
|
.card__success-msg {
|
||||||
border-left: 2px solid var(--success-msg-border);
|
border-left: 2px solid var(--success-msg-border);
|
||||||
color: var(--success-msg-color);
|
color: var(--success-msg-color);
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
.content__wrapper {
|
||||||
|
max-width: var(--card-max-width);
|
||||||
|
flex: 1 0 var(--file-page-min-width);
|
||||||
|
}
|
||||||
|
|
||||||
.content__embedded {
|
.content__embedded {
|
||||||
background-color: var(--color-black);
|
background-color: var(--color-black);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -22,11 +22,11 @@
|
||||||
|
|
||||||
.file-tile {
|
.file-tile {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: $spacing-vertical;
|
padding-top: $spacing-vertical;
|
||||||
|
|
||||||
.card__media {
|
.card__media {
|
||||||
height: var(--file-tile--media-height);
|
height: var(--file-tile-media-height);
|
||||||
flex: 0 0 var(--file-tile--media-width);
|
flex: 0 0 var(--file-tile-media-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtitle {
|
.card__subtitle {
|
||||||
|
@ -34,8 +34,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-tile--fullwidth {
|
.file-tile.file-tile--small {
|
||||||
max-width: none;
|
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 {
|
.file-tile__info {
|
||||||
|
|
|
@ -51,6 +51,10 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field__input.form-field--first-item {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.form-field__input {
|
.form-field__input {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-top: $spacing-vertical / 3;
|
padding-top: $spacing-vertical / 3;
|
||||||
|
|
|
@ -6,9 +6,13 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 $spacing-width;
|
padding: 0 $spacing-width * 1/3;
|
||||||
background-color: var(--color-bg);
|
background-color: var(--color-bg);
|
||||||
box-shadow: var(--box-shadow-header);
|
box-shadow: var(--box-shadow-header);
|
||||||
|
|
||||||
|
@media (min-width: $medium-breakpoint) {
|
||||||
|
padding: 0 $spacing-width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__navigation {
|
.header__navigation {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
.nav {
|
.nav {
|
||||||
width: var(--side-nav-width);
|
width: var(--side-nav-width);
|
||||||
background-color: var(--nav-bg-color);
|
background-color: var(--nav-bg-color);
|
||||||
padding: $spacing-width;
|
padding: $spacing-width * 1/3;
|
||||||
color: var(--nav-color);
|
color: var(--nav-color);
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
|
@ -11,8 +11,13 @@
|
||||||
margin: $spacing-vertical $spacing-vertical * 2/3;
|
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) {
|
@media (min-width: $large-breakpoint) {
|
||||||
width: calc(var(--side-nav-width) * 1.1);
|
width: calc(var(--side-nav-width) * 1.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue
Minor: Split to multiple lines.