+
{title && subtitle && (
-
+
{title}
-
{subtitle}
+
{subtitle}
)}
diff --git a/src/ui/constants/modal_types.js b/src/ui/constants/modal_types.js
index bf4b1ad4c..14eb7429d 100644
--- a/src/ui/constants/modal_types.js
+++ b/src/ui/constants/modal_types.js
@@ -6,7 +6,6 @@ export const DOWNLOADING = 'downloading';
export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded';
export const AUTO_UPDATE_CONFIRM = 'auto_update_confirm';
export const ERROR = 'error';
-export const INSUFFICIENT_CREDITS = 'insufficient_credits';
export const UPGRADE = 'upgrade';
export const WELCOME = 'welcome';
export const EMAIL_COLLECTION = 'email_collection';
diff --git a/src/ui/modal/modalCreditIntro/index.js b/src/ui/modal/modalCreditIntro/index.js
deleted file mode 100644
index 69f8b718a..000000000
--- a/src/ui/modal/modalCreditIntro/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { connect } from 'react-redux';
-import { doSetClientSetting } from 'redux/actions/settings';
-import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc';
-import { selectBalance } from 'lbry-redux';
-import { doHideModal } from 'redux/actions/app';
-import * as settings from 'constants/settings';
-import ModalCreditIntro from './view';
-import { navigate } from '@reach/router';
-
-const select = state => ({
- currentBalance: selectBalance(state),
- isRewardApproved: selectUserIsRewardApproved(state),
- totalRewardValue: selectUnclaimedRewardValue(state),
-});
-
-const perform = dispatch => () => ({
- addBalance: () => {
- navigate('/$/getcredits');
- dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
- dispatch(doHideModal());
- },
- closeModal: () => {
- dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
- dispatch(doHideModal());
- },
-});
-
-export default connect(
- select,
- perform
-)(ModalCreditIntro);
diff --git a/src/ui/modal/modalCreditIntro/view.jsx b/src/ui/modal/modalCreditIntro/view.jsx
deleted file mode 100644
index 5d3f411ee..000000000
--- a/src/ui/modal/modalCreditIntro/view.jsx
+++ /dev/null
@@ -1,56 +0,0 @@
-// @flow
-import React from 'react';
-import { Modal } from 'modal/modal';
-import CurrencySymbol from 'component/common/lbc-symbol';
-import CreditAmount from 'component/common/credit-amount';
-import Button from 'component/button';
-
-type Props = {
- totalRewardValue: number,
- currentBalance: number,
- closeModal: () => void,
- addBalance: () => void,
-};
-
-const ModalCreditIntro = (props: Props) => {
- const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
- const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
-
- return (
-
-
-
- Some actions require LBRY credits (
-
-
-
- ), the blockchain token that powers the LBRY network.
-
- {currentBalance <= 0 && (
-
- You currently have , so the actions
- you can take are limited.
-
- )}
- {Boolean(totalRewardValue) && (
-
- {__(' There are a variety of ways to get credits, including more than')}{' '}
- {' '}
- {__('in free rewards for participating in the LBRY beta.')}
-
- )}
-
-
-
-
-
-
-
- );
-};
-
-export default ModalCreditIntro;
diff --git a/src/ui/modal/modalRouter/index.js b/src/ui/modal/modalRouter/index.js
index 2ff9387a5..422f215ca 100644
--- a/src/ui/modal/modalRouter/index.js
+++ b/src/ui/modal/modalRouter/index.js
@@ -1,28 +1,15 @@
import { connect } from 'react-redux';
-import * as settings from 'constants/settings';
-import { selectBalance, makeSelectCostInfoForUri, selectError, doToast } from 'lbry-redux';
-import { makeSelectClientSetting } from 'redux/selectors/settings';
-import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc';
import { selectModal } from 'redux/selectors/app';
import { doOpenModal } from 'redux/actions/app';
+import { selectError } from 'lbry-redux';
import ModalRouter from './view';
const select = (state, props) => ({
- balance: selectBalance(state),
- showPageCost: makeSelectCostInfoForUri(props.uri)(state),
- isVerificationCandidate: selectUserIsVerificationCandidate(state),
- isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state),
- isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)(
- state
- ),
- isWelcomeAcknowledged: makeSelectClientSetting(settings.NEW_USER_ACKNOWLEDGED)(state),
- user: selectUser(state),
modal: selectModal(state),
error: selectError(state),
});
const perform = dispatch => ({
- showToast: props => dispatch(doToast(props)),
openModal: props => dispatch(doOpenModal(props)),
});
diff --git a/src/ui/modal/modalRouter/view.jsx b/src/ui/modal/modalRouter/view.jsx
index 69d68d0fb..90e524f36 100644
--- a/src/ui/modal/modalRouter/view.jsx
+++ b/src/ui/modal/modalRouter/view.jsx
@@ -10,7 +10,6 @@ import ModalUpgrade from 'modal/modalUpgrade';
import ModalWelcome from 'modal/modalWelcome';
import ModalFirstReward from 'modal/modalFirstReward';
import ModalRewardApprovalRequired from 'modal/modalRewardApprovalRequired';
-import ModalCreditIntro from 'modal/modalCreditIntro';
import ModalRemoveFile from 'modal/modalRemoveFile';
import ModalTransactionFailed from 'modal/modalTransactionFailed';
import ModalFileTimeout from 'modal/modalFileTimeout';
@@ -32,162 +31,76 @@ import ModalRewardCode from 'modal/modalRewardCode';
type Props = {
modal: { id: string, modalProps: {} },
error: { message: string },
- openModal: string => void,
- page: string,
- isWelcomeAcknowledged: boolean,
- isEmailCollectionAcknowledged: boolean,
- isVerificationCandidate: boolean,
- isCreditIntroAcknowledged: boolean,
- balance: number,
- showPageCost: number,
- user: {
- is_reward_approved: boolean,
- is_identity_verified: boolean,
- has_verified_email: boolean,
- },
};
-type State = {
- lastTransitionModal: ?string,
- lastTransitionPage: ?string,
-};
+function ModalRouter(props: Props) {
+ const { modal, error } = props;
-class ModalRouter extends React.PureComponent
{
- constructor(props: Props) {
- super(props);
-
- this.state = {
- lastTransitionModal: null,
- lastTransitionPage: null,
- };
+ if (error) {
+ return ;
}
- componentWillMount() {
- this.showTransitionModals(this.props);
+ if (!modal) {
+ return null;
}
- componentWillReceiveProps(nextProps: Props) {
- this.showTransitionModals(nextProps);
- }
+ const { id, modalProps } = modal;
- showTransitionModals(props: Props) {
- const { modal, openModal, page } = props;
-
- if (modal) {
- return;
- }
-
- const transitionModal = [this.checkShowCreditIntro].reduce(
- (acc, func) => (!acc ? func.bind(this)(props) : acc),
- false
- );
-
- if (
- transitionModal &&
- (transitionModal !== this.state.lastTransitionModal || page !== this.state.lastTransitionPage)
- ) {
- openModal(transitionModal);
- this.setState({
- lastTransitionModal: transitionModal,
- lastTransitionPage: page,
- });
- }
- }
-
- checkShowCreditIntro(props: Props) {
- // @if TARGET='app'
- // This doesn't make sense to show until the web has wallet support
- const { balance, page, isCreditIntroAcknowledged } = props;
-
- if (
- balance === 0 &&
- !isCreditIntroAcknowledged &&
- (['send', 'publish'].includes(page) || this.isPaidShowPage(props))
- ) {
- return MODALS.INSUFFICIENT_CREDITS;
- }
- // @endif
-
- return undefined;
- }
-
- isPaidShowPage(props: Props) {
- const { page, showPageCost } = props;
- // Fix me
- return page === 'show' && showPageCost > 0;
- }
-
- render() {
- const { modal, error } = this.props;
-
- if (error) {
- return ;
- }
-
- if (!modal) {
+ switch (id) {
+ case MODALS.UPGRADE:
+ return ;
+ case MODALS.DOWNLOADING:
+ return ;
+ case MODALS.AUTO_UPDATE_DOWNLOADED:
+ return ;
+ case MODALS.AUTO_UPDATE_CONFIRM:
+ return ;
+ case MODALS.ERROR:
+ return ;
+ case MODALS.FILE_TIMEOUT:
+ return ;
+ case MODALS.WELCOME:
+ return ;
+ case MODALS.FIRST_REWARD:
+ return ;
+ case MODALS.AUTHENTICATION_FAILURE:
+ return ;
+ case MODALS.TRANSACTION_FAILED:
+ return ;
+ case MODALS.REWARD_APPROVAL_REQUIRED:
+ return ;
+ case MODALS.CONFIRM_FILE_REMOVE:
+ return ;
+ case MODALS.AFFIRM_PURCHASE:
+ return ;
+ case MODALS.CONFIRM_CLAIM_REVOKE:
+ return ;
+ case MODALS.PHONE_COLLECTION:
+ return ;
+ case MODALS.FIRST_SUBSCRIPTION:
+ return ;
+ case MODALS.SEND_TIP:
+ return ;
+ case MODALS.SOCIAL_SHARE:
+ return ;
+ case MODALS.PUBLISH:
+ return ;
+ case MODALS.CONFIRM_EXTERNAL_LINK:
+ return ;
+ case MODALS.CONFIRM_TRANSACTION:
+ return ;
+ case MODALS.CONFIRM_THUMBNAIL_UPLOAD:
+ return ;
+ case MODALS.WALLET_ENCRYPT:
+ return ;
+ case MODALS.WALLET_DECRYPT:
+ return ;
+ case MODALS.WALLET_UNLOCK:
+ return ;
+ case MODALS.REWARD_GENERATED_CODE:
+ return ;
+ default:
return null;
- }
-
- const { id, modalProps } = modal;
-
- switch (id) {
- case MODALS.UPGRADE:
- return ;
- case MODALS.DOWNLOADING:
- return ;
- case MODALS.AUTO_UPDATE_DOWNLOADED:
- return ;
- case MODALS.AUTO_UPDATE_CONFIRM:
- return ;
- case MODALS.ERROR:
- return ;
- case MODALS.FILE_TIMEOUT:
- return ;
- case MODALS.INSUFFICIENT_CREDITS:
- return ;
- case MODALS.WELCOME:
- return ;
- case MODALS.FIRST_REWARD:
- return ;
- case MODALS.AUTHENTICATION_FAILURE:
- return ;
- case MODALS.TRANSACTION_FAILED:
- return ;
- case MODALS.REWARD_APPROVAL_REQUIRED:
- return ;
- case MODALS.CONFIRM_FILE_REMOVE:
- return ;
- case MODALS.AFFIRM_PURCHASE:
- return ;
- case MODALS.CONFIRM_CLAIM_REVOKE:
- return ;
- case MODALS.PHONE_COLLECTION:
- return ;
- case MODALS.FIRST_SUBSCRIPTION:
- return ;
- case MODALS.SEND_TIP:
- return ;
- case MODALS.SOCIAL_SHARE:
- return ;
- case MODALS.PUBLISH:
- return ;
- case MODALS.CONFIRM_EXTERNAL_LINK:
- return ;
- case MODALS.CONFIRM_TRANSACTION:
- return ;
- case MODALS.CONFIRM_THUMBNAIL_UPLOAD:
- return ;
- case MODALS.WALLET_ENCRYPT:
- return ;
- case MODALS.WALLET_DECRYPT:
- return ;
- case MODALS.WALLET_UNLOCK:
- return ;
- case MODALS.REWARD_GENERATED_CODE:
- return ;
- default:
- return null;
- }
}
}
diff --git a/src/ui/page/file/index.js b/src/ui/page/file/index.js
index 921eba8b0..b543d4150 100644
--- a/src/ui/page/file/index.js
+++ b/src/ui/page/file/index.js
@@ -12,6 +12,7 @@ import {
makeSelectContentTypeForUri,
makeSelectMetadataForUri,
makeSelectChannelForClaimUri,
+ selectBalance,
} from 'lbry-redux';
import {
doFetchViewCount,
@@ -39,6 +40,7 @@ const select = (state, props) => ({
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
channelUri: makeSelectChannelForClaimUri(props.uri, true)(state),
viewCount: makeSelectViewCountForUri(props.uri)(state),
+ balance: selectBalance(state),
});
const perform = dispatch => ({
diff --git a/src/ui/page/file/view.jsx b/src/ui/page/file/view.jsx
index 7c9eae257..5124a2e02 100644
--- a/src/ui/page/file/view.jsx
+++ b/src/ui/page/file/view.jsx
@@ -42,6 +42,7 @@ type Props = {
openModal: (id: string, { uri: string }) => void,
markSubscriptionRead: (string, string) => void,
fetchViewCount: string => void,
+ balance: number,
};
class FilePage extends React.Component {
@@ -135,6 +136,7 @@ class FilePage extends React.Component {
fileInfo,
channelUri,
viewCount,
+ balance,
} = this.props;
// File info
@@ -147,6 +149,7 @@ class FilePage extends React.Component {
const mediaType = getMediaType(contentType, fileName);
const showFile =
PLAYABLE_MEDIA_TYPES.includes(mediaType) || PREVIEW_MEDIA_TYPES.includes(mediaType);
+
const speechShareable =
costInfo &&
costInfo.cost === 0 &&
@@ -168,11 +171,32 @@ class FilePage extends React.Component {
editUri = buildURI(uriObject);
}
+ const insufficientCredits = costInfo && costInfo.cost > balance;
+
return (
-
{uri}
- {showFile &&
}
+
+
+
+ {insufficientCredits && (
+
+ {__(
+ 'The publisher has chosen to charge LBC to view this content. Your balance is currently to low to view it.'
+ )}{' '}
+ {__('Checkout')}{' '}
+ {' '}
+ {__('or send more LBC to your wallet.')}
+
+ )}
+ {showFile && (
+
+ )}
{!showFile &&
(thumbnail ? (
diff --git a/src/ui/page/publish/index.js b/src/ui/page/publish/index.js
index 19ccb3c60..8389f1622 100644
--- a/src/ui/page/publish/index.js
+++ b/src/ui/page/publish/index.js
@@ -14,6 +14,7 @@ import {
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
+import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
const select = state => ({
@@ -27,6 +28,7 @@ const select = state => ({
isStillEditing: selectIsStillEditing(state),
balance: selectBalance(state),
isResolvingUri: selectIsResolvingPublishUris(state),
+ totalRewardValue: selectUnclaimedRewardValue(state),
});
const perform = dispatch => ({
diff --git a/src/ui/page/publish/view.jsx b/src/ui/page/publish/view.jsx
index 0745e9430..6903a79b4 100644
--- a/src/ui/page/publish/view.jsx
+++ b/src/ui/page/publish/view.jsx
@@ -1,19 +1,65 @@
-import React from 'react';
+import React, { Fragment } from 'react';
import PublishForm from 'component/publishForm';
import Page from 'component/page';
+import Yrbl from 'component/yrbl';
+import LbcSymbol from 'component/common/lbc-symbol';
+import CreditAmount from 'component/common/credit-amount';
+import Button from 'component/button';
class PublishPage extends React.PureComponent {
scrollToTop = () => {
- // #content wraps every
- const mainContent = document.getElementById('content');
+ const mainContent = document.querySelector('main');
if (mainContent) {
mainContent.scrollTop = 0; // It would be nice to animate this
}
};
render() {
+ const { balance, totalRewardValue } = this.props;
+ const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
+
return (
+ {balance === 0 && (
+
+
+
+ {__(
+ 'LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.'
+ )}
+
+
+ {__('Because of the blockchain, some actions require LBRY credits')} (
+
+ ).
+
+
+ {' '}
+ {__(
+ 'allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.'
+ )}
+
+
+ }
+ />
+
+
+ {__('LBRY Credits Required')}
+
+
+ {__(' There are a variety of ways to get credits, including more than')}{' '}
+ {' '}
+ {__('in free rewards for participating in the LBRY beta.')}
+
+
+
+
+
+
+ )}
);
diff --git a/src/ui/redux/actions/content.js b/src/ui/redux/actions/content.js
index dd8b8a05d..a2afb26b1 100644
--- a/src/ui/redux/actions/content.js
+++ b/src/ui/redux/actions/content.js
@@ -272,7 +272,6 @@ export function doPurchaseUri(
if (cost > balance) {
dispatch(doSetPlayingUri(null));
- dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS));
Promise.resolve();
return;
}
diff --git a/src/ui/scss/component/_card.scss b/src/ui/scss/component/_card.scss
index 8ea599ca6..164ad18c0 100644
--- a/src/ui/scss/component/_card.scss
+++ b/src/ui/scss/component/_card.scss
@@ -1,7 +1,7 @@
.card {
background-color: $lbry-white;
border: 1px solid $lbry-gray-1;
- margin-bottom: var(--spacing-vertical-large);
+ margin-bottom: var(--spacing-vertical-xlarge);
position: relative;
html[data-mode='dark'] & {
@@ -84,6 +84,11 @@
p:not(:last-child) {
margin-bottom: var(--spacing-vertical-medium);
}
+
+ .badge {
+ bottom: -0.15rem;
+ position: relative;
+ }
}
// C A R D
@@ -92,10 +97,6 @@
.card__header {
position: relative;
- + .card__content {
- margin-top: var(--spacing-vertical-medium);
- }
-
&:not(.card__header--flat) {
margin-bottom: var(--spacing-vertical-small);
}
@@ -195,6 +196,10 @@
.button {
font-size: 1.2rem;
}
+
+ + .card__content {
+ margin-top: var(--spacing-vertical-medium);
+ }
}
.card__title--flex {
diff --git a/src/ui/scss/component/_content.scss b/src/ui/scss/component/_content.scss
index a1c9a85a9..2fbc41b85 100644
--- a/src/ui/scss/component/_content.scss
+++ b/src/ui/scss/component/_content.scss
@@ -67,6 +67,11 @@
background-color: $lbry-grape-3;
}
+.card__media--disabled {
+ opacity: 0.5;
+ pointer-events: none;
+}
+
.content__loading {
width: 100%;
height: 100%;
diff --git a/src/ui/scss/component/_header.scss b/src/ui/scss/component/_header.scss
index 62f444b7a..12ad4be1f 100644
--- a/src/ui/scss/component/_header.scss
+++ b/src/ui/scss/component/_header.scss
@@ -81,6 +81,14 @@
}
}
+.header__navigation-item--active {
+ background-image: linear-gradient(
+ to bottom,
+ transparent 0%,
+ mix(transparent, $lbry-teal-3, 70%) 90%
+ );
+}
+
.header__navigation-item--back,
.header__navigation-item--forward,
.header__navigation-item--home,
diff --git a/src/ui/scss/component/_media.scss b/src/ui/scss/component/_media.scss
index 81624e156..5363166dc 100644
--- a/src/ui/scss/component/_media.scss
+++ b/src/ui/scss/component/_media.scss
@@ -155,6 +155,10 @@
opacity: 0.6;
}
+.media__insufficient-credits {
+ padding: 10px;
+}
+
// M E D I A
// A C T I O N S
diff --git a/src/ui/scss/component/_yrbl.scss b/src/ui/scss/component/_yrbl.scss
index 8d6f92a6d..6e9b1df4e 100644
--- a/src/ui/scss/component/_yrbl.scss
+++ b/src/ui/scss/component/_yrbl.scss
@@ -1,10 +1,10 @@
-.yrbl-wrap {
+.yrbl__wrap {
align-items: center;
display: flex;
justify-content: center;
vertical-align: middle;
text-align: left;
- margin-bottom: var(--spacing-vertical-large);
+ margin-bottom: var(--spacing-vertical-xlarge);
}
.yrbl {
@@ -12,6 +12,10 @@
margin-right: var(--spacing-vertical-large);
}
+.yrbl__content {
+ max-width: 500px;
+}
+
.yrbl--first-run {
align-self: center;
height: 250px;
diff --git a/src/ui/scss/init/_gui.scss b/src/ui/scss/init/_gui.scss
index c10d86524..6899fdd90 100644
--- a/src/ui/scss/init/_gui.scss
+++ b/src/ui/scss/init/_gui.scss
@@ -170,7 +170,7 @@ code {
}
html[data-mode='dark'] & {
- background-color: $lbry-yellow-4;
+ background-color: $lbry-yellow-3;
color: $lbry-black;
}
}
diff --git a/src/ui/scss/init/_vars.scss b/src/ui/scss/init/_vars.scss
index 90972d9e5..c583d702f 100644
--- a/src/ui/scss/init/_vars.scss
+++ b/src/ui/scss/init/_vars.scss
@@ -17,6 +17,7 @@ $large-breakpoint: 1921px;
--spacing-vertical-small: calc(2rem / 3);
--spacing-vertical-medium: calc(2rem / 2);
--spacing-vertical-large: 2rem;
+ --spacing-vertical-xlarge: 3rem;
--file-page-max-width: 1787px;
--file-max-height: 788px;