[redesign] downloaded/published/transactions page #1017

Merged
neb-b merged 2 commits from redesign-wip into redesign 2018-02-16 10:53:46 +01:00
32 changed files with 497 additions and 469 deletions

View file

@ -5,7 +5,7 @@ import setupContextMenu from './menu/setupContextMenu';
export default deepLinkingURIArg => {
let windowConfiguration = {
backgroundColor: '#44b098',
minWidth: 800,
minWidth: 950,
minHeight: 600,
neb-b commented 2018-02-15 23:40:54 +01:00 (Migrated from github.com)
Review

Upped this to give us some more space. This is similar to Discords min width

Upped this to give us some more space. This is similar to Discords min width
autoHideMenuBar: true,
show: false,

View file

@ -11,6 +11,8 @@ type Props = {
showPlus: boolean,
isEstimate?: boolean,
large?: boolean,
plain?: boolean,
fee?: boolean
};
class CreditAmount extends React.PureComponent<Props> {
@ -18,11 +20,11 @@ class CreditAmount extends React.PureComponent<Props> {
precision: 2,
showFree: false,
showFullPrice: false,
showPlus: false,
showPlus: false
};
render() {
const { amount, precision, showFullPrice, showFree, showPlus, large, isEstimate } = this.props;
const { amount, precision, showFullPrice, showFree, showPlus, large, isEstimate, plain, fee } = this.props;
const minimumRenderableAmount = 10 ** (-1 * precision);
const fullPrice = formatFullPrice(amount, 2);
@ -42,11 +44,19 @@ class CreditAmount extends React.PureComponent<Props> {
if (showFree && isFree) {
amountText = __('FREE');
} else {
amountText = `${formattedAmount} ${__('LBC')}`;
amountText = formattedAmount;
if (showPlus && amount > 0) {
amountText = `+${amountText}`;
}
if (!plain) {
amountText = `${amountText} ${__('LBC')}`
}
if (fee) {
amountText = `${amountText} ${__('fee')}`
}
}
return (
@ -56,6 +66,7 @@ class CreditAmount extends React.PureComponent<Props> {
'credit-amount--free': !large && isFree,
'credit-amount--cost': !large && !isFree,
'credit-amount--large': large,
'credit-amount--plain': plain,
})}
>
{amountText}

View file

@ -1,14 +1,22 @@
// @flow
import React from 'react';
import * as React from 'react';
import classnames from 'classnames';
const Spinner = () => (
<div className="spinner">
<div className="rect1" />
<div className="rect2" />
<div className="rect3" />
<div className="rect4" />
<div className="rect5" />
</div>
);
type Props = {
dark?: boolean,
}
const Spinner = (props: Props) => {
const { dark } = props;
return (
<div className={classnames("spinner", { "spinner--dark": dark })}>
<div className="rect rect1" />
<div className="rect rect2" />
<div className="rect rect3" />
<div className="rect rect4" />
<div className="rect rect5" />
</div>
);
}
export default Spinner;

View file

@ -0,0 +1,18 @@
// @flow
import React from 'react';
import Link from 'component/link';
type Props = {
id: string,
}
const TransactionLink = (props: Props) => {
const { id } = props;
const href = `https://explorer.lbry.io/#!/transaction/${id}`;
const label = id.substr(0, 7);
return <Link fakeLink href={href} label={label} />;
};
export default TransactionLink;

View file

@ -21,9 +21,14 @@ type Props = {
navigate: (string, ?{}) => void,
rewardedContentClaimIds: Array<string>,
obscureNsfw: boolean,
showPrice: boolean
};
class FileCard extends React.PureComponent<Props> {
static defaultProps = {
showPrice: true
}
componentWillMount() {
this.resolve(this.props);
}
@ -48,6 +53,7 @@ class FileCard extends React.PureComponent<Props> {
navigate,
rewardedContentClaimIds,
obscureNsfw,
showPrice
} = this.props;
const uri = normalizeURI(this.props.uri);
const title = metadata && metadata.title ? metadata.title : uri;
@ -79,7 +85,7 @@ class FileCard extends React.PureComponent<Props> {
>
<CardMedia thumbnail={thumbnail} />
<div className="card-media__internal-links">
<FilePrice uri={uri} />
{showPrice && <FilePrice uri={uri} />}
</div>
<div className="card__title-identity">

View file

@ -1,71 +1,85 @@
import React from 'react';
// @flow
import * as React from 'react';
import { buildURI } from 'lbryURI';
import { FormField } from 'component/common/form';
import FileTile from 'component/fileTile';
import FileCard from 'component/fileCard';
import { BusyMessage } from 'component/common.js';
class FileList extends React.PureComponent {
constructor(props) {
const sortFunctions = {
date: (fileInfos: Array<FileInfo>) => {
return fileInfos.slice().reverse();
},
title: (fileInfos) => {
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const title1 = fileInfo1.value
? fileInfo1.value.stream.metadata.title.toLowerCase()
: fileInfo1.name;
const title2 = fileInfo2.value
? fileInfo2.value.stream.metadata.title.toLowerCase()
: fileInfo2.name;
if (title1 < title2) {
return -1;
} else if (title1 > title2) {
return 1;
}
return 0;
});
},
};
type FileInfo = {
name: string,
channelName: ?string,
value?: {
publisherSignature: {
certificateId: string,
}
},
metadata: {
publisherSignature: {
certificateId: string
}
}
}
type Props = {
fileInfos: Array<FileInfo>
}
type State = {
sortBy: string
}
class FileList extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
sortBy: 'date',
};
this._sortFunctions = {
date(fileInfos) {
return fileInfos.slice().reverse();
},
title(fileInfos) {
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const title1 = fileInfo1.value
? fileInfo1.value.stream.metadata.title.toLowerCase()
: fileInfo1.name;
const title2 = fileInfo2.value
? fileInfo2.value.stream.metadata.title.toLowerCase()
: fileInfo2.name;
if (title1 < title2) {
return -1;
} else if (title1 > title2) {
return 1;
}
return 0;
});
},
filename(fileInfos) {
return fileInfos.slice().sort(({ file_name: fileName1 }, { file_name: fileName2 }) => {
const fileName1Lower = fileName1.toLowerCase();
const fileName2Lower = fileName2.toLowerCase();
if (fileName1Lower < fileName2Lower) {
return -1;
} else if (fileName2Lower > fileName1Lower) {
return 1;
}
return 0;
});
},
};
(this: any).handleSortChanged = this.handleSortChanged.bind(this);
}
getChannelSignature(fileInfo) {
handleSortChanged(event: SyntheticInputEvent<*>) {
this.setState({
sortBy: event.target.value,
});
}
getChannelSignature = (fileInfo: FileInfo) => {
if (fileInfo.value) {
return fileInfo.value.publisherSignature.certificateId;
}
return fileInfo.metadata.publisherSignature.certificateId;
}
handleSortChanged(event) {
this.setState({
sortBy: event.target.value,
});
}
render() {
const { handleSortChanged, fetching, fileInfos } = this.props;
const { fileInfos } = this.props;
const { sortBy } = this.state;
const content = [];
this._sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
const uriParams = {};
if (fileInfo.channel_name) {
@ -79,27 +93,25 @@ class FileList extends React.PureComponent {
const uri = buildURI(uriParams);
content.push(
<FileTile
<FileCard
key={fileInfo.outpoint || fileInfo.claim_id}
uri={uri}
showPrice={false}
showLocal={false}
showActions
showEmpty={this.props.fileTileShowEmpty}
/>
);
});
return (
<section className="file-list__header">
{fetching && <BusyMessage />}
<span className="sort-section">
{__('Sort by')}{' '}
<FormField type="select" onChange={this.handleSortChanged.bind(this)}>
<section>
<div className="file-list__sort">
<FormField prefix={__('Sort by')} type="select" value={sortBy} onChange={this.handleSortChanged}>
<option value="date">{__('Date')}</option>
<option value="title">{__('Title')}</option>
</FormField>
</span>
{content}
</div>
<div className="file-list">
{content}
</div>
</section>
);
}

View file

@ -68,6 +68,7 @@ const Button = (props: Props) => {
'btn--circle': circle,
'btn--flat': flat,
'btn--no-underline': fakeLink && noUnderline,
'btn--external-link': href
},
className
);

View file

@ -1,5 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import LinkTransaction from './view';
export default connect(null, null)(LinkTransaction);

View file

@ -1,14 +0,0 @@
import React from 'react';
import Link from 'component/link';
const LinkTransaction = props => {
const { id } = props;
const linkProps = Object.assign({}, props);
linkProps.href = `https://explorer.lbry.io/#!/transaction/${id}`;
linkProps.label = id.substr(0, 7);
return <Link {...linkProps} />;
};
export default LinkTransaction;

View file

@ -1,6 +1,6 @@
// @flow
import React from 'react';
import LinkTransaction from 'component/linkTransaction';
import LinkTransaction from 'component/common/transaction-link';
type Reward = {
id: string,

View file

@ -1,30 +1,45 @@
// I'll come back to this
/* eslint-disable */
// @flow
import React from 'react';
import LinkTransaction from 'component/linkTransaction';
import LinkTransaction from 'component/common/transaction-link';
import CreditAmount from 'component/common/credit-amount';
import DateTime from 'component/dateTime';
import Link from 'component/link';
import { buildURI } from 'lbryURI';
import * as txnTypes from 'constants/transaction_types';
import type { Transaction } from '../view';
type Props = {
transaction: Transaction,
revokeClaim: (string, number) => void,
isRevokeable: boolean,
reward: ?{
reward_title: string
}
}
class TransactionListItem extends React.PureComponent<Props> {
constructor() {
super();
(this: any).abandonClaim = this.abandonClaim.bind(this);
}
class TransactionListItem extends React.PureComponent {
abandonClaim() {
const { txid, nout } = this.props.transaction;
this.props.revokeClaim(txid, nout);
}
getLink(type) {
if (type == txnTypes.TIP) {
getLink(type: string) {
if (type === txnTypes.TIP) {
return (
<Link onClick={this.abandonClaim.bind(this)} icon="icon-unlock-alt" title={__('Unlock')} />
<Link onClick={this.abandonClaim} label={__('Unlock Tip')} />
);
}
return <Link onClick={this.abandonClaim.bind(this)} icon="icon-trash" title={__('Revoke')} />;
return <Link onClick={this.abandonClaim} label={__('Abandon Claim')} />;
}
capitalize(string) {
capitalize(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
@ -49,11 +64,40 @@ class TransactionListItem extends React.PureComponent {
return (
<tr>
<td>
<CreditAmount amount={amount} plain showPlus precision={8} />
<br />
{fee !== 0 && (
<span className="table__item-label">
<CreditAmount plain fee amount={fee} precision={8} />
</span>
)}
</td>
<td>
<span>{this.capitalize(type)}</span> {isRevokeable && this.getLink(type)}
</td>
<td>
{reward && reward.reward_title}
{name && claimId && (
<Link
fakeLink
navigate="/show"
navigateParams={{ uri: buildURI({ name, claimId }) }}
>
{name}
</Link>
)}
</td>
<td>
<LinkTransaction id={txid} />
</td>
<td>
{date ? (
<div>
<DateTime date={date} show={DateTime.SHOW_DATE} formatOptions={dateFormat} />
<div className="meta">
<div className="table__item-label">
<DateTime date={date} show={DateTime.SHOW_TIME} />
</div>
</div>
@ -61,34 +105,9 @@ class TransactionListItem extends React.PureComponent {
<span className="empty">{__('Pending')}</span>
)}
</td>
<td>
<CreditAmount amount={amount} look="plain" label={false} showPlus precision={8} />
<br />
{fee != 0 && <CreditAmount amount={fee} look="fee" label={false} precision={8} />}
</td>
<td>
{this.capitalize(type)} {isRevokeable && this.getLink(type)}
</td>
<td>
{reward && <Link navigate="/rewards">{__('Reward: %s', reward.reward_title)}</Link>}
{name &&
claimId && (
<Link
className="button-text"
navigate="/show"
navigateParams={{ uri: buildURI({ name, claimId }) }}
>
{name}
</Link>
)}
</td>
<td>
<LinkTransaction id={txid} />
</td>
</tr>
);
}
}
export default TransactionListItem;
/* eslint-disable */

View file

@ -1,82 +1,114 @@
// I'll come back to this
/* eslint-disable */
import React from 'react';
import TransactionListItem from './internal/TransactionListItem';
import { FormRow } from 'component/common/form';
// @flow
import * as React from 'react';
import { FormField } from 'component/common/form';
import Link from 'component/link';
import * as icons from 'constants/icons';
import * as modals from 'constants/modal_types';
import TransactionListItem from './internal/transaction-list-item';
class TransactionList extends React.PureComponent {
constructor(props) {
export type Transaction = {
amount: number,
claim_id: string,
claim_name: string,
fee: number,
nout: number,
txid: string,
type: string,
date: Date
}
type Props = {
emptyMessage: ?string,
noFilter?: boolean,
transactions: Array<Transaction>,
rewards: {},
openModal: (string, any) => void,
myClaims: any
}
type State = {
filter: string
}
class TransactionList extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
filter: null,
filter: "all",
};
(this: any).handleFilterChanged = this.handleFilterChanged.bind(this);
(this: any).filterTransaction = this.filterTransaction.bind(this);
(this: any).revokeClaim = this.revokeClaim.bind(this);
(this: any).isRevokeable = this.isRevokeable.bind(this);
}
handleFilterChanged(event) {
handleFilterChanged(event: SyntheticInputEvent<*>) {
this.setState({
filter: event.target.value,
});
}
filterTransaction(transaction) {
filterTransaction(transaction: Transaction) {
const { filter } = this.state;
return !filter || filter == transaction.type;
return filter == "all" || filter === transaction.type;
}
isRevokeable(txid, nout) {
isRevokeable(txid: string, nout: number) {
const { myClaims } = this.props;
// a claim/support/update is revokable if it
// is in my claim list(claim_list_mine)
return this.props.myClaims.has(`${txid}:${nout}`);
return myClaims.has(`${txid}:${nout}`);
}
revokeClaim(txid, nout) {
revokeClaim(txid: string, nout: number) {
this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, { txid, nout });
}
render() {
const { emptyMessage, rewards, transactions } = this.props;
const transactionList = transactions.filter(this.filterTransaction.bind(this));
const { emptyMessage, rewards, transactions, noFilter } = this.props;
const { filter } = this.state;
const transactionList = transactions.filter(this.filterTransaction);
return (
<div>
{(transactionList.length || this.state.filter) && (
<FormRow
prefix={__('Filter')}
postfix={
<Link fakeLink href="https://lbry.io/faq/transaction-types" label={__('Help')} />
}
render={() => (
<select>
<option value="">{__('All')}</option>
<option value="spend">{__('Spends')}</option>
<option value="receive">{__('Receives')}</option>
<option value="publish">{__('Publishes')}</option>
<option value="channel">{__('Channels')}</option>
<option value="tip">{__('Tips')}</option>
<option value="support">{__('Supports')}</option>
<option value="update">{__('Updates')}</option>
</select>
)}
/>
)}
<React.Fragment>
{!transactionList.length && (
<div className="empty">{emptyMessage || __('No transactions to list.')}</div>
<div className="card__content">{emptyMessage || __('No transactions to list.')}</div>
)}
{Boolean(transactionList.length) && (
<table className="table-standard table-transactions table-stretch">
{!noFilter && transactionList.length && (
<div className="card__actions-top-corner">
<FormField
type="select"
value={filter}
onChange={this.handleFilterChanged}
prefix={__('Show')}
postfix={
<Link fakeLink href="https://lbry.io/faq/transaction-types" label={__('Help')} />
}
>
<option value="all">{__('All')}</option>
<option value="spend">{__('Spends')}</option>
<option value="receive">{__('Receives')}</option>
<option value="publish">{__('Publishes')}</option>
<option value="channel">{__('Channels')}</option>
<option value="tip">{__('Tips')}</option>
<option value="support">{__('Supports')}</option>
<option value="update">{__('Updates')}</option>
</FormField>
</div>
)}
{!!transactionList.length && (
<table className="table table--transactions table--stretch">
<thead>
<tr>
<th>{__('Date')}</th>
<th>{__('Amount (Fee)')}</th>
<th>{__('Amount')}</th>
<th>{__('Type')} </th>
<th>{__('Details')} </th>
<th>{__('Transaction')}</th>
<th>{__('Date')}</th>
</tr>
</thead>
<tbody>
@ -86,16 +118,15 @@ class TransactionList extends React.PureComponent {
transaction={t}
reward={rewards && rewards[t.txid]}
isRevokeable={this.isRevokeable(t.txid, t.nout)}
revokeClaim={this.revokeClaim.bind(this)}
revokeClaim={this.revokeClaim}
/>
))}
</tbody>
</table>
)}
</div>
</React.Fragment>
);
}
}
export default TransactionList;
/* eslint-enable */

View file

@ -4,16 +4,17 @@ import { BusyMessage } from 'component/common';
import Button from 'component/link';
import TransactionList from 'component/transactionList';
import * as icons from 'constants/icons';
import type { Transaction } from 'component/transactionList/view';
type Props = {
fetchTransactions: () => void,
fetchingTransactions: boolean,
hasTransactions: boolean,
transactions: Array<{}>, // Will iron this out when I work on transactions page - Sean
transactions: Array<Transaction>,
};
class TransactionListRecent extends React.PureComponent<Props> {
componentWillMount() {
componentDidMount() {
this.props.fetchTransactions();
}
@ -27,6 +28,7 @@ class TransactionListRecent extends React.PureComponent<Props> {
{fetchingTransactions && <BusyMessage message={__('Loading transactions')} />}
{!fetchingTransactions && (
<TransactionList
noFilter
transactions={transactions}
emptyMessage={__("Looks like you don't have any recent transactions.")}
/>

View file

@ -1,29 +1,20 @@
import React from 'react';
import { connect } from 'react-redux';
import { doFetchFileInfosAndPublishedClaims } from 'redux/actions/file_info';
import {
selectFileInfosDownloaded,
selectIsFetchingFileListDownloadedOrPublished,
} from 'redux/selectors/file_info';
import {
selectMyClaimsWithoutChannels,
selectIsFetchingClaimListMine,
} from 'redux/selectors/claims';
import { doFetchClaimListMine } from 'redux/actions/content';
import { doNavigate } from 'redux/actions/navigation';
import FileListDownloaded from './view';
const select = state => ({
fileInfos: selectFileInfosDownloaded(state),
isFetching: selectIsFetchingFileListDownloadedOrPublished(state),
claims: selectMyClaimsWithoutChannels(state),
isFetchingClaims: selectIsFetchingClaimListMine(state),
});
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
fetchFileInfosDownloaded: () => dispatch(doFetchFileInfosAndPublishedClaims()),
fetchClaims: () => dispatch(doFetchClaimListMine()),
});
export default connect(select, perform)(FileListDownloaded);

View file

@ -1,36 +1,32 @@
import React from 'react';
import Link from 'component/link';
import { FileTile } from 'component/fileTile';
import { BusyMessage, Thumbnail } from 'component/common.js';
import FileList from 'component/fileList';
import Page from 'component/page';
class FileListDownloaded extends React.PureComponent {
componentWillMount() {
if (!this.props.isFetchingClaims) this.props.fetchClaims();
if (!this.props.isFetching) this.props.fetchFileInfosDownloaded();
}
render() {
const { fileInfos, isFetching, navigate } = this.props;
const { fileInfos, navigate } = this.props;
const hasDownloads = fileInfos && fileInfos.length > 0;
neb-b commented 2018-02-15 23:46:16 +01:00 (Migrated from github.com)
Review

We fetch this on app startup, no need to fetch them again

We fetch this on app startup, no need to fetch them again
let content;
if (fileInfos && fileInfos.length > 0) {
content = <FileList fileInfos={fileInfos} fetching={isFetching} />;
} else if (isFetching) {
content = <BusyMessage message={__('Loading')} />;
} else {
content = (
<span>
{__("You haven't downloaded anything from LBRY yet. Go")}{' '}
<Link
onClick={() => navigate('/discover')}
label={__('search for your first download')}
/>!
</span>
);
}
return <main className="main--single-column">{content}</main>;
return (
<Page>
{hasDownloads ? (
<FileList fileInfos={fileInfos} />
) : (
<div className="page__empty">
{__("You haven't downloaded anything from LBRY yet.")}
<div className="card__actions card__actions--center">
<Link
onClick={() => navigate('/discover')}
label={__('Explore new content')}
/>
</div>
</div>
)}
</Page>
);
}
}

View file

@ -1,24 +1,16 @@
import React from 'react';
import rewards from 'rewards';
import { connect } from 'react-redux';
import { doFetchClaimListMine } from 'redux/actions/content';
import {
selectMyClaimsWithoutChannels,
selectIsFetchingClaimListMine,
} from 'redux/selectors/claims';
import { doClaimRewardType } from 'redux/actions/rewards';
import { doNavigate } from 'redux/actions/navigation';
import FileListPublished from './view';
const select = state => ({
claims: selectMyClaimsWithoutChannels(state),
isFetching: selectIsFetchingClaimListMine(state),
});
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
fetchClaims: () => dispatch(doFetchClaimListMine()),
claimFirstPublishReward: () => dispatch(doClaimRewardType(rewards.TYPE_FIRST_PUBLISH)),
});
export default connect(select, perform)(FileListPublished);

View file

@ -1,46 +1,32 @@
import React from 'react';
import Link from 'component/link';
import FileTile from 'component/fileTile';
import { BusyMessage, Thumbnail } from 'component/common.js';
import FileList from 'component/fileList';
import Page from 'component/page';
class FileListPublished extends React.PureComponent {
componentWillMount() {
if (!this.props.isFetching) this.props.fetchClaims();
}
componentDidUpdate() {
// if (this.props.claims.length > 0) this.props.fetchClaims();
}
render() {
const { claims, isFetching, navigate } = this.props;
const { claims, navigate } = this.props;
const hasClaims = claims && claims.length > 0;
let content;
if (claims && claims.length > 0) {
content = (
<FileList
fileInfos={claims}
fetching={isFetching}
fileTileShowEmpty={FileTile.SHOW_EMPTY_PENDING}
/>
);
} else if (isFetching) {
content = <BusyMessage message={__('Loading')} />;
} else {
content = (
<span>
{__("It looks like you haven't published anything to LBRY yet. Go")}{' '}
<Link
onClick={() => navigate('/publish')}
label={__('share your beautiful cats with the world')}
/>!
</span>
);
}
return <main className="main--single-column">{content}</main>;
return (
<Page>
{hasClaims ? (
<FileList
fileInfos={claims}
/>
) : (
<div className="page__empty">
{__("It looks like you haven't published anything to LBRY yet.")}
<div className="card__actions card__actions--center">
<Link
onClick={() => navigate('/publish')}
label={__('Publish something new')}
/>
</div>
</div>
)}
</Page>
)
}
}

View file

@ -125,84 +125,83 @@ class HelpPage extends React.PureComponent {
<div className="card__title">
{__('About')}
</div>
<div className="card__content">
{this.state.upgradeAvailable !== null && this.state.upgradeAvailable ? (
<p>
<div className="card__subtitle">
{__('A newer version of LBRY is available.')}{' '}
<Link href={newVerLink} label={__('Download now!')} />
</p>
<Link fakeLink href={newVerLink} label={__('Download now!')} />
</div>
) : (
<p>{__('Your LBRY app is up to date.')}</p>
<div className="card__subtitle">{__('Your LBRY app is up to date.')}</div>
)}
{this.state.uiVersion && ver ? (
<table className="card__content table-standard table-stretch table-standard--definition-list">
<tbody>
<tr>
<th>{__('App')}</th>
<td>{this.state.uiVersion}</td>
</tr>
<tr>
<th>{__('Daemon (lbrynet)')}</th>
<td>{ver.lbrynet_version}</td>
</tr>
<tr>
<th>{__('Wallet (lbryum)')}</th>
<td>{ver.lbryum_version}</td>
</tr>
<tr>
<th>{__('Connected Email')}</th>
<td>
{user && user.primary_email ? (
user.primary_email
) : (
<span>
<span className="empty">{__('none')} </span>
(<Link onClick={() => doAuth()} label={__('set email')} />)
</span>
)}
</td>
</tr>
<tr>
<th>{__('Reward Eligible')}</th>
<td>
{user && user.is_reward_approved ? (
__("Yes")
) : (
__("No")
)}
</td>
</tr>
<tr>
<th>{__('Platform')}</th>
<td>{platform}</td>
</tr>
<tr>
<th>{__('Installation ID')}</th>
<td>{this.state.lbryId}</td>
</tr>
<tr>
<th>{__('Access Token')}</th>
<td>
{this.state.accessTokenHidden && (
<Link fakeLink label={__('View')} onClick={this.showAccessToken.bind(this)} />
)}
{!this.state.accessTokenHidden &&
accessToken && (
<div>
<p>{accessToken}</p>
<div className="help">
{__('This is equivalent to a password. Do not post or share this.')}
</div>
{this.state.uiVersion && ver ? (
<table className="table table--stretch table--help">
<tbody>
<tr>
<td>{__('App')}</td>
<td>{this.state.uiVersion}</td>
</tr>
<tr>
<td>{__('Daemon (lbrynet)')}</td>
<td>{ver.lbrynet_version}</td>
</tr>
<tr>
<td>{__('Wallet (lbryum)')}</td>
<td>{ver.lbryum_version}</td>
</tr>
<tr>
<td>{__('Connected Email')}</td>
<td>
{user && user.primary_email ? (
user.primary_email
) : (
<span>
<span className="empty">{__('none')} </span>
(<Link onClick={() => doAuth()} label={__('set email')} />)
</span>
)}
</td>
</tr>
<tr>
<td>{__('Reward Eligible')}</td>
<td>
{user && user.is_reward_approved ? (
__("Yes")
) : (
__("No")
)}
</td>
</tr>
<tr>
<td>{__('Platform')}</td>
<td>{platform}</td>
</tr>
<tr>
<td>{__('Installation ID')}</td>
<td>{this.state.lbryId}</td>
</tr>
<tr>
<td>{__('Access Token')}</td>
<td>
{this.state.accessTokenHidden && (
<Link fakeLink label={__('View')} onClick={this.showAccessToken.bind(this)} />
)}
{!this.state.accessTokenHidden &&
accessToken && (
<div>
<p>{accessToken}</p>
<div className="help">
{__('This is equivalent to a password. Do not post or share this.')}
</div>
)}
</td>
</tr>
</tbody>
</table>
) : (
<BusyMessage message={__('Looking up version info')} />
)}
</div>
</div>
)}
</td>
</tr>
</tbody>
</table>
) : (
<BusyMessage message={__('Looking up version info')} />
)}
</section>
</Page>
);

View file

@ -196,6 +196,11 @@ dd {
font-size: 3em;
}
.page__empty {
margin-top: 200px;
text-align: center;
}
.columns {
display: flex;
justify-content: space-between;
@ -246,6 +251,13 @@ dd {
font-weight: 800;
}
.credit-amount--plain {
background-color: inherit;
color: inherit;
font-weight: inherit;
font-size: 1em;
}
//
// .credit-amount--fee {
// font-size: 0.9em;

View file

@ -9,15 +9,16 @@ $width-page-constrained: 800px;
--color-white: #fff;
--color-black: #000; // I shouldn't use color names like this
--color-grey: #d6d6d6;
--color-grey-dark: #8e8e8e;
--color-grey-dark: #888;
--color-primary: #44b098;
--color-primary-dark: #2c6e60;
--color-secondary: #6afbda;
--color-third: #fbd55e;
--color-fourth: #49b2e2;
--color-divider: #e3e3e3;
--text-color: var(--color-black);
--color-brand: #155b4a;
// --color-brand: #155b4a;
--color-dark-overlay: rgba(32, 32, 32, 0.9);
--color-help: rgba(0, 0, 0, 0.54);
// --color-notice: #8a6d3b;
@ -89,7 +90,7 @@ $width-page-constrained: 800px;
--btn-primary-color: #fff;
--button-alt-color: var(--text-color);
--btn-primary-bg: var(--color-primary);
--btn-inverse-color: var(--color-primary-dark);
--btn-inverse-color: var(--color-primary);
--btn-inverse-bg: var(--color-white);
--btn-radius: 20px;
--btn-height: 40px;

View file

@ -6,7 +6,6 @@
@import 'component/_button.scss';
@import 'component/_card.scss';
@import 'component/_file-download.scss';
@import 'component/_file-tile.scss';
@import 'component/_form-field.scss';
@import 'component/_header.scss';
@import 'component/_menu.scss';
@ -20,6 +19,6 @@
@import 'component/_pagination.scss';
@import 'component/_markdown-editor.scss';
@import 'component/_scrollbar.scss';
@import 'component/_divider.scss';
@import 'component/_spinner.scss';
@import 'component/_nav.scss';
@import 'component/_file-list.scss';

View file

@ -1,8 +0,0 @@
.divider__horizontal {
border-top: var(--divider);
margin: 16px 0;
}
.divider__vertical {
margin: 10px;
}

View file

@ -37,11 +37,7 @@
min-width: var(--btn-height);
border-radius: var(--btn-radius);
color: var(--btn-primary-color);
// TODO: Why does using --color-primary not work here? something is being overriden
// background-color: var(--color-primary);
background-color: #44b098;
background-color: var(--color-primary);
display: flex;
align-items: center;
justify-content: center;
@ -90,6 +86,7 @@
background-color: inherit;
font-size: 1em;
color: var(--btn-inverse-color);
border-bottom: 1px solid var(--btn-inverse-color);
border-radius: 0;
display: inline;
@ -99,12 +96,17 @@
}
}
.btn--secondary {
.btn.btn--external-link:not(.btn--primary):not(.btn--secondary) {
color: var(--color-fourth);
border-bottom: 1px solid var(--color-fourth);
}
.btn.btn--secondary {
background-color: var(--color-secondary);
color: var(--color-primary);
}
.btn--no-style {
.btn.btn--no-style {
font-size: inherit;
font-weight: inherit;
color: inherit;

View file

@ -160,12 +160,19 @@
.card__actions--center {
align-items: center;
justify-content: center;
.btn {
margin: 0 $spacing-vertical / 3;
}
}
.card__actions-top-corner {
position: absolute;
top: $spacing-vertical;
right: $spacing-vertical;
}
/*
.card-row is used on the discover/subscriptions page
It is a list of cards that extend past the right edge of the screen

View file

@ -0,0 +1,11 @@
.file-list {
display: grid;
grid-gap: $spacing-vertical * 2/3;
grid-template-columns: repeat(auto-fill, var(--card-small-width));
margin-top: $spacing-vertical * 2/3;
}
.file-list__sort {
display: flex;
justify-content: flex-end;
}

View file

@ -1,22 +0,0 @@
$height-file-tile: $spacing-vertical * 6;
.file-tile__row {
overflow: hidden;
height: $height-file-tile;
//also a hack
.card__media {
height: $height-file-tile;
max-width: $height-file-tile;
width: $height-file-tile;
margin-right: $spacing-vertical / 2;
float: left;
}
//basically everything here is a hack now
.file-tile__content {
padding-top: $spacing-vertical * 1/3;
margin-left: $height-file-tile + $spacing-vertical / 2;
}
.card__title-primary {
margin-top: 0;
}
}

View file

@ -20,12 +20,6 @@
}
}
.form-field {
label {
cursor: pointer;
}
}
.form-field__input {
display: flex;
padding-top: $spacing-vertical / 3;

View file

@ -15,6 +15,10 @@
margin-left: auto;
padding-left: $spacing-vertical / 2;
display: flex;
.btn {
margin-left: $spacing-vertical * 1/3;
}
}
.header__wunderbar {

View file

@ -1,25 +0,0 @@
.shapeshift__tx-info {
min-height: 63px;
}
.shapeshift__deposit-address-wrapper {
display: flex;
flex-direction: row;
* {
align-self: center;
}
}
// this should be pulled out into it's own styling when we add more qr codes
.shapeshift__qrcode {
// don't use a variable here. adds a white border for easier reading in dark mode
// needs to stay the same no matter what theme is present
background-color: #fff;
padding: 2px;
margin-left: 40px;
}
.shapeshift__link {
padding-left: 10px;
}

View file

@ -4,30 +4,36 @@
height: 40px;
text-align: center;
font-size: 10px;
.rect {
display: inline-block;
height: 100%;
width: 6px;
margin: 0 2px;
background-color: var(--color-white);
animation: sk-stretchdelay 1.2s infinite ease-in-out;
&.rect2 {
animation-delay: -1.1s;
}
&.rect3 {
animation-delay: -1s;
}
&.rect4 {
animation-delay: -0.9s;
}
&.rect5 {
animation-delay: -0.8s;
}
}
}
.spinner > div {
display: inline-block;
height: 100%;
width: 6px;
margin: 0 2px;
background-color: var(--color-white);
animation: sk-stretchdelay 1.2s infinite ease-in-out;
&.rect2 {
animation-delay: -1.1s;
}
&.rect3 {
animation-delay: -1s;
}
&.rect4 {
animation-delay: -0.9s;
}
&.rect5 {
animation-delay: -0.8s;
.spinner--dark {
.rect {
background-color: var(--color-black);
}
}

View file

@ -1,40 +1,38 @@
table.table-standard {
table.table {
margin-top: $spacing-vertical;
word-wrap: break-word;
max-width: 100%;
text-align: left;
tr td:first-of-type,
tr th:first-of-type {
padding-left: $spacing-vertical * 2/3;
}
tr td:last-of-type,
tr th:last-of-type {
padding-right: $spacing-vertical * 2/3;
}
thead {
border-bottom: 1px solid var(--color-grey);
}
th,
td {
padding: $spacing-vertical/2 8px;
}
th {
font-weight: 500;
font-size: 0.9em;
}
td {
vertical-align: top;
}
thead th,
> tr:first-child th {
vertical-align: bottom;
font-weight: 500;
font-size: 0.9em;
padding: $spacing-vertical/4+1 8px $spacing-vertical/4-2;
text-align: left;
border-bottom: var(--table-border);
img {
vertical-align: text-bottom;
}
&.text-center {
text-align: center;
font-size: .8em;
color: var(--color-grey-dark);
padding: $spacing-vertical * 1/6 0;
.btn:not(.btn--link) {
display: inline;
margin-left: $spacing-vertical * 1/3;
}
}
tr.thead:not(:first-child) th {
border-top: var(--table-border);
}
tfoot td {
padding: $spacing-vertical / 2 8px;
font-size: 0.85em;
.table__item-label {
font-size: .8em;
}
tbody {
tr {
&:nth-child(even):not(.odd) {
@ -52,28 +50,31 @@ table.table-standard {
}
}
}
.table-standard--definition-list {
th {
text-align: right;
}
}
table.table-stretch {
table.table--stretch {
width: 100%;
}
table.table-transactions {
table.table--help {
td:nth-of-type(1) {
width: 15%;
color: var(--color-black);
font-weight: 700;
min-width: 130px;
}
}
table.table--transactions {
td:nth-of-type(1) {
width: 17.5%;
}
td:nth-of-type(2) {
width: 15%;
width: 27.5%;
}
td:nth-of-type(3) {
width: 15%;
width: 22.5%;
}
td:nth-of-type(4) {
width: 40%;
width: 17.5%;
}
td:nth-of-type(5) {
width: 15%;

View file

@ -1,8 +1 @@
:root {
/* Colors */
--color-primary: #155B4A;
/* search */
--search-bg: var(--color-canvas);
--search-border: 1px solid rgba(0,0,0,0.15);
}
:root {}