diff --git a/.eslintrc.json b/.eslintrc.json index abeff7ac8..fb260f101 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -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 } } diff --git a/.gitignore b/.gitignore index 52f16b2e0..4fc96cbb9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ yarn-error.log package-lock.json .idea/ -/build/daemon.ver \ No newline at end of file +/build/daemon* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a1907091e..aceda5a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,35 +5,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -### Added - -### Changed - ### Fixed - -## [0.23.0] - 2018-07-25 + * Edit option missing from certain published claims ([#1756](https://github.com/lbryio/lbry-desktop/issues/1756)) + * Fix navigation issue with channels that have more than one page ([#1797](https://github.com/lbryio/lbry-desktop/pull/1797)) ### Added - * 3D file viewer for OBJ & STL file types ([#1558](https://github.com/lbryio/lbry-desktop/pull/1558)) - * Thumbnail preview on publish page ([#1755](https://github.com/lbryio/lbry-desktop/pull/1755)) - * Abandoned claim transactions now show in wallet history ([#1769](https://github.com/lbryio/lbry-desktop/pull/1769)) - * Emoji support in the claim description ([#1800](https://github.com/lbryio/lbry-desktop/pull/1800)) - * PDF preview ([#1576](https://github.com/lbryio/lbry-desktop/pull/1576)) + + * Added 3D file viewer for OBJ & STL file types ([#1558](https://github.com/lbryio/lbry-desktop/pull/1558)) + * Added thumbnail preview on publish page ([#1755](https://github.com/lbryio/lbry-desktop/pull/1755)) ### Changed - * Upgraded LBRY Protocol to [version 0.20.4](https://github.com/lbryio/lbry/releases/tag/v0.20.4) to assist with download availability and lower CPU usage on idle. - * Upgraded Electron-Builder and Updater to support signing the daemon and improving the auto update process ([#1784](https://github.com/lbryio/lbry-desktop/pull/1784)) - * Channel page now uses caching, faster switching between channels/claims ([#1750](https://github.com/lbryio/lbry-desktop/pull/1750)) + + * Rename the Github repo to lbry-desktop ([#1765](https://github.com/lbryio/lbry-desktop/pull/1765)) * Only show video error modal if you are on the video page & don't retry to play failed videos ([#1768](https://github.com/lbryio/lbry-desktop/pull/1768)) * Actually hide NSFW files if a user chooses to hide NSFW content via the settings page ([#1748](https://github.com/lbryio/lbry-desktop/pull/1748)) * Hide the "Community top bids" section if user chooses to hide NSFW content ([#1760](https://github.com/lbryio/lbry-desktop/pull/1760)) - * More descriptive error message when Shapeshift is unavailable ([#1771](https://github.com/lbryio/lbry-desktop/pull/1771)) - * Rename the Github repo to lbry-desktop ([#1765](https://github.com/lbryio/lbry-desktop/pull/1765)) - -### Fixed - * Edit option missing from certain published claims ([#1756](https://github.com/lbryio/lbry-desktop/issues/1756)) - * Fix navigation issue with channels that have more than one page ([#1797](https://github.com/lbryio/lbry-desktop/pull/1797)) + * Add a more descriptive error message when Shapeshift is unavailable ([#1771](https://github.com/lbryio/lbry-desktop/pull/1771)) ## [0.22.2] - 2018-07-09 diff --git a/package.json b/package.json index cdf37a7b8..c98337920 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.23.0", + "version": "0.22.2", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "keywords": [ "lbry" diff --git a/src/renderer/component/common/credit-amount.jsx b/src/renderer/component/common/credit-amount.jsx index 0147c0154..67243394f 100644 --- a/src/renderer/component/common/credit-amount.jsx +++ b/src/renderer/component/common/credit-amount.jsx @@ -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 { @@ -22,6 +23,7 @@ class CreditAmount extends React.PureComponent { showFree: false, showFullPrice: false, showPlus: false, + showLBC: true, }; render() { @@ -33,9 +35,10 @@ class CreditAmount extends React.PureComponent { 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 { amountText = `+${amountText}`; } - if (!plain) { + if (showLBC) { amountText = `${amountText} ${__('LBC')}`; } @@ -78,8 +81,8 @@ class CreditAmount extends React.PureComponent { '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} diff --git a/src/renderer/component/common/form-components/form-field.jsx b/src/renderer/component/common/form-components/form-field.jsx index 0cac65160..4c2045881 100644 --- a/src/renderer/component/common/form-components/form-field.jsx +++ b/src/renderer/component/common/form-components/form-field.jsx @@ -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 } 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 { @@ -41,6 +42,7 @@ export class FormField extends React.PureComponent { stretch, affixClass, useToggle, + firstInList, ...inputProps } = this.props; @@ -108,6 +110,7 @@ export class FormField extends React.PureComponent {
{prefix && ( diff --git a/src/renderer/component/common/spinner.jsx b/src/renderer/component/common/spinner.jsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 7a7e4f7d5..f63e23d13 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -92,9 +92,8 @@ class FileCard extends React.PureComponent { onContextMenu={handleContextMenu} > -
{showPrice && }
-
+
{title}
@@ -103,13 +102,12 @@ class FileCard extends React.PureComponent { ) : ( -
- {isRewardContent && } - {fileInfo && } -
+ {isRewardContent && } + {fileInfo && }
)}
+ {showPrice && }
); diff --git a/src/renderer/component/filePrice/view.jsx b/src/renderer/component/filePrice/view.jsx index e40a6c25e..ebb0318f1 100644 --- a/src/renderer/component/filePrice/view.jsx +++ b/src/renderer/component/filePrice/view.jsx @@ -9,6 +9,10 @@ type Props = { uri: string, fetching: boolean, claim: ?{}, + // below props are just passed to + filePage?: boolean, + inheritStyle?: boolean, + showLBC?: boolean, }; class FilePrice extends React.PureComponent { @@ -33,13 +37,16 @@ class FilePrice extends React.PureComponent { }; render() { - const { costInfo, showFullPrice } = this.props; + const { costInfo, showFullPrice, filePage, inheritStyle, showLBC } = this.props; return costInfo ? ( ) : null; diff --git a/src/renderer/component/fileTile/view.jsx b/src/renderer/component/fileTile/view.jsx index f7945ed75..2535eb886 100644 --- a/src/renderer/component/fileTile/view.jsx +++ b/src/renderer/component/fileTile/view.jsx @@ -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 { static defaultProps = { showUri: false, showLocal: false, - fullWidth: false, + displayDescription: true, }; componentDidMount() { @@ -57,13 +58,14 @@ class FileTile extends React.PureComponent { 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 { return !name && hideNoResult ? null : (
{ {isResolvingUri &&
{__('Loading...')}
} {!isResolvingUri && ( -
- {title || name} +
+ {title || name}
-
+
{showUri ? uri : channel || __('Anonymous')} {isRewardContent && } {showLocal && isDownloaded && }
-
- {description} -
-
- -
+ + {displayDescription && ( +
+ {description} +
+ )} {!name && ( {__('This location is unused.')}{' '} diff --git a/src/renderer/component/page/view.jsx b/src/renderer/component/page/view.jsx index 34998d528..7286c9046 100644 --- a/src/renderer/component/page/view.jsx +++ b/src/renderer/component/page/view.jsx @@ -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 { 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 (
{pageTitle && ( diff --git a/src/renderer/component/recommendedContent/index.js b/src/renderer/component/recommendedContent/index.js new file mode 100644 index 000000000..2588d29c9 --- /dev/null +++ b/src/renderer/component/recommendedContent/index.js @@ -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); diff --git a/src/renderer/component/recommendedContent/view.jsx b/src/renderer/component/recommendedContent/view.jsx new file mode 100644 index 000000000..df2ac55e6 --- /dev/null +++ b/src/renderer/component/recommendedContent/view.jsx @@ -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, + autoplay: boolean, + setAutoplay: boolean => void, + fetchClaims: (string, number) => void, +}; + +export default class RecommendedContent extends React.PureComponent { + 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 ( +
+ + + setAutoplay(e.target.checked)} + /> + + + {recommendedContent && + recommendedContent.map(({ permanent_url: permanentUrl }) => ( + + ))} +
+ ); + } +} diff --git a/src/renderer/component/rewardSummary/view.jsx b/src/renderer/component/rewardSummary/view.jsx index 0a74fdfb6..87b20ca6c 100644 --- a/src/renderer/component/rewardSummary/view.jsx +++ b/src/renderer/component/rewardSummary/view.jsx @@ -31,7 +31,7 @@ class RewardSummary extends React.Component { {__('You have')}   - +   {__('in unclaimed rewards')}. diff --git a/src/renderer/component/transactionList/internal/transaction-list-item.jsx b/src/renderer/component/transactionList/internal/transaction-list-item.jsx index 379758722..f59c920a8 100644 --- a/src/renderer/component/transactionList/internal/transaction-list-item.jsx +++ b/src/renderer/component/transactionList/internal/transaction-list-item.jsx @@ -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 { (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
+ ))} -
- - -
+
+
+

{title}

+
+ {isRewardContent && } +
- - - + + {__('Published on')}  + + + {metadata.nsfw &&
NSFW
} +
+ +
+
+
+ {claimIsMine ? ( +
+ +
+ + +
-
- )} +
+ + ); } diff --git a/src/renderer/page/search/view.jsx b/src/renderer/page/search/view.jsx index 9e47ebadd..5db8016ee 100644 --- a/src/renderer/page/search/view.jsx +++ b/src/renderer/page/search/view.jsx @@ -73,7 +73,7 @@ class SearchPage extends React.PureComponent {
- + )} diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss index 8ea4b0907..8bd6f403c 100644 --- a/src/renderer/scss/_gui.scss +++ b/src/renderer/scss/_gui.scss @@ -203,6 +203,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; @@ -250,11 +256,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 { @@ -262,30 +267,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 { diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss index 517f33fdd..30649058e 100644 --- a/src/renderer/scss/_vars.scss +++ b/src/renderer/scss/_vars.scss @@ -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; @@ -153,9 +153,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; diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss index f44a60d91..40ba15923 100644 --- a/src/renderer/scss/component/_card.scss +++ b/src/renderer/scss/component/_card.scss @@ -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); diff --git a/src/renderer/scss/component/_content.scss b/src/renderer/scss/component/_content.scss index 7f324d20f..ea0c7b3e4 100644 --- a/src/renderer/scss/component/_content.scss +++ b/src/renderer/scss/component/_content.scss @@ -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%; diff --git a/src/renderer/scss/component/_file-list.scss b/src/renderer/scss/component/_file-list.scss index c7e21cc8d..b4ed9e7ac 100644 --- a/src/renderer/scss/component/_file-list.scss +++ b/src/renderer/scss/component/_file-list.scss @@ -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 { diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss index 1c8db8db9..f27667ec2 100644 --- a/src/renderer/scss/component/_form-field.scss +++ b/src/renderer/scss/component/_form-field.scss @@ -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; diff --git a/src/renderer/scss/component/_header.scss b/src/renderer/scss/component/_header.scss index 32058ec7c..1f9ab038a 100644 --- a/src/renderer/scss/component/_header.scss +++ b/src/renderer/scss/component/_header.scss @@ -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 { diff --git a/src/renderer/scss/component/_nav.scss b/src/renderer/scss/component/_nav.scss index 8dc4587a4..fb1162c9a 100644 --- a/src/renderer/scss/component/_nav.scss +++ b/src/renderer/scss/component/_nav.scss @@ -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); } }