Merge pull request #2473 from lbryio/fixes

RC fixes
This commit is contained in:
Sean Yesmunt 2019-05-14 14:22:03 -04:00 committed by GitHub
commit c07ba58d42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 279 additions and 230 deletions

View file

@ -19,7 +19,8 @@
"__": true, "__": true,
"__n": true, "__n": true,
"app": true, "app": true,
"IS_WEB": true "IS_WEB": true,
"WEBPACK_PORT": true
}, },
"rules": { "rules": {
"comma-dangle": ["error", "always-multiline"], "comma-dangle": ["error", "always-multiline"],

View file

@ -4,7 +4,7 @@ declare type UpdatePublishFormData = {
filePath?: string, filePath?: string,
contentIsFree?: boolean, contentIsFree?: boolean,
fee?: { fee?: {
amount: number, amount: string,
currency: string, currency: string,
}, },
title?: string, title?: string,

View file

@ -1,6 +1,6 @@
{ {
"name": "LBRY", "name": "LBRY",
"version": "0.32.0-rc.1", "version": "0.32.0-rc.6",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [ "keywords": [
"lbry" "lbry"
@ -26,7 +26,7 @@
"dev": "yarn dev:electron", "dev": "yarn dev:electron",
"dev:electron": "cross-env NODE_ENV=development node ./src/platforms/electron/devServer.js", "dev:electron": "cross-env NODE_ENV=development node ./src/platforms/electron/devServer.js",
"dev:web": "cross-env NODE_ENV=development webpack-dev-server --open --hot --progress --config webpack.web.config.js", "dev:web": "cross-env NODE_ENV=development webpack-dev-server --open --hot --progress --config webpack.web.config.js",
"dev:internal-apis": "LBRY_API_URL='http://localhost:9090' yarn dev:electron", "dev:internal-apis": "LBRY_API_URL='http://localhost:8080' yarn dev:electron",
"run:web": "cross-env NODE_ENV=production yarn compile:web && node ./dist/web/server.js", "run:web": "cross-env NODE_ENV=production yarn compile:web && node ./dist/web/server.js",
"pack": "electron-builder --dir", "pack": "electron-builder --dir",
"dist": "electron-builder", "dist": "electron-builder",
@ -117,7 +117,7 @@
"jsmediatags": "^3.8.1", "jsmediatags": "^3.8.1",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#c8126ab21792d7a85e1123a2363af285a0263654", "lbry-redux": "lbryio/lbry-redux#02f6918238110726c0b3b4248c61a84ac0b969e3",
"lbryinc": "lbryio/lbryinc#43d382d9b74d396a581a74d87e4c53105e04f845", "lbryinc": "lbryio/lbryinc#43d382d9b74d396a581a74d87e4c53105e04f845",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",
@ -151,7 +151,6 @@
"react-router-dom": "^5.0.0", "react-router-dom": "^5.0.0",
"react-simplemde-editor": "^4.0.0", "react-simplemde-editor": "^4.0.0",
"react-toggle": "^4.0.2", "react-toggle": "^4.0.2",
"react-virtualized": "^9.21.0",
"redux": "^3.6.0", "redux": "^3.6.0",
"redux-persist": "^4.8.0", "redux-persist": "^4.8.0",
"redux-persist-transform-compress": "^4.2.0", "redux-persist-transform-compress": "^4.2.0",
@ -188,7 +187,7 @@
"yarn": "^1.3" "yarn": "^1.3"
}, },
"lbrySettings": { "lbrySettings": {
"lbrynetDaemonVersion": "0.37.0rc5", "lbrynetDaemonVersion": "0.37.0",
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
"lbrynetDaemonDir": "static/daemon", "lbrynetDaemonDir": "static/daemon",
"lbrynetDaemonFileName": "lbrynet" "lbrynetDaemonFileName": "lbrynet"

View file

@ -36,7 +36,7 @@ export default appState => {
}; };
const lbryProto = 'lbry://'; const lbryProto = 'lbry://';
const lbryProtoQ = 'lbry://?'; const lbryProtoQ = 'lbry://?';
const rendererURL = isDev ? `http://localhost:8080` : `file://${__dirname}/index.html`; const rendererURL = isDev ? `http://localhost:${WEBPACK_PORT}` : `file://${__dirname}/index.html`;
let window = new BrowserWindow(windowConfiguration); let window = new BrowserWindow(windowConfiguration);

View file

@ -1,5 +1,3 @@
const fs = require('fs');
const path = require('path');
const chalk = require('chalk'); const chalk = require('chalk');
const webpack = require('webpack'); const webpack = require('webpack');
const merge = require('webpack-merge'); const merge = require('webpack-merge');
@ -7,12 +5,9 @@ const middleware = require('webpack-dev-middleware');
const express = require('express'); const express = require('express');
const app = express(); const app = express();
// TODO: Spawn separate threads so realtime status logging can be used // Primary definition for this is in webpack.web.config.js
// without overwriting information/execptions logged by the compilers // We can't access it here because webpack isn't running on this file
const logRealtime = str => { const WEBPACK_PORT = 9090;
let lineCount = (str.match(/\n/) || []).length + 1;
console.log('\u001B[' + lineCount + 'F\u001B[G\u001B[2K' + str);
};
console.log( console.log(
chalk.magenta(`Compiling ${chalk.underline('main')} and ${chalk.underline('render')}, this will take a while.`) chalk.magenta(`Compiling ${chalk.underline('main')} and ${chalk.underline('render')}, this will take a while.`)
@ -46,8 +41,8 @@ app.use(require('webpack-hot-middleware')(renderCompiler));
app.use(renderInstance); app.use(renderInstance);
app.use(express.static('dist/electron/static')); app.use(express.static('dist/electron/static'));
app.listen(8080, () => { app.listen(WEBPACK_PORT, () => {
console.log(chalk.yellow.bold('Renderer listening on port 8080 (still compiling)')); console.log(chalk.yellow.bold(`Renderer listening on port ${WEBPACK_PORT} (still compiling)`));
}); });
mainInstance.waitUntilValid(() => console.log(chalk.green(`${chalk.underline('main')} compilation complete.`))); mainInstance.waitUntilValid(() => console.log(chalk.green(`${chalk.underline('main')} compilation complete.`)));

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,15 +1,30 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { parseURI } from 'lbry-redux';
import classnames from 'classnames';
import Gerbil from './gerbil.png';
type Props = { type Props = {
thumbnail: ?string, thumbnail: ?string,
uri: string,
}; };
function ChannelThumbnail(props: Props) { function ChannelThumbnail(props: Props) {
const { thumbnail } = props; const { thumbnail, uri } = props;
// Generate a random color class based on the first letter of the channel name
const { channelName } = parseURI(uri);
const initializer = channelName.charCodeAt(0) - 65; // will be between 0 and 57
const className = `channel-thumbnail__default--${initializer % 4}`;
return ( return (
<div className="channel__thumbnail"> <div
{thumbnail && <img className="channel__thumbnail--custom" src={thumbnail} />} className={classnames('channel-thumbnail', {
[className]: !thumbnail,
})}
>
{!thumbnail && <img className="channel-thumbnail__default" src={Gerbil} />}
{thumbnail && <img className="channel-thumbnail__custom" src={thumbnail} />}
</div> </div>
); );
} }

View file

@ -25,7 +25,7 @@ class IconComponent extends React.PureComponent<Props> {
switch (icon) { switch (icon) {
case ICONS.FEATURED: case ICONS.FEATURED:
return __('Featured content. Earn rewards for watching.'); return __('Featured content. Earn rewards for watching.');
case ICONS.LOCAL: case ICONS.DOWNLOAD:
return __('This file is downloaded.'); return __('This file is downloaded.');
default: default:
return null; return null;

View file

@ -16,7 +16,7 @@ type Props = {
}; };
function Paginate(props: Props) { function Paginate(props: Props) {
const { totalPages, loading, location, history, onPageChange } = props; const { totalPages = 1, loading, location, history, onPageChange } = props;
const { search } = location; const { search } = location;
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const currentPage = Number(urlParams.get(PAGINATE_PARAM)) || 1; const currentPage = Number(urlParams.get(PAGINATE_PARAM)) || 1;

View file

@ -3,19 +3,25 @@ import { Lbryio } from 'lbryinc';
import * as React from 'react'; import * as React from 'react';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import Button from 'component/button'; import Button from 'component/button';
import { withRouter } from 'react-router';
type Props = { type Props = {
children: React.Node, children: React.Node,
history: {
replace: string => void,
},
}; };
type State = { type State = {
hasError: boolean, hasError: boolean,
}; };
export default class ErrorBoundary extends React.Component<Props, State> { class ErrorBoundary extends React.Component<Props, State> {
constructor() { constructor() {
super(); super();
this.state = { hasError: false }; this.state = { hasError: false };
(this: any).refresh = this.refresh.bind(this);
} }
static getDerivedStateFromError() { static getDerivedStateFromError() {
@ -35,6 +41,13 @@ export default class ErrorBoundary extends React.Component<Props, State> {
} }
} }
refresh() {
const { history } = this.props;
// use history.replace instead of history.push so the user can't click back to the errored page
history.replace('');
this.setState({ hasError: false });
}
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
return ( return (
@ -50,7 +63,7 @@ export default class ErrorBoundary extends React.Component<Props, State> {
button="link" button="link"
className="load-screen__button" className="load-screen__button"
label={__('refreshing the app')} label={__('refreshing the app')}
onClick={() => (window.location.href = '/')} onClick={this.refresh}
/>{' '} />{' '}
{__('to fix it')}. {__('to fix it')}.
</p> </p>
@ -64,3 +77,5 @@ export default class ErrorBoundary extends React.Component<Props, State> {
return this.props.children; return this.props.children;
} }
} }
export default withRouter(ErrorBoundary);

View file

@ -12,7 +12,6 @@ import { openCopyLinkMenu } from 'util/context-menu';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
import get from 'lodash.get';
type Props = { type Props = {
uri: string, uri: string,
@ -65,7 +64,6 @@ class FileCard extends React.PureComponent<Props> {
const { const {
claim, claim,
fileInfo, fileInfo,
metadata,
rewardedContentClaimIds, rewardedContentClaimIds,
obscureNsfw, obscureNsfw,
claimIsMine, claimIsMine,
@ -106,7 +104,6 @@ class FileCard extends React.PureComponent<Props> {
const uri = !pending ? normalizeURI(this.props.uri) : this.props.uri; const uri = !pending ? normalizeURI(this.props.uri) : this.props.uri;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id); const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
const height = claim && claim.height;
const handleContextMenu = event => { const handleContextMenu = event => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -146,7 +143,7 @@ class FileCard extends React.PureComponent<Props> {
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />} {isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
{isSubscribed && <Icon icon={icons.SUBSCRIPTION} />} {isSubscribed && <Icon icon={icons.SUBSCRIPTION} />}
{claimIsMine && <Icon icon={icons.PUBLISHED} />} {claimIsMine && <Icon icon={icons.PUBLISHED} />}
{!claimIsMine && fileInfo && <Icon icon={icons.LOCAL} />} {!claimIsMine && fileInfo && <Icon icon={icons.DOWNLOAD} />}
{isNew && <span className="badge badge--alert">{__('NEW')}</span>} {isNew && <span className="badge badge--alert">{__('NEW')}</span>}
</div> </div>
</li> </li>

View file

@ -92,7 +92,6 @@ class FileDetails extends PureComponent<Props> {
{__('Downloaded to')} {__('Downloaded to')}
{': '} {': '}
<Button <Button
constrict
button="link" button="link"
onClick={() => { onClick={() => {
if (downloadPath) { if (downloadPath) {

View file

@ -47,8 +47,8 @@ class FileTile extends React.PureComponent<Props> {
if (!isResolvingUri && !claim && uri) resolveUri(uri); if (!isResolvingUri && !claim && uri) resolveUri(uri);
} }
componentWillReceiveProps(nextProps: Props) { componentDidUpdate() {
const { isResolvingUri, claim, uri, resolveUri } = nextProps; const { isResolvingUri, claim, uri, resolveUri } = this.props;
if (!isResolvingUri && claim === undefined && uri) resolveUri(uri); if (!isResolvingUri && claim === undefined && uri) resolveUri(uri);
} }
@ -68,7 +68,7 @@ class FileTile extends React.PureComponent<Props> {
{isNew && <span className="badge badge--alert icon">{__('NEW')}</span>} {isNew && <span className="badge badge--alert icon">{__('NEW')}</span>}
{isSubscribed && <Icon icon={ICONS.SUBSCRIPTION} />} {isSubscribed && <Icon icon={ICONS.SUBSCRIPTION} />}
{isRewardContent && <Icon iconColor="red" icon={ICONS.FEATURED} />} {isRewardContent && <Icon iconColor="red" icon={ICONS.FEATURED} />}
{!claimIsMine && isDownloaded && <Icon icon={ICONS.LOCAL} />} {!claimIsMine && isDownloaded && <Icon icon={ICONS.DOWNLOAD} />}
{claimIsMine && <Icon icon={ICONS.PUBLISHED} />} {claimIsMine && <Icon icon={ICONS.PUBLISHED} />}
</div> </div>
); );

View file

@ -78,7 +78,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
return historyItems.length ? ( return historyItems.length ? (
<React.Fragment> <React.Fragment>
<div className="card__actions card__actions--between"> <div className="card__header card__actions card__actions--between">
{Object.keys(itemsSelected).length ? ( {Object.keys(itemsSelected).length ? (
<Button button="link" label={__('Delete')} onClick={this.removeSelected} /> <Button button="link" label={__('Delete')} onClick={this.removeSelected} />
) : ( ) : (

View file

@ -29,7 +29,7 @@ type Props = {
nsfw: boolean, nsfw: boolean,
contentIsFree: boolean, contentIsFree: boolean,
fee: { fee: {
amount: number, amount: string,
currency: string, currency: string,
}, },
channel: string, channel: string,

View file

@ -14,7 +14,6 @@ import FileListPublished from 'page/fileListPublished';
import TransactionHistoryPage from 'page/transactionHistory'; import TransactionHistoryPage from 'page/transactionHistory';
import AuthPage from 'page/auth'; import AuthPage from 'page/auth';
import InvitePage from 'page/invite'; import InvitePage from 'page/invite';
import BackupPage from 'page/backup';
import SubscriptionsPage from 'page/subscriptions'; import SubscriptionsPage from 'page/subscriptions';
import SearchPage from 'page/search'; import SearchPage from 'page/search';
import UserHistoryPage from 'page/userHistory'; import UserHistoryPage from 'page/userHistory';
@ -39,7 +38,6 @@ export default function AppRouter() {
<Switch> <Switch>
<Route path="/" exact component={DiscoverPage} /> <Route path="/" exact component={DiscoverPage} />
<Route path={`/$/${PAGES.AUTH}`} exact component={AuthPage} /> <Route path={`/$/${PAGES.AUTH}`} exact component={AuthPage} />
<Route path={`/$/${PAGES.BACKUP}`} exact component={BackupPage} />
<Route path={`/$/${PAGES.INVITE}`} exact component={InvitePage} /> <Route path={`/$/${PAGES.INVITE}`} exact component={InvitePage} />
<Route path={`/$/${PAGES.DOWNLOADED}`} exact component={FileListDownloaded} /> <Route path={`/$/${PAGES.DOWNLOADED}`} exact component={FileListDownloaded} />
<Route path={`/$/${PAGES.PUBLISHED}`} exact component={FileListPublished} /> <Route path={`/$/${PAGES.PUBLISHED}`} exact component={FileListPublished} />

View file

@ -62,10 +62,10 @@ class SideBar extends React.PureComponent<Props> {
), ),
}, },
{ {
...buildLink(PAGES.PUBLISHED, 'Publishes', ICONS.PUBLISHED), ...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISHED),
}, },
{ {
...buildLink(PAGES.HISTORY, 'History', ICONS.HISTORY), ...buildLink(PAGES.HISTORY, __('Library'), ICONS.DOWNLOAD),
}, },
].map(renderLink)} ].map(renderLink)}
</ul> </ul>
@ -74,35 +74,30 @@ class SideBar extends React.PureComponent<Props> {
<ul className="navigation__links"> <ul className="navigation__links">
{[ {[
{ {
...buildLink(PAGES.ACCOUNT, 'Overview', ICONS.ACCOUNT), ...buildLink(PAGES.ACCOUNT, __('Overview'), ICONS.ACCOUNT),
}, },
{ {
...buildLink(PAGES.INVITE, 'Invite', ICONS.INVITE, shouldShowInviteGuide && __('Check this out!')), ...buildLink(PAGES.INVITE, __('Invite'), ICONS.INVITE, shouldShowInviteGuide && __('Check this out!')),
}, },
{ {
...buildLink(PAGES.REWARDS, 'Rewards', ICONS.FEATURED), ...buildLink(PAGES.REWARDS, __('Rewards'), ICONS.FEATURED),
}, },
{ {
...buildLink(PAGES.SEND, 'Send & Recieve', ICONS.SEND), ...buildLink(PAGES.SEND, __('Send & Recieve'), ICONS.SEND),
}, },
{ {
...buildLink(PAGES.TRANSACTIONS, 'Transactions', ICONS.TRANSACTIONS), ...buildLink(PAGES.TRANSACTIONS, __('Transactions'), ICONS.TRANSACTIONS),
}, },
{ {
...buildLink(PAGES.SETTINGS, 'Settings', ICONS.SETTINGS), ...buildLink(PAGES.SETTINGS, __('Settings'), ICONS.SETTINGS),
}, },
// @if TARGET='app'
{
...buildLink(PAGES.BACKUP, 'Backup', ICONS.BACKUP),
},
// @endif
].map(renderLink)} ].map(renderLink)}
</ul> </ul>
<ul className="navigation__links navigation__links--bottom"> <ul className="navigation__links navigation__links--bottom">
{[ {[
{ {
...buildLink(PAGES.HELP, 'Help', ICONS.HELP), ...buildLink(PAGES.HELP, __('Help'), ICONS.HELP),
}, },
].map(renderLink)} ].map(renderLink)}
</ul> </ul>

View file

@ -27,7 +27,7 @@ class SocialShare extends React.PureComponent<Props> {
render() { render() {
const { claim, isChannel } = this.props; const { claim, isChannel } = this.props;
const { claim_id: claimId, name: claimName, channel_name: channelName, value } = claim; const { claim_id: claimId, name: claimName, channel_name: channelName } = claim;
const { speechShareable, onDone } = this.props; const { speechShareable, onDone } = this.props;
const channelClaimId = claim.signing_channel && claim.signing_channel.claim_id; const channelClaimId = claim.signing_channel && claim.signing_channel.claim_id;
@ -70,7 +70,7 @@ class SocialShare extends React.PureComponent<Props> {
<React.Fragment> <React.Fragment>
{speechShareable && ( {speechShareable && (
<div className="card__content"> <div className="card__content">
<label className="card__subtitle">{__('Web link')}</label> <label className="help">{__('Web link')}</label>
<CopyableText copyable={speechURL} /> <CopyableText copyable={speechURL} />
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<ToolTip onComponent body={__('Facebook')}> <ToolTip onComponent body={__('Facebook')}>
@ -98,7 +98,7 @@ class SocialShare extends React.PureComponent<Props> {
</div> </div>
)} )}
<div className="card__content"> <div className="card__content">
<label className="card__subtitle">{__('LBRY App link')}</label> <label className="help">{__('LBRY App link')}</label>
<CopyableText copyable={lbryURL} noSnackbar /> <CopyableText copyable={lbryURL} noSnackbar />
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<ToolTip onComponent body={__('Facebook')}> <ToolTip onComponent body={__('Facebook')}>

View file

@ -1,11 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimedRewardsByTransactionId } from 'lbryinc'; import { selectClaimedRewardsByTransactionId } from 'lbryinc';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectAllMyClaimsByOutpoint, selectTransactionListFilter, doSetTransactionListFilter } from 'lbry-redux'; import {
selectAllMyClaimsByOutpoint,
selectSupportsByOutpoint,
selectTransactionListFilter,
doSetTransactionListFilter,
} from 'lbry-redux';
import TransactionList from './view'; import TransactionList from './view';
const select = state => ({ const select = state => ({
rewards: selectClaimedRewardsByTransactionId(state), rewards: selectClaimedRewardsByTransactionId(state),
mySupports: selectSupportsByOutpoint(state),
myClaims: selectAllMyClaimsByOutpoint(state), myClaims: selectAllMyClaimsByOutpoint(state),
filterSetting: selectTransactionListFilter(state), filterSetting: selectTransactionListFilter(state),
}); });

View file

@ -6,7 +6,7 @@ import ButtonTransaction from 'component/common/transaction-link';
import CreditAmount from 'component/common/credit-amount'; import CreditAmount from 'component/common/credit-amount';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Button from 'component/button'; import Button from 'component/button';
import { buildURI } from 'lbry-redux'; import { buildURI, parseURI } from 'lbry-redux';
type Props = { type Props = {
transaction: Transaction, transaction: Transaction,
@ -42,6 +42,9 @@ class TransactionListItem extends React.PureComponent<Props> {
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;
// Ensure the claim name is valid
const { claimName } = parseURI(name);
const dateFormat = { const dateFormat = {
month: 'short', month: 'short',
day: 'numeric', day: 'numeric',
@ -65,9 +68,9 @@ class TransactionListItem extends React.PureComponent<Props> {
</td> </td>
<td className="table__item--actionable"> <td className="table__item--actionable">
{reward && <span>{reward.reward_title}</span>} {reward && <span>{reward.reward_title}</span>}
{name && claimId && ( {claimName && claimId && (
<Button button="link" navigate={buildURI({ claimName: name, claimId })}> <Button button="link" navigate={buildURI({ claimName: claimName, claimId })}>
{name} {claimName}
</Button> </Button>
)} )}
</td> </td>

View file

@ -14,6 +14,7 @@ type Props = {
transactions: Array<Transaction>, transactions: Array<Transaction>,
rewards: {}, rewards: {},
openModal: (id: string, { nout: number, txid: string }) => void, openModal: (id: string, { nout: number, txid: string }) => void,
mySupports: {},
myClaims: any, myClaims: any,
filterSetting: string, filterSetting: string,
setTransactionFilter: string => void, setTransactionFilter: string => void,
@ -42,10 +43,9 @@ class TransactionList extends React.PureComponent<Props> {
} }
isRevokeable(txid: string, nout: number) { isRevokeable(txid: string, nout: number) {
const { myClaims } = this.props; const outpoint = `${txid}:${nout}`;
// a claim/support/update is revokable if it const { mySupports, myClaims } = this.props;
// is in my claim list(claim_list_mine) return !!mySupports[outpoint] || myClaims.has(outpoint);
return myClaims.has(`${txid}:${nout}`);
} }
revokeClaim(txid: string, nout: number) { revokeClaim(txid: string, nout: number) {

View file

@ -39,6 +39,12 @@ class TransactionListRecent extends React.PureComponent<Props> {
</div> </div>
)} )}
{!fetchingTransactions && !hasTransactions && (
<div className="card__content">
<p className="card__subtitle">{__('No transactions... yet.')}</p>
</div>
)}
{hasTransactions && ( {hasTransactions && (
<Fragment> <Fragment>
<div className="card__content"> <div className="card__content">

View file

@ -1,9 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings } from 'redux/selectors/settings';
import BackupPage from './view'; import WalletBackup from './view';
const select = state => ({ const select = state => ({
daemonSettings: selectDaemonSettings(state), daemonSettings: selectDaemonSettings(state),
}); });
export default connect(select)(BackupPage); export default connect(select)(WalletBackup);

View file

@ -0,0 +1,66 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
type Props = {
daemonSettings: {
wallet_dir: ?string,
},
};
class WalletBackup extends React.PureComponent<Props> {
render() {
const { daemonSettings } = this.props;
const { wallet_dir: lbryumWalletDir } = daemonSettings;
const noDaemonSettings = Object.keys(daemonSettings).length === 0;
return (
<section className="card card--section">
{noDaemonSettings ? (
<header className="card__header">
<h2 className="card__title">{__('Failed to load settings.')}</h2>
</header>
) : (
<React.Fragment>
<header className="card__header">
<h2 className="card__title">{__('Backup Your LBRY Credits')}</h2>
<p className="card__subtitle">
{__(
'Your LBRY credits are controllable by you and only you, via wallet file(s) stored locally on your computer.'
)}
</p>
</header>
<div className="card__content">
<p>
{__(
'Currently, there is no automatic wallet backup. If you lose access to these files, you will lose your credits permanently.'
)}
</p>
<p>
{__(
'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:'
)}
</p>
<p className="card__message">{lbryumWalletDir}</p>
<p>
{__(
'Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place.'
)}
</p>
<p>
For more details on backing up and best practices,{' '}
<Button button="link" href="https://lbry.com/faq/how-to-backup-wallet" label={__('see this article')} />
.
</p>
</div>
</React.Fragment>
)}
</section>
);
}
}
export default WalletBackup;

View file

@ -92,12 +92,12 @@ class WalletSend extends React.PureComponent<Props> {
parseFloat(values.amount) === balance parseFloat(values.amount) === balance
} }
/> />
{!!Object.keys(errors).length && ( {!!Object.keys(errors).length || (
<span className="error-text"> <span className="error-text">
{(!!values.address && touched.address && errors.address) || {(!!values.address && touched.address && errors.address) ||
(!!values.amount && touched.amount && errors.amount) || (!!values.amount && touched.amount && errors.amount) ||
(values.amount === balance && __('Decrease amount to account for transaction fee')) || (parseFloat(values.amount) === balance && __('Decrease amount to account for transaction fee')) ||
(values.amount > balance && __('Not enough credits'))} (parseFloat(values.amount) > balance && __('Not enough credits'))}
</span> </span>
)} )}
</div> </div>

View file

@ -3,7 +3,7 @@ import React, { Suspense } from 'react';
import { Modal } from 'modal/modal'; import { Modal } from 'modal/modal';
import Button from 'component/button'; import Button from 'component/button';
import UserPhoneVerify from 'component/userPhoneVerify'; import UserPhoneVerify from 'component/userPhoneVerify';
import { withRouter } from 'react-router-dom'; import { Redirect } from 'react-router';
const LazyUserPhoneNew = React.lazy(() => const LazyUserPhoneNew = React.lazy(() =>
import(/* webpackChunkName: "userPhoneNew" */ import(/* webpackChunkName: "userPhoneNew" */
@ -13,7 +13,7 @@ const LazyUserPhoneNew = React.lazy(() =>
type Props = { type Props = {
phone: ?number, phone: ?number,
user: { user: {
phone_number: ?number, is_identity_verified: boolean,
}, },
closeModal: () => void, closeModal: () => void,
history: { push: string => void }, history: { push: string => void },
@ -23,29 +23,30 @@ class ModalPhoneCollection extends React.PureComponent<Props> {
getTitle() { getTitle() {
const { user, phone } = this.props; const { user, phone } = this.props;
if (!user.phone_number && !phone) { if (!user.is_identity_verified && !phone) {
return __('Enter Your Phone Number'); return __('Enter Your Phone Number');
} }
return __('Enter The Verification Code'); return __('Enter The Verification Code');
} }
renderInner() { renderInner() {
const { closeModal, phone, user, history } = this.props; const { closeModal, phone, user } = this.props;
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />; const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
if (!user.phone_number && !phone) { if (!user.is_identity_verified && !phone) {
return ( return (
<Suspense fallback={<div />}> <Suspense fallback={<div />}>
<LazyUserPhoneNew cancelButton={cancelButton} /> <LazyUserPhoneNew cancelButton={cancelButton} />
</Suspense> </Suspense>
); );
} else if (!user.phone_number) { } else if (!user.is_identity_verified) {
return <UserPhoneVerify cancelButton={cancelButton} />; return <UserPhoneVerify cancelButton={cancelButton} />;
} }
history.push('/$/rewards'); closeModal();
return closeModal(); return <Redirect to="/$/rewards" />;
} }
render() { render() {
@ -64,4 +65,4 @@ class ModalPhoneCollection extends React.PureComponent<Props> {
} }
} }
export default withRouter(ModalPhoneCollection); export default ModalPhoneCollection;

View file

@ -1,73 +0,0 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import Page from 'component/page';
type Props = {
daemonSettings: {
wallet_dir: ?string,
},
};
class BackupPage extends React.PureComponent<Props> {
render() {
const { daemonSettings } = this.props;
const { wallet_dir: lbryumWalletDir } = daemonSettings;
const noDaemonSettings = Object.keys(daemonSettings).length === 0;
return (
<Page>
<section className="card card--section">
{noDaemonSettings ? (
<header className="card__header">
<h2 className="card__title">{__('Failed to load settings.')}</h2>
</header>
) : (
<React.Fragment>
<header className="card__header">
<h2 className="card__title">{__('Backup Your LBRY Credits')}</h2>
<p className="card__subtitle">
{__(
'Your LBRY credits are controllable by you and only you, via wallet file(s) stored locally on your computer.'
)}
</p>
</header>
<div className="card__content">
<p>
{__(
'Currently, there is no automatic wallet backup. If you lose access to these files, you will lose your credits permanently.'
)}
</p>
<p>
{__(
'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:'
)}
</p>
<p className="card__message">{lbryumWalletDir}</p>
<p>
{__(
'Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place.'
)}
</p>
<p>
For more details on backing up and best practices,{' '}
<Button
button="link"
href="https://lbry.com/faq/how-to-backup-wallet"
label={__('see this article')}
/>
.
</p>
</div>
</React.Fragment>
)}
</section>
</Page>
);
}
}
export default BackupPage;

View file

@ -4,6 +4,7 @@ import {
makeSelectTitleForUri, makeSelectTitleForUri,
makeSelectThumbnailForUri, makeSelectThumbnailForUri,
makeSelectCoverForUri, makeSelectCoverForUri,
selectCurrentChannelPage,
} from 'lbry-redux'; } from 'lbry-redux';
import ChannelPage from './view'; import ChannelPage from './view';
@ -12,6 +13,7 @@ const select = (state, props) => ({
thumbnail: makeSelectThumbnailForUri(props.uri)(state), thumbnail: makeSelectThumbnailForUri(props.uri)(state),
cover: makeSelectCoverForUri(props.uri)(state), cover: makeSelectCoverForUri(props.uri)(state),
channelIsMine: makeSelectClaimIsMine(props.uri)(state), channelIsMine: makeSelectClaimIsMine(props.uri)(state),
page: selectCurrentChannelPage(state),
}); });
export default connect( export default connect(

View file

@ -19,13 +19,14 @@ type Props = {
title: ?string, title: ?string,
cover: ?string, cover: ?string,
thumbnail: ?string, thumbnail: ?string,
page: number,
location: { search: string }, location: { search: string },
history: { push: string => void }, history: { push: string => void },
match: { params: { attribute: ?string } }, match: { params: { attribute: ?string } },
}; };
function ChannelPage(props: Props) { function ChannelPage(props: Props) {
const { uri, title, cover, history, location } = props; const { uri, title, cover, history, location, page } = props;
const { channelName, claimName, claimId } = parseURI(uri); const { channelName, claimName, claimId } = parseURI(uri);
const { search } = location; const { search } = location;
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
@ -37,17 +38,20 @@ function ChannelPage(props: Props) {
const tabIndex = currentView === ABOUT_PAGE ? 1 : 0; const tabIndex = currentView === ABOUT_PAGE ? 1 : 0;
const onTabChange = newTabIndex => { const onTabChange = newTabIndex => {
let url = formatLbryUriForWeb(uri); let url = formatLbryUriForWeb(uri);
let search = '?';
if (newTabIndex !== 0) { if (newTabIndex !== 0) {
url += `?${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`; search += `${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`;
} else {
search += `page=${page}`;
} }
history.push(url); history.push(`${url}${search}`);
}; };
return ( return (
<Page notContained className="main--no-padding-top"> <Page notContained className="main--no-padding-top">
<header className="channel__cover main__item--extend-outside"> <header className="channel-cover main__item--extend-outside">
{cover && <img className="channel__cover--custom" src={cover} />} {cover && <img className="channel-cover__custom" src={cover} />}
<div className="channel__primary-info"> <div className="channel__primary-info">
<ChannelThumbnail uri={uri} /> <ChannelThumbnail uri={uri} />

View file

@ -16,6 +16,7 @@ import {
makeSelectTitleForUri, makeSelectTitleForUri,
makeSelectThumbnailForUri, makeSelectThumbnailForUri,
makeSelectClaimIsNsfw, makeSelectClaimIsNsfw,
doToast,
} from 'lbry-redux'; } from 'lbry-redux';
import { doFetchViewCount, makeSelectViewCountForUri, makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc'; import { doFetchViewCount, makeSelectViewCountForUri, makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings'; import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
@ -53,6 +54,7 @@ const perform = dispatch => ({
setViewed: uri => dispatch(doSetContentHistoryItem(uri)), setViewed: uri => dispatch(doSetContentHistoryItem(uri)),
markSubscriptionRead: (channel, uri) => dispatch(doRemoveUnreadSubscription(channel, uri)), markSubscriptionRead: (channel, uri) => dispatch(doRemoveUnreadSubscription(channel, uri)),
fetchViewCount: claimId => dispatch(doFetchViewCount(claimId)), fetchViewCount: claimId => dispatch(doFetchViewCount(claimId)),
showToast: options => dispatch(doToast(options)),
}); });
export default connect( export default connect(

View file

@ -2,6 +2,7 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import { clipboard } from 'electron';
import { buildURI, normalizeURI } from 'lbry-redux'; import { buildURI, normalizeURI } from 'lbry-redux';
import FileViewer from 'component/fileViewer'; import FileViewer from 'component/fileViewer';
import Thumbnail from 'component/common/thumbnail'; import Thumbnail from 'component/common/thumbnail';
@ -22,7 +23,6 @@ import RecommendedContent from 'component/recommendedContent';
type Props = { type Props = {
claim: StreamClaim, claim: StreamClaim,
fileInfo: FileListItem, fileInfo: FileListItem,
metadata: StreamMetadata,
contentType: string, contentType: string,
uri: string, uri: string,
rewardedContentClaimIds: Array<string>, rewardedContentClaimIds: Array<string>,
@ -44,6 +44,7 @@ type Props = {
title: string, title: string,
thumbnail: ?string, thumbnail: ?string,
nsfw: boolean, nsfw: boolean,
showToast: ({}) => void,
}; };
class FilePage extends React.Component<Props> { class FilePage extends React.Component<Props> {
@ -125,7 +126,6 @@ class FilePage extends React.Component<Props> {
render() { render() {
const { const {
claim, claim,
metadata,
contentType, contentType,
uri, uri,
rewardedContentClaimIds, rewardedContentClaimIds,
@ -141,10 +141,11 @@ class FilePage extends React.Component<Props> {
title, title,
thumbnail, thumbnail,
nsfw, nsfw,
showToast,
} = this.props; } = this.props;
// File info // File info
const { height, channel_name: channelName } = claim; const { channel_name: channelName } = claim;
const { PLAYABLE_MEDIA_TYPES, PREVIEW_MEDIA_TYPES } = FilePage; const { PLAYABLE_MEDIA_TYPES, PREVIEW_MEDIA_TYPES } = FilePage;
const isRewardContent = (rewardedContentClaimIds || []).includes(claim.claim_id); const isRewardContent = (rewardedContentClaimIds || []).includes(claim.claim_id);
const shouldObscureThumbnail = obscureNsfw && nsfw; const shouldObscureThumbnail = obscureNsfw && nsfw;
@ -175,7 +176,17 @@ class FilePage extends React.Component<Props> {
return ( return (
<Page notContained className="main--file-page"> <Page notContained className="main--file-page">
<div className="grid-area--content"> <div className="grid-area--content">
<h1 className="media__uri">{uri}</h1> <Button
className="media__uri"
button="alt"
label={uri}
onClick={() => {
clipboard.writeText(uri);
showToast({
message: __('Text copied'),
});
}}
/>
{!fileInfo && insufficientCredits && ( {!fileInfo && insufficientCredits && (
<div className="media__insufficient-credits help--warning"> <div className="media__insufficient-credits help--warning">
{__( {__(

View file

@ -2,7 +2,6 @@
// @flow // @flow
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import classnames from 'classnames';
// @if TARGET='app' // @if TARGET='app'
import { shell } from 'electron'; import { shell } from 'electron';
// @endif // @endif
@ -10,6 +9,7 @@ import { Lbry } from 'lbry-redux';
import Native from 'native'; import Native from 'native';
import Button from 'component/button'; import Button from 'component/button';
import Page from 'component/page'; import Page from 'component/page';
import BackupSection from 'component/walletBackup';
type DeamonSettings = { type DeamonSettings = {
data_dir: string | any, data_dir: string | any,
@ -194,6 +194,10 @@ class HelpPage extends React.PureComponent<Props, State> {
</div> </div>
</section> </section>
{/* @if TARGET='app' */}
<BackupSection />
{/* @endif */}
<section className="card card--section"> <section className="card card--section">
<header className="card__header"> <header className="card__header">
<h2 className="card__title">{__('About')}</h2> <h2 className="card__title">{__('About')}</h2>

View file

@ -39,7 +39,7 @@ export default function SearchPage(props: Props) {
<Fragment> <Fragment>
{isValid && ( {isValid && (
<header className="search__header"> <header className="search__header">
<Button navigate={uri} className="media__uri"> <Button button="alt" navigate={uri} className="media__uri">
{uri} {uri}
</Button> </Button>
{isChannel ? ( {isChannel ? (
@ -52,7 +52,6 @@ export default function SearchPage(props: Props) {
<div className="search__results-wrapper"> <div className="search__results-wrapper">
<SearchOptions /> <SearchOptions />
<FileListSearch query={urlQuery} /> <FileListSearch query={urlQuery} />
<div className="card__content help">{__('These search results are provided by LBRY, Inc.')}</div> <div className="card__content help">{__('These search results are provided by LBRY, Inc.')}</div>
</div> </div>

View file

@ -35,7 +35,7 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) { if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) {
const [txid, nout] = outpoint.split(':'); const [txid, nout] = outpoint.split(':');
dispatch(doAbandonClaim(txid, nout)); dispatch(doAbandonClaim(txid, Number(nout)));
} }
dispatch({ dispatch({

View file

@ -43,7 +43,6 @@ export const doResetThumbnailStatus = () => (dispatch: Dispatch) => {
data: { data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.READY, uploadThumbnailStatus: THUMBNAIL_STATUSES.READY,
thumbnail: '', thumbnail: '',
nsfw: false,
}, },
}); });
}) })
@ -53,7 +52,6 @@ export const doResetThumbnailStatus = () => (dispatch: Dispatch) => {
data: { data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN, uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN,
thumbnail: '', thumbnail: '',
nsfw: false,
}, },
}) })
); );

View file

@ -1,6 +1,5 @@
.card { .card {
background-color: $lbry-white; background-color: $lbry-white;
border: 1px solid $lbry-gray-1;
margin-bottom: var(--spacing-vertical-xlarge); margin-bottom: var(--spacing-vertical-xlarge);
position: relative; position: relative;
border-radius: var(--card-radius); border-radius: var(--card-radius);
@ -8,7 +7,6 @@
html[data-mode='dark'] & { html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1); background-color: rgba($lbry-white, 0.1);
border-color: rgba($lbry-white, 0.1);
box-shadow: var(--card-box-shadow) darken($lbry-gray-1, 80%); box-shadow: var(--card-box-shadow) darken($lbry-gray-1, 80%);
} }
} }
@ -125,15 +123,15 @@
// Depending on screen width, the amount of items in // Depending on screen width, the amount of items in
// each row change and are auto-sized // each row change and are auto-sized
@media (min-width: 2001px) { // @media (min-width: 2001px) {
grid-template-columns: repeat(auto-fill, minmax(calc(100% / 10), 1fr)); // grid-template-columns: repeat(auto-fill, minmax(calc(100% / 10), 1fr));
} // }
@media (min-width: 1801px) and (max-width: 2000px) { // @media (min-width: 1801px) and (max-width: 2000px) {
grid-template-columns: repeat(auto-fill, minmax(calc(100% / 8), 1fr)); // grid-template-columns: repeat(auto-fill, minmax(calc(100% / 8), 1fr));
} // }
@media (min-width: 1551px) and (max-width: 1800px) { @media (min-width: 1551px) {
grid-template-columns: repeat(auto-fill, minmax(calc(100% / 7), 1fr)); grid-template-columns: repeat(auto-fill, minmax(calc(100% / 7), 1fr));
} }

View file

@ -1,7 +1,7 @@
$cover-z-index: 0; $cover-z-index: 0;
$metadata-z-index: 1; $metadata-z-index: 1;
.channel__cover { .channel-cover {
background-image: linear-gradient(to right, $lbry-indigo-4, $lbry-cyan-5 80%); background-image: linear-gradient(to right, $lbry-indigo-4, $lbry-cyan-5 80%);
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
@ -9,41 +9,62 @@ $metadata-z-index: 1;
color: $lbry-white; color: $lbry-white;
} }
.channel__cover--custom { .channel-cover__custom {
z-index: $cover-z-index; z-index: $cover-z-index;
align-self: flex-start; align-self: flex-start;
position: absolute; position: absolute;
object-fit: cover; object-fit: cover;
filter: brightness(40%); filter: brightness(60%);
} }
.channel__cover, .channel-cover,
.channel__cover--custom { .channel-cover__custom {
height: var(--cover-photo-height); height: var(--cover-photo-height);
width: 100%; width: 100%;
} }
.channel__thumbnail { .channel-thumbnail {
position: absolute; position: absolute;
display: flex;
left: var(--spacing-main-padding); left: var(--spacing-main-padding);
height: var(--channel-thumbnail-size); height: var(--channel-thumbnail-size);
width: var(--channel-thumbnail-size); width: var(--channel-thumbnail-size);
background-color: $lbry-gray-3;
background-image: linear-gradient(to right, $lbry-white, $lbry-gray-3 80%);
background-size: cover; background-size: cover;
box-shadow: 0px 8px 40px -3px $lbry-black; box-shadow: 0px 8px 40px -3px $lbry-black;
} }
.channel__thumbnail--custom { .channel-thumbnail__custom {
width: 100%; width: 100%;
object-fit: cover; object-fit: cover;
} }
.channel__thumbnail, .channel-thumbnail__default {
.channel__thumbnail--custom { width: 80%;
height: 80%;
margin-left: auto;
margin-right: auto;
align-self: flex-end;
margin-bottom: -1px;
}
.channel-thumbnail,
.channel-thumbnail__custom {
border-radius: var(--card-radius); border-radius: var(--card-radius);
} }
.channel-thumbnail__default--0 {
background-color: $lbry-indigo-3;
}
.channel-thumbnail__default--1 {
background-color: $lbry-orange-2;
}
.channel-thumbnail__default--2 {
background-color: $lbry-blue-3;
}
.channel-thumbnail__default--3 {
background-color: $lbry-red-1;
}
.channel__primary-info { .channel__primary-info {
// Ensure the profile pic/title sit ontop of the default cover background // Ensure the profile pic/title sit ontop of the default cover background
z-index: $metadata-z-index; z-index: $metadata-z-index;
@ -61,11 +82,6 @@ $metadata-z-index: 1;
.channel__url { .channel__url {
font-size: 1.2rem; font-size: 1.2rem;
user-select: all;
margin-top: -0.25rem; margin-top: -0.25rem;
color: rgba($lbry-white, 0.75);
} }
// .channel__description {
// font-size: 1.3rem;
// margin: var(--spacing-vertical-large) 0;
// }

View file

@ -1,6 +1,5 @@
.item-list { .item-list {
background-color: $lbry-white; background-color: $lbry-white;
margin-top: var(--spacing-vertical-large);
margin-bottom: var(--spacing-vertical-large); margin-bottom: var(--spacing-vertical-large);
padding: var(--spacing-vertical-large); padding: var(--spacing-vertical-large);

View file

@ -30,14 +30,9 @@
position: relative; position: relative;
} }
.search__results-title {
@extend .media-group__header-title;
margin-bottom: var(--spacing-vertical-large);
}
.search__options-wrapper { .search__options-wrapper {
font-size: 1.25em; font-size: 1.25em;
margin-bottom: var(--spacing-vertical-large); margin: var(--spacing-vertical-xlarge) 0;
} }
.search__options { .search__options {

View file

@ -29,6 +29,8 @@ table,
} }
.table--transactions { .table--transactions {
table-layout: fixed;
td:nth-of-type(1) { td:nth-of-type(1) {
// TX amounts // TX amounts
font-size: 0.9em; font-size: 0.9em;
@ -36,10 +38,13 @@ table,
} }
td:nth-of-type(3) { td:nth-of-type(3) {
max-width: 150px; // Only add ellipsis to the links in the table
overflow: hidden; // We still want to show the entire message if a TX includes one
white-space: nowrap; .button__content {
text-overflow: ellipsis; @include constrict(10rem);
vertical-align: bottom;
display: inline-block;
}
} }
} }

View file

@ -77,5 +77,5 @@ $large-breakpoint: 1921px;
// Image // Image
--thumbnail-preview-height: 100px; --thumbnail-preview-height: 100px;
--thumbnail-preview-width: 177px; --thumbnail-preview-width: 177px;
--cover-photo-height: 250px; --cover-photo-height: 300px;
} }

View file

@ -7,6 +7,10 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="text/javascript" src="http://localhost:8080/ui.js"></script> <!--
Primary definition for this is in webpack.web.config.js
We can't access it here because webpack isn't running on this file
-->
<script type="text/javascript" src="http://localhost:9090/ui.js"></script>
</body> </body>
</html> </html>

View file

@ -13,6 +13,12 @@ const UI_ROOT = path.resolve(__dirname, 'src/ui/');
const STATIC_ROOT = path.resolve(__dirname, 'static/'); const STATIC_ROOT = path.resolve(__dirname, 'static/');
const DIST_ROOT = path.resolve(__dirname, 'dist/'); const DIST_ROOT = path.resolve(__dirname, 'dist/');
// There are a two other uses of this value that can't access it from webpack
// They exist in
// src/platforms/electron/devServer.js
// static/index.dev.html
const WEBPACK_PORT = 9090;
console.log(ifProduction('production', 'development')); console.log(ifProduction('production', 'development'));
let baseConfig = { let baseConfig = {
@ -32,6 +38,10 @@ let baseConfig = {
node: { node: {
__dirname: false, __dirname: false,
}, },
devServer: {
historyApiFallback: true,
port: WEBPACK_PORT,
},
module: { module: {
rules: [ rules: [
{ {
@ -117,6 +127,7 @@ let baseConfig = {
'process.env.NODE_ENV': JSON.stringify(NODE_ENV), 'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
'process.env.SDK_API_URL': JSON.stringify(process.env.SDK_API_URL), 'process.env.SDK_API_URL': JSON.stringify(process.env.SDK_API_URL),
'process.env.LBRY_API_URL': JSON.stringify(process.env.LBRY_API_URL), 'process.env.LBRY_API_URL': JSON.stringify(process.env.LBRY_API_URL),
WEBPACK_PORT,
}), }),
], ],
}; };

View file

@ -18,9 +18,6 @@ const webConfig = {
path: __dirname + '/dist/web', path: __dirname + '/dist/web',
publicPath: '/', publicPath: '/',
}, },
devServer: {
historyApiFallback: true,
},
module: { module: {
rules: [ rules: [
{ {

View file

@ -2389,7 +2389,7 @@ class-utils@^0.3.5:
isobject "^3.0.0" isobject "^3.0.0"
static-extend "^0.1.1" static-extend "^0.1.1"
classnames@^2.2.3, classnames@^2.2.5: classnames@^2.2.5:
version "2.2.6" version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@ -3540,13 +3540,6 @@ dom-converter@^0.2:
dependencies: dependencies:
utila "~0.4" utila "~0.4"
"dom-helpers@^2.4.0 || ^3.0.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
dependencies:
"@babel/runtime" "^7.1.2"
dom-scroll-into-view@^1.2.1: dom-scroll-into-view@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e" resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e"
@ -6498,9 +6491,9 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2" yargs "^13.2.2"
zstd-codec "^0.1.1" zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#423123f1c19e61cead67c745d0892a2e4481cb6a: lbry-redux@lbryio/lbry-redux#02f6918238110726c0b3b4248c61a84ac0b969e3:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/423123f1c19e61cead67c745d0892a2e4481cb6a" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/02f6918238110726c0b3b4248c61a84ac0b969e3"
dependencies: dependencies:
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"
reselect "^3.0.0" reselect "^3.0.0"
@ -6814,7 +6807,7 @@ longest-streak@^2.0.1:
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e"
integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA== integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -9381,18 +9374,6 @@ react-toggle@^4.0.2:
dependencies: dependencies:
classnames "^2.2.5" classnames "^2.2.5"
react-virtualized@^9.21.0:
version "9.21.0"
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.21.0.tgz#8267c40ffb48db35b242a36dea85edcf280a6506"
integrity sha512-duKD2HvO33mqld4EtQKm9H9H0p+xce1c++2D5xn59Ma7P8VT7CprfAe5hwjd1OGkyhqzOZiTMlTal7LxjH5yBQ==
dependencies:
babel-runtime "^6.26.0"
classnames "^2.2.3"
dom-helpers "^2.4.0 || ^3.0.0"
loose-envify "^1.3.0"
prop-types "^15.6.0"
react-lifecycles-compat "^3.0.4"
react@^16.8.2: react@^16.8.2:
version "16.8.6" version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"