[redesign] navigation/wallet pages
This commit is contained in:
parent
2d72d1f663
commit
f1c960c3c6
93 changed files with 1551 additions and 6033 deletions
|
@ -18,6 +18,7 @@ module.name_mapper='^types\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/types\1'
|
||||||
module.name_mapper='^component\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/component\1'
|
module.name_mapper='^component\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/component\1'
|
||||||
module.name_mapper='^page\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/page\1'
|
module.name_mapper='^page\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/page\1'
|
||||||
module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
|
module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
|
||||||
|
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/rewards\1'
|
||||||
module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
|
module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
|
||||||
|
|
||||||
[strict]
|
[strict]
|
||||||
|
|
3
flow-typed/react-feather.js
vendored
Normal file
3
flow-typed/react-feather.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
declare module 'react-feather' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
25
npm-debug.log.3540228334
Normal file
25
npm-debug.log.3540228334
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
0 info it worked if it ends with ok
|
||||||
|
1 verbose cli [ '/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/node',
|
||||||
|
1 verbose cli '/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/npm',
|
||||||
|
1 verbose cli 'config',
|
||||||
|
1 verbose cli '--loglevel=warn',
|
||||||
|
1 verbose cli 'get',
|
||||||
|
1 verbose cli 'prefix' ]
|
||||||
|
2 info using npm@3.10.10
|
||||||
|
3 info using node@v6.12.0
|
||||||
|
4 verbose exit [ 0, true ]
|
||||||
|
5 verbose stack Error: write EPIPE
|
||||||
|
5 verbose stack at exports._errnoException (util.js:1020:11)
|
||||||
|
5 verbose stack at WriteWrap.afterWrite (net.js:800:14)
|
||||||
|
6 verbose cwd /Users/seanyesmunt/Workspace/lbry/lbry-app
|
||||||
|
7 error Darwin 17.3.0
|
||||||
|
8 error argv "/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/node" "/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/npm" "config" "--loglevel=warn" "get" "prefix"
|
||||||
|
9 error node v6.12.0
|
||||||
|
10 error npm v3.10.10
|
||||||
|
11 error code EPIPE
|
||||||
|
12 error errno EPIPE
|
||||||
|
13 error syscall write
|
||||||
|
14 error write EPIPE
|
||||||
|
15 error If you need help, you may report this error at:
|
||||||
|
15 error <https://github.com/npm/npm/issues>
|
||||||
|
16 verbose exit [ 1, true ]
|
25
npm-debug.log.3958211012
Normal file
25
npm-debug.log.3958211012
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
0 info it worked if it ends with ok
|
||||||
|
1 verbose cli [ '/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/node',
|
||||||
|
1 verbose cli '/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/npm',
|
||||||
|
1 verbose cli 'config',
|
||||||
|
1 verbose cli '--loglevel=warn',
|
||||||
|
1 verbose cli 'get',
|
||||||
|
1 verbose cli 'prefix' ]
|
||||||
|
2 info using npm@3.10.10
|
||||||
|
3 info using node@v6.12.0
|
||||||
|
4 verbose exit [ 0, true ]
|
||||||
|
5 verbose stack Error: write EPIPE
|
||||||
|
5 verbose stack at exports._errnoException (util.js:1020:11)
|
||||||
|
5 verbose stack at WriteWrap.afterWrite (net.js:800:14)
|
||||||
|
6 verbose cwd /Users/seanyesmunt/Workspace/lbry/lbry-app
|
||||||
|
7 error Darwin 17.3.0
|
||||||
|
8 error argv "/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/node" "/Users/seanyesmunt/.nvm/versions/node/v6.12.0/bin/npm" "config" "--loglevel=warn" "get" "prefix"
|
||||||
|
9 error node v6.12.0
|
||||||
|
10 error npm v3.10.10
|
||||||
|
11 error code EPIPE
|
||||||
|
12 error errno EPIPE
|
||||||
|
13 error syscall write
|
||||||
|
14 error write EPIPE
|
||||||
|
15 error If you need help, you may report this error at:
|
||||||
|
15 error <https://github.com/npm/npm/issues>
|
||||||
|
16 verbose exit [ 1, true ]
|
|
@ -52,6 +52,7 @@
|
||||||
"rc-progress": "^2.0.6",
|
"rc-progress": "^2.0.6",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
"react-dom": "^16.2.0",
|
"react-dom": "^16.2.0",
|
||||||
|
"react-feather": "^1.0.8",
|
||||||
"react-markdown": "^2.5.0",
|
"react-markdown": "^2.5.0",
|
||||||
"react-modal": "^3.1.7",
|
"react-modal": "^3.1.7",
|
||||||
"react-paginate": "^5.0.0",
|
"react-paginate": "^5.0.0",
|
||||||
|
|
|
@ -1,52 +1,56 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
import PropTypes from 'prop-types';
|
import * as React from 'react';
|
||||||
import { clipboard } from 'electron';
|
import { clipboard } from 'electron';
|
||||||
import Link from 'component/link';
|
import { FormField } from 'component/common/form';
|
||||||
import classnames from 'classnames';
|
import Button from 'component/link';
|
||||||
|
|
||||||
export default class Address extends React.PureComponent {
|
type Props = {
|
||||||
static propTypes = {
|
address: string,
|
||||||
address: PropTypes.string,
|
doShowSnackBar: ({ message: string }) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
export default class Address extends React.PureComponent<Props> {
|
||||||
super(props);
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
this._inputElem = null;
|
this.input = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { address, showCopyButton, doShowSnackBar } = this.props;
|
const { address, doShowSnackBar } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-field form-field--address">
|
<FormField
|
||||||
|
name="address"
|
||||||
|
render={() => (
|
||||||
|
<React.Fragment>
|
||||||
<input
|
<input
|
||||||
className={classnames('input-copyable', {
|
id="address"
|
||||||
'input-copyable--with-copy-btn': showCopyButton,
|
className="input-copyable"
|
||||||
})}
|
readOnly
|
||||||
type="text"
|
value={address || ''}
|
||||||
ref={input => {
|
ref={input => {
|
||||||
this._inputElem = input;
|
this.input = input;
|
||||||
}}
|
}}
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
this._inputElem.select();
|
if (this.input) {
|
||||||
|
this.input.select();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
readOnly="readonly"
|
|
||||||
value={address || ''}
|
|
||||||
/>
|
/>
|
||||||
{showCopyButton && (
|
<Button
|
||||||
<span className="header__item">
|
alt
|
||||||
<Link
|
icon="Clipboard"
|
||||||
button="alt button--flat"
|
|
||||||
icon="clipboard"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(address);
|
clipboard.writeText(address);
|
||||||
doShowSnackBar({ message: __('Address copied') });
|
doShowSnackBar({ message: __('Address copied') });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</span>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
selectPageTitle,
|
selectPageTitle,
|
||||||
|
@ -10,7 +9,7 @@ import { doAlertError } from 'redux/actions/app';
|
||||||
import { doRecordScroll } from 'redux/actions/navigation';
|
import { doRecordScroll } from 'redux/actions/navigation';
|
||||||
import App from './view';
|
import App from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = state => ({
|
||||||
pageTitle: selectPageTitle(state),
|
pageTitle: selectPageTitle(state),
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
currentStackIndex: selectHistoryIndex(state),
|
currentStackIndex: selectHistoryIndex(state),
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'component/router/index';
|
import Router from 'component/router/index';
|
||||||
import Header from 'component/header';
|
|
||||||
import Theme from 'component/theme';
|
import Theme from 'component/theme';
|
||||||
import ModalRouter from 'modal/modalRouter';
|
import ModalRouter from 'modal/modalRouter';
|
||||||
import ReactModal from 'react-modal';
|
import ReactModal from 'react-modal';
|
||||||
import throttle from 'util/throttle';
|
import throttle from 'util/throttle';
|
||||||
|
import SideBar from 'component/sideBar';
|
||||||
|
import Header from 'component/header';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
alertError: (string | {}) => void,
|
alertError: (string | {}) => void,
|
||||||
|
@ -33,7 +34,7 @@ class App extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const mainContent = document.getElementById('main-content');
|
const mainContent = document.getElementById('content');
|
||||||
this.mainContent = mainContent;
|
this.mainContent = mainContent;
|
||||||
|
|
||||||
if (this.mainContent) {
|
if (this.mainContent) {
|
||||||
|
@ -82,10 +83,15 @@ class App extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<div id="window">
|
<div id="window">
|
||||||
<Theme />
|
<Theme />
|
||||||
|
<main className="page">
|
||||||
|
<SideBar />
|
||||||
<Header />
|
<Header />
|
||||||
|
<div className="content" id="content">
|
||||||
<Router />
|
<Router />
|
||||||
<ModalRouter />
|
<ModalRouter />
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,78 +44,6 @@ export class CurrencySymbol extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreditAmount extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
amount: PropTypes.number.isRequired,
|
|
||||||
precision: PropTypes.number,
|
|
||||||
isEstimate: PropTypes.bool,
|
|
||||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
||||||
showFree: PropTypes.bool,
|
|
||||||
showFullPrice: PropTypes.bool,
|
|
||||||
showPlus: PropTypes.bool,
|
|
||||||
look: PropTypes.oneOf(['indicator', 'plain', 'fee']),
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
precision: 2,
|
|
||||||
label: true,
|
|
||||||
showFree: false,
|
|
||||||
look: 'indicator',
|
|
||||||
showFullPrice: false,
|
|
||||||
showPlus: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const minimumRenderableAmount = Math.pow(10, -1 * this.props.precision);
|
|
||||||
const { amount, precision, showFullPrice } = this.props;
|
|
||||||
|
|
||||||
let formattedAmount;
|
|
||||||
const fullPrice = formatFullPrice(amount, 2);
|
|
||||||
|
|
||||||
if (showFullPrice) {
|
|
||||||
formattedAmount = fullPrice;
|
|
||||||
} else {
|
|
||||||
formattedAmount =
|
|
||||||
amount > 0 && amount < minimumRenderableAmount
|
|
||||||
? `<${minimumRenderableAmount}`
|
|
||||||
: formatCredits(amount, precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountText;
|
|
||||||
if (this.props.showFree && parseFloat(this.props.amount) === 0) {
|
|
||||||
amountText = __('free');
|
|
||||||
} else {
|
|
||||||
if (this.props.label) {
|
|
||||||
const label =
|
|
||||||
typeof this.props.label === 'string'
|
|
||||||
? this.props.label
|
|
||||||
: parseFloat(amount) == 1 ? __('credit') : __('credits');
|
|
||||||
|
|
||||||
amountText = `${formattedAmount} ${label}`;
|
|
||||||
} else {
|
|
||||||
amountText = formattedAmount;
|
|
||||||
}
|
|
||||||
if (this.props.showPlus && amount > 0) {
|
|
||||||
amountText = `+${amountText}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className={`credit-amount credit-amount--${this.props.look}`} title={fullPrice}>
|
|
||||||
<span>{amountText}</span>
|
|
||||||
{this.props.isEstimate ? (
|
|
||||||
<span
|
|
||||||
className="credit-amount__estimate"
|
|
||||||
title={__('This is an estimate and does not include data fees')}
|
|
||||||
>
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Thumbnail extends React.PureComponent {
|
export class Thumbnail extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
src: PropTypes.string,
|
src: PropTypes.string,
|
||||||
|
|
|
@ -200,7 +200,7 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
<h3>
|
<h3>
|
||||||
{categoryLink ? (
|
{categoryLink ? (
|
||||||
<Button
|
<Button
|
||||||
className="button-text no-underline"
|
noStyle
|
||||||
label={category}
|
label={category}
|
||||||
navigate="/show"
|
navigate="/show"
|
||||||
navigateParams={{ uri: categoryLink }}
|
navigateParams={{ uri: categoryLink }}
|
||||||
|
@ -219,20 +219,20 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="card-row__scroll-btns">
|
||||||
<Button
|
<Button
|
||||||
inverse
|
inverse
|
||||||
circle
|
circle
|
||||||
disabled={!canScrollPrevious}
|
disabled={!canScrollPrevious}
|
||||||
onClick={this.handleScrollPrevious}
|
onClick={this.handleScrollPrevious}
|
||||||
icon="chevron-left"
|
icon="ChevronLeft"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
inverse
|
inverse
|
||||||
circle
|
circle
|
||||||
disabled={!canScrollNext}
|
disabled={!canScrollNext}
|
||||||
onClick={this.handleScrollNext}
|
onClick={this.handleScrollNext}
|
||||||
icon="chevron-right"
|
icon="ChevronRight"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
76
src/renderer/component/common/credit-amount.jsx
Normal file
76
src/renderer/component/common/credit-amount.jsx
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { formatCredits, formatFullPrice } from 'util/formatCredits';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
amount: number,
|
||||||
|
precision: number,
|
||||||
|
showFree: boolean,
|
||||||
|
showFullPrice: boolean,
|
||||||
|
showPlus: boolean,
|
||||||
|
isEstimate?: boolean,
|
||||||
|
large?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CreditAmount extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
precision: 2,
|
||||||
|
showFree: false,
|
||||||
|
showFullPrice: false,
|
||||||
|
showPlus: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { amount, precision, showFullPrice, showFree, showPlus, large, isEstimate } = this.props;
|
||||||
|
|
||||||
|
const minimumRenderableAmount = 10 ** (-1 * precision);
|
||||||
|
const fullPrice = formatFullPrice(amount, 2);
|
||||||
|
const isFree = parseFloat(amount) === 0;
|
||||||
|
|
||||||
|
let formattedAmount;
|
||||||
|
if (showFullPrice) {
|
||||||
|
formattedAmount = fullPrice;
|
||||||
|
} else {
|
||||||
|
formattedAmount =
|
||||||
|
amount > 0 && amount < minimumRenderableAmount
|
||||||
|
? `<${minimumRenderableAmount}`
|
||||||
|
: formatCredits(amount, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
let amountText;
|
||||||
|
if (showFree && isFree) {
|
||||||
|
amountText = __('FREE');
|
||||||
|
} else {
|
||||||
|
amountText = `${formattedAmount} ${__('LBC')}`;
|
||||||
|
|
||||||
|
if (showPlus && amount > 0) {
|
||||||
|
amountText = `+${amountText}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
title={fullPrice}
|
||||||
|
className={classnames('credit-amount', {
|
||||||
|
'credit-amount--free': !large && isFree,
|
||||||
|
'credit-amount--cost': !large && !isFree,
|
||||||
|
'credit-amount--large': large,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{amountText}
|
||||||
|
|
||||||
|
{isEstimate ? (
|
||||||
|
<span
|
||||||
|
className="credit-amount__estimate"
|
||||||
|
title={__('This is an estimate and does not include data fees')}
|
||||||
|
>
|
||||||
|
*
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreditAmount;
|
85
src/renderer/component/common/form.jsx
Normal file
85
src/renderer/component/common/form.jsx
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// @flow
|
||||||
|
/* eslint-disable react/no-multi-comp */
|
||||||
|
import * as React from 'react';
|
||||||
|
import Button from 'component/link';
|
||||||
|
|
||||||
|
type FormRowProps = {
|
||||||
|
children: React.Node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormRow = (props: FormRowProps) => {
|
||||||
|
const { children } = props;
|
||||||
|
return <div className="form-row">{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FormFieldProps = {
|
||||||
|
render: () => React.Node,
|
||||||
|
label?: string,
|
||||||
|
prefix?: string,
|
||||||
|
postfix?: string,
|
||||||
|
error?: string | boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class FormField extends React.PureComponent<FormFieldProps> {
|
||||||
|
render() {
|
||||||
|
const { render, label, prefix, postfix, error } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="form-field">
|
||||||
|
{label && (
|
||||||
|
<label className="form-field__label">
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
<div className="form-field__wrapper">
|
||||||
|
{prefix && <span className="form-field__prefix">{prefix}</span>}
|
||||||
|
{render()}
|
||||||
|
{postfix && <span className="form-field__postfix">{postfix}</span>}
|
||||||
|
</div>
|
||||||
|
{error && (
|
||||||
|
<div className="form-field__error">
|
||||||
|
{typeof error === 'string' ? error : __('There was an error')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubmitProps = {
|
||||||
|
label: string,
|
||||||
|
disabled: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Submit extends React.PureComponent<SubmitProps> {
|
||||||
|
static defaultProps = {
|
||||||
|
label: 'Submit',
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { label, disabled } = this.props;
|
||||||
|
return <Button type="submit" label={label} disabled={disabled} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormProps = {
|
||||||
|
children: React.Node,
|
||||||
|
onSubmit: any => any,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Form extends React.PureComponent<FormProps> {
|
||||||
|
render() {
|
||||||
|
const { children, onSubmit } = this.props;
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="form"
|
||||||
|
onSubmit={event => {
|
||||||
|
event.preventDefault();
|
||||||
|
onSubmit(event);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* eslint-enable react/no-multi-comp */
|
|
@ -1,43 +1,22 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
// import * as icons from 'constants/icons';
|
||||||
import * as icons from 'constants/icons';
|
import * as Icons from 'react-feather';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
icon: string,
|
icon: string,
|
||||||
fixed?: boolean,
|
size?: number,
|
||||||
padded?: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Icon extends React.PureComponent<Props> {
|
class IconComponent extends React.PureComponent<Props> {
|
||||||
getIconTitle() {
|
// TODO: Move all icons to constants and add titles for all
|
||||||
const { icon } = this.props;
|
// Add some some sort of hover flyout with the title?
|
||||||
|
|
||||||
switch (icon) {
|
|
||||||
case icons.FEATURED:
|
|
||||||
return __('Watch this and earn rewards.');
|
|
||||||
case icons.LOCAL:
|
|
||||||
return __('You have a copy of this file.');
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { icon, fixed, padded } = this.props;
|
const { icon, size = 14 } = this.props;
|
||||||
const iconClassName = icon.startsWith('icon-') ? icon : `icon-${icon}`;
|
const Icon = Icons[icon];
|
||||||
const title = this.getIconTitle();
|
return Icon ? <Icon size={size} className="icon" /> : null;
|
||||||
|
|
||||||
const spanClassName = classnames(
|
|
||||||
{
|
|
||||||
'icon--fixed-width': fixed,
|
|
||||||
'icon--padded': padded,
|
|
||||||
},
|
|
||||||
iconClassName
|
|
||||||
);
|
|
||||||
|
|
||||||
return <span className={spanClassName} title={title} />;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Icon;
|
export default IconComponent;
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ToolTip extends React.PureComponent<Props, State> {
|
||||||
<span className="tooltip">
|
<span className="tooltip">
|
||||||
<Button fakeLink className="help tooltip__link" onClick={this.handleClick}>
|
<Button fakeLink className="help tooltip__link" onClick={this.handleClick}>
|
||||||
{label}
|
{label}
|
||||||
{showTooltip && <Icon icon="times" fixed />}
|
{showTooltip && <Icon icon="X" />}
|
||||||
</Button>
|
</Button>
|
||||||
<div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div>
|
<div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -78,6 +78,9 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<CardMedia thumbnail={thumbnail} />
|
<CardMedia thumbnail={thumbnail} />
|
||||||
|
<div className="card-media__internal-links">
|
||||||
|
<FilePrice uri={uri} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="card__title-identity">
|
<div className="card__title-identity">
|
||||||
<div className="card__title--small">
|
<div className="card__title--small">
|
||||||
|
@ -87,8 +90,8 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
<div className="card__subtitle">
|
<div className="card__subtitle">
|
||||||
<UriIndicator uri={uri} link />
|
<UriIndicator uri={uri} link />
|
||||||
<div className="card--file-subtitle">
|
<div className="card--file-subtitle">
|
||||||
<FilePrice uri={uri} /> {isRewardContent && <Icon icon={icons.FEATURED} padded />}
|
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||||
{fileInfo && <Icon icon={icons.LOCAL} padded />}
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,35 +1,48 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CreditAmount } from 'component/common';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
showFullPrice: boolean,
|
||||||
|
costInfo: ?{ includesData: boolean, cost: number },
|
||||||
|
fetchCostInfo: string => void,
|
||||||
|
uri: string,
|
||||||
|
fetching: boolean,
|
||||||
|
claim: ?{},
|
||||||
|
};
|
||||||
|
|
||||||
|
class FilePrice extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
showFullPrice: false,
|
||||||
|
};
|
||||||
|
|
||||||
class FilePrice extends React.PureComponent {
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.fetchCost(this.props);
|
this.fetchCost(this.props);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
this.fetchCost(nextProps);
|
this.fetchCost(nextProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchCost(props) {
|
fetchCost = (props: Props) => {
|
||||||
const { costInfo, fetchCostInfo, uri, fetching, claim } = props;
|
const { costInfo, fetchCostInfo, uri, fetching, claim } = props;
|
||||||
|
|
||||||
if (costInfo === undefined && !fetching && claim) {
|
if (costInfo === undefined && !fetching && claim) {
|
||||||
fetchCostInfo(uri);
|
fetchCostInfo(uri);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { costInfo, look = 'indicator', showFullPrice = false } = this.props;
|
const { costInfo, showFullPrice } = this.props;
|
||||||
|
|
||||||
const isEstimate = costInfo ? !costInfo.includesData : null;
|
const isEstimate = costInfo ? !costInfo.includesData : false;
|
||||||
|
|
||||||
if (!costInfo) {
|
if (!costInfo) {
|
||||||
return <span className={`credit-amount credit-amount--${look}`}>???</span>;
|
return <span className="credit-amount">???</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CreditAmount
|
<CreditAmount
|
||||||
label={false}
|
|
||||||
amount={costInfo.cost}
|
amount={costInfo.cost}
|
||||||
isEstimate={isEstimate}
|
isEstimate={isEstimate}
|
||||||
showFree
|
showFree
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import FormField from 'component/formField';
|
|
||||||
import Icon from 'component/common/icon';
|
|
||||||
|
|
||||||
let formFieldCounter = 0;
|
|
||||||
|
|
||||||
export const formFieldNestedLabelTypes = ['radio', 'checkbox'];
|
|
||||||
|
|
||||||
export function formFieldId() {
|
|
||||||
return `form-field-${++formFieldCounter}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Form extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
onSubmit: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.props.onSubmit();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <form onSubmit={event => this.handleSubmit(event)}>{this.props.children}</form>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FormRow extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
|
||||||
errorMessage: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
||||||
// helper: PropTypes.html,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
isFocus: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._field = null;
|
|
||||||
|
|
||||||
this._fieldRequiredText = __('This field is required');
|
|
||||||
|
|
||||||
this.state = this.getStateFromProps(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
this.setState(this.getStateFromProps(nextProps));
|
|
||||||
}
|
|
||||||
|
|
||||||
getStateFromProps(props) {
|
|
||||||
return {
|
|
||||||
isError: !!props.errorMessage,
|
|
||||||
errorMessage:
|
|
||||||
typeof props.errorMessage === 'string'
|
|
||||||
? props.errorMessage
|
|
||||||
: props.errorMessage instanceof Error ? props.errorMessage.toString() : '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
showError(text) {
|
|
||||||
this.setState({
|
|
||||||
isError: true,
|
|
||||||
errorMessage: text,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showRequiredError() {
|
|
||||||
this.showError(this._fieldRequiredText);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearError(text) {
|
|
||||||
this.setState({
|
|
||||||
isError: false,
|
|
||||||
errorMessage: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getValue() {
|
|
||||||
return this._field.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedElement() {
|
|
||||||
return this._field.getSelectedElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
getOptions() {
|
|
||||||
return this._field.getOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
this._field.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocus() {
|
|
||||||
this.setState({ isFocus: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onBlur() {
|
|
||||||
this.setState({ isFocus: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const fieldProps = Object.assign({}, this.props),
|
|
||||||
elementId = formFieldId(),
|
|
||||||
renderLabelInFormField = formFieldNestedLabelTypes.includes(this.props.type);
|
|
||||||
|
|
||||||
if (!renderLabelInFormField) {
|
|
||||||
delete fieldProps.label;
|
|
||||||
}
|
|
||||||
delete fieldProps.helper;
|
|
||||||
delete fieldProps.errorMessage;
|
|
||||||
delete fieldProps.isFocus;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`form-row${this.state.isFocus ? ' form-row--focus' : ''}`}>
|
|
||||||
{this.props.label && !renderLabelInFormField ? (
|
|
||||||
<div
|
|
||||||
className={`form-row__label-row ${
|
|
||||||
this.props.labelPrefix ? 'form-row__label-row--prefix' : ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
htmlFor={elementId}
|
|
||||||
className={`form-field__label ${
|
|
||||||
this.state.isError ? 'form-field__label--error' : ' '
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{this.props.label}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
<FormField
|
|
||||||
ref={ref => {
|
|
||||||
this._field = ref ? ref.getWrappedInstance() : null;
|
|
||||||
}}
|
|
||||||
hasError={this.state.isError}
|
|
||||||
onFocus={this.onFocus.bind(this)}
|
|
||||||
onBlur={this.onBlur.bind(this)}
|
|
||||||
{...fieldProps}
|
|
||||||
/>
|
|
||||||
{!this.state.isError && this.props.helper ? (
|
|
||||||
<div className="form-field__helper">{this.props.helper}</div>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
{this.state.isError ? (
|
|
||||||
<div className="form-field__error">{this.state.errorMessage}</div>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Submit = props => {
|
|
||||||
const { title, label, icon, disabled } = props;
|
|
||||||
|
|
||||||
const className = `${'button-block' +
|
|
||||||
' button-primary' +
|
|
||||||
' button-set-item' +
|
|
||||||
' button--submit'}${disabled ? ' disabled' : ''}`;
|
|
||||||
|
|
||||||
const content = (
|
|
||||||
<span className="button__content">
|
|
||||||
{'icon' in props ? <Icon icon={icon} fixed /> : null}
|
|
||||||
{label ? <span className="button-label">{label}</span> : null}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button type="submit" className={className} title={title}>
|
|
||||||
{content}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
// This file is going to die
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import FileSelector from 'component/file-selector.js';
|
import FileSelector from 'component/file-selector.js';
|
||||||
import SimpleMDE from 'react-simplemde-editor';
|
import SimpleMDE from 'react-simplemde-editor';
|
||||||
import { formFieldNestedLabelTypes, formFieldId } from '../form';
|
import { formFieldNestedLabelTypes, formFieldId } from 'component/common/form';
|
||||||
import style from 'react-simplemde-editor/dist/simplemde.min.css';
|
import style from 'react-simplemde-editor/dist/simplemde.min.css';
|
||||||
|
|
||||||
const formFieldFileSelectorTypes = ['file', 'directory'];
|
const formFieldFileSelectorTypes = ['file', 'directory'];
|
||||||
|
@ -195,3 +197,4 @@ class FormField extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FormField;
|
export default FormField;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
import React from 'react';
|
|
||||||
import { formatCredits } from 'util/formatCredits';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectIsBackDisabled, selectIsForwardDisabled } from 'redux/selectors/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectBalance } from 'redux/selectors/wallet';
|
|
||||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
|
||||||
import Header from './view';
|
|
||||||
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
||||||
import { doDownloadUpgrade } from 'redux/actions/app';
|
import { formatCredits } from 'util/formatCredits';
|
||||||
|
import { selectBalance } from 'redux/selectors/wallet';
|
||||||
|
import Header from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
isBackDisabled: selectIsBackDisabled(state),
|
|
||||||
isForwardDisabled: selectIsForwardDisabled(state),
|
|
||||||
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
||||||
balance: formatCredits(selectBalance(state) || 0, 2),
|
balance: formatCredits(selectBalance(state) || 0, 2),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
back: () => dispatch(doHistoryBack()),
|
|
||||||
forward: () => dispatch(doHistoryForward()),
|
|
||||||
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(Header);
|
export default connect(select, perform)(Header);
|
||||||
|
|
|
@ -5,78 +5,34 @@ import WunderBar from 'component/wunderbar';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
balance: string,
|
balance: string,
|
||||||
back: any => void,
|
|
||||||
forward: any => void,
|
|
||||||
isBackDisabled: boolean,
|
|
||||||
isForwardDisabled: boolean,
|
|
||||||
isUpgradeAvailable: boolean,
|
|
||||||
navigate: any => void,
|
navigate: any => void,
|
||||||
downloadUpgrade: any => void,
|
downloadUpgrade: any => void,
|
||||||
|
isUpgradeAvailable: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Header = (props: Props) => {
|
const Header = (props: Props) => {
|
||||||
const {
|
const { balance, isUpgradeAvailable, navigate, downloadUpgrade } = props;
|
||||||
balance,
|
|
||||||
back,
|
|
||||||
forward,
|
|
||||||
isBackDisabled,
|
|
||||||
isForwardDisabled,
|
|
||||||
isUpgradeAvailable,
|
|
||||||
navigate,
|
|
||||||
downloadUpgrade,
|
|
||||||
} = props;
|
|
||||||
return (
|
return (
|
||||||
<header id="header">
|
<header className="header">
|
||||||
<div className="header__actions-left">
|
|
||||||
<Button
|
|
||||||
alt
|
|
||||||
circle
|
|
||||||
onClick={back}
|
|
||||||
disabled={isBackDisabled}
|
|
||||||
icon="arrow-left"
|
|
||||||
description={__('Navigate back')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
alt
|
|
||||||
circle
|
|
||||||
onClick={forward}
|
|
||||||
disabled={isForwardDisabled}
|
|
||||||
icon="arrow-right"
|
|
||||||
description={__('Navigate forward')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button alt onClick={() => navigate('/discover')} icon="home" description={__('Home')} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<WunderBar />
|
<WunderBar />
|
||||||
|
|
||||||
<div className="header__actions-right">
|
<div className="header__actions-right">
|
||||||
<Button
|
<Button
|
||||||
inverse
|
inverse
|
||||||
onClick={() => navigate('/wallet')}
|
onClick={() => navigate('/wallet')}
|
||||||
icon="user"
|
icon="User"
|
||||||
label={isUpgradeAvailable ? `${balance} LBC` : `You have ${balance} LBC`}
|
label={isUpgradeAvailable ? `${balance} LBC` : `You have ${balance} LBC`}
|
||||||
description={__('Your wallet')}
|
description={__('Your wallet')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => navigate('/publish')}
|
onClick={() => navigate('/publish')}
|
||||||
icon="cloud-upload"
|
icon="UploadCloud"
|
||||||
label={isUpgradeAvailable ? '' : __('Publish')}
|
label={isUpgradeAvailable ? '' : __('Publish')}
|
||||||
description={__('Publish content')}
|
description={__('Publish content')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
|
||||||
alt
|
|
||||||
onClick={() => navigate('/settings')}
|
|
||||||
icon="gear"
|
|
||||||
description={__('Settings')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button alt onClick={() => navigate('/help')} icon="question" description={__('Help')} />
|
|
||||||
{isUpgradeAvailable && (
|
{isUpgradeAvailable && (
|
||||||
<Button onClick={() => downloadUpgrade()} icon="arrow-up" label={__('Upgrade App')} />
|
<Button onClick={() => downloadUpgrade()} icon="Download" label={__('Upgrade App')} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BusyMessage, CreditAmount } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
|
// import { Form, FormField } from 'component/common/form';
|
||||||
|
|
||||||
class FormInviteNew extends React.PureComponent {
|
class FormInviteNew extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -24,25 +27,25 @@ class FormInviteNew extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { errorMessage, isPending } = this.props;
|
const { errorMessage, isPending } = this.props;
|
||||||
|
return null;
|
||||||
return (
|
// return (
|
||||||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
// <Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
<FormRow
|
// <FormRow
|
||||||
type="text"
|
// type="text"
|
||||||
label="Email"
|
// label="Email"
|
||||||
placeholder="youremail@example.org"
|
// placeholder="youremail@example.org"
|
||||||
name="email"
|
// name="email"
|
||||||
value={this.state.email}
|
// value={this.state.email}
|
||||||
errorMessage={errorMessage}
|
// errorMessage={errorMessage}
|
||||||
onChange={event => {
|
// onChange={event => {
|
||||||
this.handleEmailChanged(event);
|
// this.handleEmailChanged(event);
|
||||||
}}
|
// }}
|
||||||
/>
|
// />
|
||||||
<div className="form-row-submit">
|
// <div className="form-row-submit">
|
||||||
<Submit label={__('Send Invite')} disabled={isPending} />
|
// <Submit label={__('Send Invite')} disabled={isPending} />
|
||||||
</div>
|
// </div>
|
||||||
</Form>
|
// </Form>
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,3 +83,4 @@ class InviteNew extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default InviteNew;
|
export default InviteNew;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -22,6 +22,8 @@ type Props = {
|
||||||
alt: ?boolean,
|
alt: ?boolean,
|
||||||
flat: ?boolean,
|
flat: ?boolean,
|
||||||
fakeLink: ?boolean,
|
fakeLink: ?boolean,
|
||||||
|
noStyle: ?boolean,
|
||||||
|
noUnderline: ?boolean,
|
||||||
description: ?string,
|
description: ?string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,19 +47,24 @@ const Button = (props: Props) => {
|
||||||
flat,
|
flat,
|
||||||
fakeLink,
|
fakeLink,
|
||||||
description,
|
description,
|
||||||
|
noStyle,
|
||||||
|
noUnderline,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const combinedClassName = classnames(
|
const combinedClassName = classnames(
|
||||||
{
|
'btn',
|
||||||
btn: !fakeLink,
|
noStyle
|
||||||
|
? 'btn--no-style'
|
||||||
|
: {
|
||||||
'btn--link': fakeLink,
|
'btn--link': fakeLink,
|
||||||
'btn--primary': !fakeLink && !alt,
|
'btn--primary': !alt && !fakeLink,
|
||||||
'btn--alt': alt,
|
'btn--alt': alt,
|
||||||
'btn--inverse': inverse,
|
'btn--inverse': inverse,
|
||||||
'btn--disabled': disabled,
|
'btn--disabled': disabled,
|
||||||
'btn--circle': circle,
|
'btn--circle': circle,
|
||||||
'btn--flat': flat,
|
'btn--flat': flat,
|
||||||
|
'btn--no-underline': fakeLink && noUnderline,
|
||||||
},
|
},
|
||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
@ -72,10 +79,10 @@ const Button = (props: Props) => {
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{icon && <Icon icon={icon} fixed />}
|
{icon && <Icon icon={icon} />}
|
||||||
{label && <span className="btn__label">{label}</span>}
|
{label && <span className="btn__label">{label}</span>}
|
||||||
{children && children}
|
{children && children}
|
||||||
{iconRight && <Icon icon={iconRight} fixed />}
|
{iconRight && <Icon icon={iconRight} />}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Icon from 'component/common/icon';
|
|
||||||
import Link from 'component/link';
|
|
||||||
|
|
||||||
export class DropDownMenuItem extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
href: PropTypes.string,
|
|
||||||
label: PropTypes.string,
|
|
||||||
icon: PropTypes.string,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
iconPosition: 'left',
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const icon = this.props.icon ? <Icon icon={this.props.icon} fixed /> : null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
className="menu__menu-item"
|
|
||||||
onClick={this.props.onClick}
|
|
||||||
href={this.props.href || 'javascript:'}
|
|
||||||
label={this.props.label}
|
|
||||||
>
|
|
||||||
{this.props.iconPosition == 'left' ? icon : null}
|
|
||||||
{this.props.label}
|
|
||||||
{this.props.iconPosition == 'left' ? null : icon}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DropDownMenu extends React.PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._isWindowClickBound = false;
|
|
||||||
this._menuDiv = null;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
menuOpen: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this._isWindowClickBound) {
|
|
||||||
window.removeEventListener('click', this.handleWindowClick, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMenuIconClick(e) {
|
|
||||||
this.setState({
|
|
||||||
menuOpen: !this.state.menuOpen,
|
|
||||||
});
|
|
||||||
if (!this.state.menuOpen && !this._isWindowClickBound) {
|
|
||||||
this._isWindowClickBound = true;
|
|
||||||
window.addEventListener('click', this.handleWindowClick, false);
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMenuClick(e) {
|
|
||||||
// Event bubbles up to the menu after a link is clicked
|
|
||||||
this.setState({
|
|
||||||
menuOpen: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this will force "this" to always be the class, even when passed to an event listener */
|
|
||||||
handleWindowClick = e => {
|
|
||||||
if (this.state.menuOpen && (!this._menuDiv || !this._menuDiv.contains(e.target))) {
|
|
||||||
this.setState({
|
|
||||||
menuOpen: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.state.menuOpen && this._isWindowClickBound) {
|
|
||||||
this._isWindowClickBound = false;
|
|
||||||
window.removeEventListener('click', this.handleWindowClick, false);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="menu-container">
|
|
||||||
<Link
|
|
||||||
ref={span => (this._menuButton = span)}
|
|
||||||
button="text"
|
|
||||||
icon="icon-ellipsis-v"
|
|
||||||
onClick={event => {
|
|
||||||
this.handleMenuIconClick(event);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{this.state.menuOpen ? (
|
|
||||||
<div
|
|
||||||
ref={div => (this._menuDiv = div)}
|
|
||||||
className="menu"
|
|
||||||
onClick={event => {
|
|
||||||
this.handleMenuClick(event);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,31 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectPageTitle } from 'redux/selectors/navigation';
|
import {
|
||||||
|
selectPageTitle,
|
||||||
|
selectIsBackDisabled,
|
||||||
|
selectIsForwardDisabled,
|
||||||
|
selectNavLinks,
|
||||||
|
} from 'redux/selectors/navigation';
|
||||||
|
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||||
|
import { doDownloadUpgrade } from 'redux/actions/app';
|
||||||
|
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
||||||
|
import { formatCredits } from 'util/formatCredits';
|
||||||
|
import { selectBalance } from 'redux/selectors/wallet';
|
||||||
import Page from './view';
|
import Page from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
title: selectPageTitle(state),
|
pageTitle: selectPageTitle(state),
|
||||||
|
navLinks: selectNavLinks(state),
|
||||||
|
isBackDisabled: selectIsBackDisabled(state),
|
||||||
|
isForwardDisabled: selectIsForwardDisabled(state),
|
||||||
|
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
||||||
|
balance: formatCredits(selectBalance(state) || 0, 2),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, null)(Page);
|
const perform = dispatch => ({
|
||||||
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
|
back: () => dispatch(doHistoryBack()),
|
||||||
|
forward: () => dispatch(doHistoryForward()),
|
||||||
|
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(Page);
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { BusyMessage } from 'component/common';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.Node,
|
children: React.Node,
|
||||||
title: ?string,
|
pageTitle: ?string,
|
||||||
noPadding: ?boolean,
|
noPadding: ?boolean,
|
||||||
isLoading: ?boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Page = (props: Props) => {
|
const Page = (props: Props) => {
|
||||||
const { children, title, noPadding, isLoading } = props;
|
const { pageTitle, children, noPadding } = props;
|
||||||
return (
|
return (
|
||||||
<main id="main-content">
|
<main className={classnames('main', { 'main--no-padding': noPadding })}>
|
||||||
|
{pageTitle && (
|
||||||
<div className="page__header">
|
<div className="page__header">
|
||||||
{title && <h1 className="page__title">{title}</h1>}
|
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
|
||||||
{isLoading && <BusyMessage message={__('Fetching content')} />}
|
|
||||||
</div>
|
</div>
|
||||||
<div className={classnames('main', { 'main--no-padding': noPadding })}>{children}</div>
|
)}
|
||||||
|
{children}
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { isNameValid } from 'lbryURI';
|
import { isNameValid } from 'lbryURI';
|
||||||
import { FormRow } from 'component/form.js';
|
import { FormRow } from 'component/common/form';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
|
|
||||||
|
@ -167,3 +169,4 @@ class ChannelSection extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ChannelSection;
|
export default ChannelSection;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import lbry from 'lbry';
|
import lbry from 'lbry';
|
||||||
import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI';
|
import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI';
|
||||||
import FormField from 'component/formField';
|
import FormField from 'component/formField';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import { Form, FormRow } from 'component/common/form';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import FormFieldPrice from 'component/formFieldPrice';
|
import FormFieldPrice from 'component/formFieldPrice';
|
||||||
import Modal from 'modal/modal';
|
import Modal from 'modal/modal';
|
||||||
|
@ -832,7 +834,8 @@ class PublishForm extends React.PureComponent {
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div className="card-series-submit">
|
<div className="card-series-submit">
|
||||||
<Submit
|
<Link
|
||||||
|
type="submit"
|
||||||
label={!this.state.submitting ? __('Publish') : __('Publishing...')}
|
label={!this.state.submitting ? __('Publish') : __('Publishing...')}
|
||||||
disabled={
|
disabled={
|
||||||
this.props.balance <= 0 ||
|
this.props.balance <= 0 ||
|
||||||
|
@ -878,3 +881,4 @@ class PublishForm extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PublishForm;
|
export default PublishForm;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LinkTransaction from 'component/linkTransaction';
|
import LinkTransaction from 'component/linkTransaction';
|
||||||
|
|
||||||
const RewardListClaimed = props => {
|
type Reward = {
|
||||||
|
id: string,
|
||||||
|
reward_title: string,
|
||||||
|
reward_amount: number,
|
||||||
|
transaction_id: string,
|
||||||
|
created_at: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
rewards: Array<Reward>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RewardListClaimed = (props: Props) => {
|
||||||
const { rewards } = props;
|
const { rewards } = props;
|
||||||
|
|
||||||
if (!rewards || !rewards.length) {
|
if (!rewards || !rewards.length) {
|
||||||
|
@ -9,7 +22,7 @@ const RewardListClaimed = props => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-identity">
|
<div className="card__title-identity">
|
||||||
<h3>Claimed Rewards</h3>
|
<h3>Claimed Rewards</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
import Link from 'component/link';
|
import Button from 'component/link';
|
||||||
import { CreditAmount } from 'component/common';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
unclaimedRewardAmount: number,
|
unclaimedRewardAmount: number,
|
||||||
|
@ -9,24 +9,25 @@ type Props = {
|
||||||
|
|
||||||
const RewardSummary = (props: Props) => {
|
const RewardSummary = (props: Props) => {
|
||||||
const { unclaimedRewardAmount } = props;
|
const { unclaimedRewardAmount } = props;
|
||||||
|
const hasRewards = unclaimedRewardAmount > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<h2>{__('Rewards')}</h2>
|
||||||
<h3>{__('Rewards')}</h3>
|
<p className="card__subtitle">
|
||||||
</div>
|
{hasRewards ? (
|
||||||
<div className="card__content">
|
<React.Fragment>
|
||||||
{unclaimedRewardAmount > 0 ? (
|
|
||||||
<p>
|
|
||||||
{__('You have')} <CreditAmount amount={unclaimedRewardAmount} precision={8} />{' '}
|
{__('You have')} <CreditAmount amount={unclaimedRewardAmount} precision={8} />{' '}
|
||||||
{__('in unclaimed rewards')}.
|
{__('in unclaimed rewards')}.
|
||||||
</p>
|
</React.Fragment>
|
||||||
) : (
|
) : (
|
||||||
<p>{__('There are no rewards available at this time, please check back later')}.</p>
|
<React.Fragment>
|
||||||
|
{__('There are no rewards available at this time, please check back later')}.
|
||||||
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</p>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
<Link button="primary" navigate="/rewards" label={__('Claim Rewards')} />
|
<Button navigate="/rewards" label={hasRewards ? __('Claim Rewards') : __('View Rewards')} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,16 +1,30 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CreditAmount, Icon } from 'component/common';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
|
import Icon from 'component/common/icon';
|
||||||
import RewardLink from 'component/rewardLink';
|
import RewardLink from 'component/rewardLink';
|
||||||
import Link from 'component/link';
|
import Button from 'component/link';
|
||||||
import rewards from 'rewards';
|
import rewards from 'rewards';
|
||||||
|
|
||||||
const RewardTile = props => {
|
type Props = {
|
||||||
|
reward: {
|
||||||
|
id: string,
|
||||||
|
reward_title: string,
|
||||||
|
reward_amount: number,
|
||||||
|
transaction_id: string,
|
||||||
|
created_at: string,
|
||||||
|
reward_description: string,
|
||||||
|
reward_type: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const RewardTile = (props: Props) => {
|
||||||
const { reward } = props;
|
const { reward } = props;
|
||||||
|
|
||||||
const claimed = !!reward.transaction_id;
|
const claimed = !!reward.transaction_id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__inner">
|
<div className="card__inner">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<CreditAmount amount={reward.reward_amount} />
|
<CreditAmount amount={reward.reward_amount} />
|
||||||
|
@ -18,8 +32,8 @@ const RewardTile = props => {
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">{reward.reward_description}</div>
|
<div className="card__content">{reward.reward_description}</div>
|
||||||
<div className="card__actions ">
|
<div className="card__actions ">
|
||||||
{reward.reward_type == rewards.TYPE_REFERRAL && (
|
{reward.reward_type === rewards.TYPE_REFERRAL && (
|
||||||
<Link button="alt" navigate="/invite" label={__('Go To Invites')} />
|
<Button alt navigate="/invite" label={__('Go To Invites')} />
|
||||||
)}
|
)}
|
||||||
{reward.reward_type !== rewards.TYPE_REFERRAL &&
|
{reward.reward_type !== rewards.TYPE_REFERRAL &&
|
||||||
(claimed ? (
|
(claimed ? (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
|
||||||
import { getExampleAddress } from 'util/shape_shift';
|
import { getExampleAddress } from 'util/shape_shift';
|
||||||
import { Submit, FormRow } from 'component/form';
|
import { FormField, Submit } from 'component/common/form';
|
||||||
import type { ShapeShiftFormValues, Dispatch } from 'redux/actions/shape_shift';
|
import type { ShapeShiftFormValues, Dispatch } from 'redux/actions/shape_shift';
|
||||||
import ShiftMarketInfo from './market_info';
|
import ShiftMarketInfo from './market_info';
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ type ShapeShiftFormErrors = {
|
||||||
type Props = {
|
type Props = {
|
||||||
values: ShapeShiftFormValues,
|
values: ShapeShiftFormValues,
|
||||||
errors: ShapeShiftFormErrors,
|
errors: ShapeShiftFormErrors,
|
||||||
touched: boolean,
|
touched: { returnAddress: boolean },
|
||||||
handleChange: Event => any,
|
handleChange: Event => any,
|
||||||
handleBlur: Event => any,
|
handleBlur: Event => any,
|
||||||
handleSubmit: Event => any,
|
handleSubmit: Event => any,
|
||||||
|
@ -21,7 +21,6 @@ type Props = {
|
||||||
originCoin: string,
|
originCoin: string,
|
||||||
updating: boolean,
|
updating: boolean,
|
||||||
getCoinStats: Dispatch,
|
getCoinStats: Dispatch,
|
||||||
receiveAddress: string,
|
|
||||||
originCoinDepositFee: number,
|
originCoinDepositFee: number,
|
||||||
originCoinDepositMin: string,
|
originCoinDepositMin: string,
|
||||||
originCoinDepositMax: number,
|
originCoinDepositMax: number,
|
||||||
|
@ -41,7 +40,6 @@ export default (props: Props) => {
|
||||||
originCoin,
|
originCoin,
|
||||||
updating,
|
updating,
|
||||||
getCoinStats,
|
getCoinStats,
|
||||||
receiveAddress,
|
|
||||||
originCoinDepositMax,
|
originCoinDepositMax,
|
||||||
originCoinDepositMin,
|
originCoinDepositMin,
|
||||||
originCoinDepositFee,
|
originCoinDepositFee,
|
||||||
|
@ -49,8 +47,10 @@ export default (props: Props) => {
|
||||||
} = props;
|
} = props;
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="form-field">
|
<FormField
|
||||||
<span>{__('Exchange')} </span>
|
prefix={__('Exchange')}
|
||||||
|
postfix={__('for LBC')}
|
||||||
|
render={() => (
|
||||||
<select
|
<select
|
||||||
className="form-field__input form-field__input-select"
|
className="form-field__input form-field__input-select"
|
||||||
name="originCoin"
|
name="originCoin"
|
||||||
|
@ -65,7 +65,9 @@ export default (props: Props) => {
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<span> {__('for LBC')}</span>
|
)}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
<div className="shapeshift__tx-info">
|
<div className="shapeshift__tx-info">
|
||||||
{!updating &&
|
{!updating &&
|
||||||
originCoinDepositMax && (
|
originCoinDepositMax && (
|
||||||
|
@ -80,16 +82,19 @@ export default (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormRow
|
<FormField
|
||||||
|
label={__('Return address')}
|
||||||
|
error={touched.returnAddress && !!errors.returnAddress && errors.returnAddress}
|
||||||
|
render={() => (
|
||||||
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="returnAddress"
|
name="returnAddress"
|
||||||
placeholder={getExampleAddress(originCoin)}
|
placeholder={getExampleAddress(originCoin)}
|
||||||
label={__('Return address')}
|
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
value={values.returnAddress}
|
value={values.returnAddress}
|
||||||
errorMessage={errors.returnAddress}
|
/>
|
||||||
hasError={touched.returnAddress && !!errors.returnAddress}
|
)}
|
||||||
/>
|
/>
|
||||||
<span className="help">
|
<span className="help">
|
||||||
<span>
|
<span>
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { shell } from 'electron';
|
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import classnames from 'classnames';
|
|
||||||
import * as statuses from 'constants/shape_shift';
|
|
||||||
import { validateShapeShiftForm } from 'util/shape_shift';
|
import { validateShapeShiftForm } from 'util/shape_shift';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import Spinner from 'component/common/spinner';
|
|
||||||
import { BusyMessage } from 'component/common';
|
|
||||||
import ShapeShiftForm from './internal/form';
|
|
||||||
import ActiveShapeShift from './internal/active-shift';
|
|
||||||
|
|
||||||
import type { ShapeShiftState } from 'redux/reducers/shape_shift';
|
import type { ShapeShiftState } from 'redux/reducers/shape_shift';
|
||||||
import type { Dispatch, ShapeShiftFormValues } from 'redux/actions/shape_shift';
|
import type { Dispatch, ShapeShiftFormValues } from 'redux/actions/shape_shift';
|
||||||
|
import ShapeShiftForm from './internal/form';
|
||||||
|
import ActiveShapeShift from './internal/active-shift';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shapeShift: ShapeShiftState,
|
shapeShift: ShapeShiftState,
|
||||||
|
@ -72,28 +66,17 @@ class ShapeShift extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// add the "shapeshift__intital-wrapper class so we can avoid content jumping once everything loads"
|
<section className="card card--section">
|
||||||
// it just gives the section a min-height equal to the height of the content when the form is rendered
|
<h2>{__('Convert Crypto to LBC')}</h2>
|
||||||
// if the markup below changes for the initial render (form.jsx) there will be content jumping
|
<p className="card__subtitle">
|
||||||
// the styling in shapeshift.scss will need to be updated to the correct min-height
|
|
||||||
<section
|
|
||||||
className={classnames('card shapeshift__wrapper', {
|
|
||||||
'shapeshift__initial-wrapper': loading,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<div className="card__title-primary">
|
|
||||||
<h3>{__('Convert Crypto to LBC')}</h3>
|
|
||||||
<p className="help">
|
|
||||||
{__('Powered by ShapeShift. Read our FAQ')}{' '}
|
{__('Powered by ShapeShift. Read our FAQ')}{' '}
|
||||||
<Link href="https://lbry.io/faq/shapeshift">{__('here')}</Link>.
|
<Link fakeLink label={__('here')} href="https://lbry.io/faq/shapeshift" />.
|
||||||
{hasActiveShift &&
|
{hasActiveShift &&
|
||||||
shiftState !== 'complete' && <span>{__('This will update automatically.')}</span>}
|
shiftState !== 'complete' && <span>{__('This will update automatically.')}</span>}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="card__content shapeshift__content">
|
<div className="card__content shapeshift__content">
|
||||||
{error && <div className="form-field__error">{error}</div>}
|
{error && <div className="form-field__error">{error}</div>}
|
||||||
{loading && <Spinner dark />}
|
|
||||||
{!loading &&
|
{!loading &&
|
||||||
!hasActiveShift &&
|
!hasActiveShift &&
|
||||||
!!shiftSupportedCoins.length && (
|
!!shiftSupportedCoins.length && (
|
||||||
|
@ -113,7 +96,6 @@ class ShapeShift extends React.PureComponent<Props> {
|
||||||
originCoinDepositMin={originCoinDepositMin}
|
originCoinDepositMin={originCoinDepositMin}
|
||||||
originCoinDepositFee={originCoinDepositFee}
|
originCoinDepositFee={originCoinDepositFee}
|
||||||
shapeShiftRate={shapeShiftRate}
|
shapeShiftRate={shapeShiftRate}
|
||||||
updating={updating}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -124,7 +106,6 @@ class ShapeShift extends React.PureComponent<Props> {
|
||||||
shiftCoinType={shiftCoinType}
|
shiftCoinType={shiftCoinType}
|
||||||
shiftReturnAddress={shiftReturnAddress}
|
shiftReturnAddress={shiftReturnAddress}
|
||||||
shiftDepositAddress={shiftDepositAddress}
|
shiftDepositAddress={shiftDepositAddress}
|
||||||
originCoinDepositMax={originCoinDepositMax}
|
|
||||||
shiftOrderId={shiftOrderId}
|
shiftOrderId={shiftOrderId}
|
||||||
shiftState={shiftState}
|
shiftState={shiftState}
|
||||||
clearShapeShift={clearShapeShift}
|
clearShapeShift={clearShapeShift}
|
||||||
|
|
24
src/renderer/component/sideBar/index.js
Normal file
24
src/renderer/component/sideBar/index.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||||
|
import {
|
||||||
|
selectIsBackDisabled,
|
||||||
|
selectIsForwardDisabled,
|
||||||
|
selectIsHome,
|
||||||
|
selectNavLinks,
|
||||||
|
} from 'redux/selectors/navigation';
|
||||||
|
import SideBar from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
navLinks: selectNavLinks(state),
|
||||||
|
isBackDisabled: selectIsBackDisabled(state),
|
||||||
|
isForwardDisabled: selectIsForwardDisabled(state),
|
||||||
|
isHome: selectIsHome(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
|
back: () => dispatch(doHistoryBack()),
|
||||||
|
forward: () => dispatch(doHistoryForward()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(SideBar);
|
101
src/renderer/component/sideBar/view.jsx
Normal file
101
src/renderer/component/sideBar/view.jsx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import Button from 'component/link';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
type SideBarLink = {
|
||||||
|
label: string,
|
||||||
|
path: string,
|
||||||
|
active: boolean,
|
||||||
|
icon: ?string,
|
||||||
|
subLinks: Array<SideBarLink>,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigate: any => void,
|
||||||
|
back: any => void,
|
||||||
|
forward: any => void,
|
||||||
|
isBackDisabled: boolean,
|
||||||
|
isForwardDisabled: boolean,
|
||||||
|
isHome: boolean,
|
||||||
|
navLinks: {
|
||||||
|
primary: Array<SideBarLink>,
|
||||||
|
secondary: Array<SideBarLink>,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const SideBar = (props: Props) => {
|
||||||
|
const { navigate, back, forward, isBackDisabled, isForwardDisabled, isHome, navLinks } = props;
|
||||||
|
return (
|
||||||
|
<nav className="nav">
|
||||||
|
<div className="nav__actions-top">
|
||||||
|
<Button
|
||||||
|
alt
|
||||||
|
icon="Home"
|
||||||
|
description={__('Home')}
|
||||||
|
onClick={() => navigate('/discover')}
|
||||||
|
disabled={isHome}
|
||||||
|
/>
|
||||||
|
<div className="nav__actions-history">
|
||||||
|
<Button
|
||||||
|
alt
|
||||||
|
icon="ArrowLeft"
|
||||||
|
description={__('Navigate back')}
|
||||||
|
onClick={back}
|
||||||
|
disabled={isBackDisabled}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
alt
|
||||||
|
icon="ArrowRight"
|
||||||
|
description={__('Navigate forward')}
|
||||||
|
onClick={forward}
|
||||||
|
disabled={isForwardDisabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="nav__links">
|
||||||
|
<ul className="nav__primary">
|
||||||
|
{navLinks.primary.map(({ label, path, active, icon }) => (
|
||||||
|
<li
|
||||||
|
key={path}
|
||||||
|
className={classnames('nav__link nav__primary-link', { 'nav__link--active': active })}
|
||||||
|
>
|
||||||
|
<Button noStyle navigate={path} label={label} icon={icon} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<hr />
|
||||||
|
<ul className="nav__secondary">
|
||||||
|
{navLinks.secondary.map(({ label, path, active, icon, subLinks = [] }) => (
|
||||||
|
<li
|
||||||
|
key={path}
|
||||||
|
className={classnames('nav__link nav__secondary-link', {
|
||||||
|
'nav__link--active': active && !subLinks.length,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button noStyle navigate={path} label={label} icon={icon} />
|
||||||
|
{!!subLinks.length &&
|
||||||
|
active && (
|
||||||
|
<ul className="nav__sub">
|
||||||
|
{subLinks.map(({ label: subLabel, path: subPath, active: subLinkActive }) => (
|
||||||
|
<li
|
||||||
|
key={subPath}
|
||||||
|
className={classnames('nav__link nav__sub-link', {
|
||||||
|
'nav__link--active': subLinkActive,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button noStyle navigate={subPath} label={subLabel} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SideBar;
|
|
@ -1,16 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { selectCurrentPage, selectHeaderLinks } from 'redux/selectors/navigation';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
|
||||||
import SubHeader from './view';
|
|
||||||
|
|
||||||
const select = (state, props) => ({
|
|
||||||
currentPage: selectCurrentPage(state),
|
|
||||||
subLinks: selectHeaderLinks(state),
|
|
||||||
});
|
|
||||||
|
|
||||||
const perform = dispatch => ({
|
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(select, perform)(SubHeader);
|
|
|
@ -1,34 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import Link from 'component/link';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
const SubHeader = props => {
|
|
||||||
const { subLinks, currentPage, navigate, fullWidth, smallMargin } = props;
|
|
||||||
|
|
||||||
const links = [];
|
|
||||||
|
|
||||||
for (const link of Object.keys(subLinks)) {
|
|
||||||
links.push(
|
|
||||||
<Link
|
|
||||||
onClick={event => navigate(`/${link}`, event)}
|
|
||||||
key={link}
|
|
||||||
className={link == currentPage ? 'sub-header-selected' : 'sub-header-unselected'}
|
|
||||||
>
|
|
||||||
{subLinks[link]}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav
|
|
||||||
className={classnames('sub-header', {
|
|
||||||
'sub-header--full-width': fullWidth,
|
|
||||||
'sub-header--small-margin': smallMargin,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{links}
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SubHeader;
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LinkTransaction from 'component/linkTransaction';
|
import LinkTransaction from 'component/linkTransaction';
|
||||||
import { CreditAmount } from 'component/common';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
import DateTime from 'component/dateTime';
|
import DateTime from 'component/dateTime';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import { buildURI } from 'lbryURI';
|
import { buildURI } from 'lbryURI';
|
||||||
|
@ -89,3 +91,4 @@ class TransactionListItem extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TransactionListItem;
|
export default TransactionListItem;
|
||||||
|
/* eslint-disable */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import TransactionListItem from './internal/TransactionListItem';
|
import TransactionListItem from './internal/TransactionListItem';
|
||||||
import FormField from 'component/formField';
|
import { FormRow } from 'component/common/form';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import * as modals from 'constants/modal_types';
|
import * as modals from 'constants/modal_types';
|
||||||
|
@ -44,9 +46,13 @@ class TransactionList extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{(transactionList.length || this.state.filter) && (
|
{(transactionList.length || this.state.filter) && (
|
||||||
<span className="sort-section">
|
<FormRow
|
||||||
{__('Filter')}{' '}
|
prefix={__('Filter')}
|
||||||
<FormField type="select" onChange={this.handleFilterChanged.bind(this)}>
|
postfix={
|
||||||
|
<Link fakeLink href="https://lbry.io/faq/transaction-types" label={__('Help')} />
|
||||||
|
}
|
||||||
|
render={() => (
|
||||||
|
<select>
|
||||||
<option value="">{__('All')}</option>
|
<option value="">{__('All')}</option>
|
||||||
<option value="spend">{__('Spends')}</option>
|
<option value="spend">{__('Spends')}</option>
|
||||||
<option value="receive">{__('Receives')}</option>
|
<option value="receive">{__('Receives')}</option>
|
||||||
|
@ -55,9 +61,9 @@ class TransactionList extends React.PureComponent {
|
||||||
<option value="tip">{__('Tips')}</option>
|
<option value="tip">{__('Tips')}</option>
|
||||||
<option value="support">{__('Supports')}</option>
|
<option value="support">{__('Supports')}</option>
|
||||||
<option value="update">{__('Updates')}</option>
|
<option value="update">{__('Updates')}</option>
|
||||||
</FormField>{' '}
|
</select>
|
||||||
<Link href="https://lbry.io/faq/transaction-types" icon={icons.HELP_CIRCLE} />
|
)}
|
||||||
</span>
|
/>
|
||||||
)}
|
)}
|
||||||
{!transactionList.length && (
|
{!transactionList.length && (
|
||||||
<div className="empty">{emptyMessage || __('No transactions to list.')}</div>
|
<div className="empty">{emptyMessage || __('No transactions to list.')}</div>
|
||||||
|
@ -92,3 +98,4 @@ class TransactionList extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TransactionList;
|
export default TransactionList;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import Link from 'component/link';
|
import Button from 'component/link';
|
||||||
import TransactionList from 'component/transactionList';
|
import TransactionList from 'component/transactionList';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
class TransactionListRecent extends React.PureComponent {
|
type Props = {
|
||||||
|
fetchTransactions: () => void,
|
||||||
|
fetchingTransactions: boolean,
|
||||||
|
hasTransactions: boolean,
|
||||||
|
transactions: Array<{}>, // Will iron this out when I work on transactions page - Sean
|
||||||
|
};
|
||||||
|
|
||||||
|
class TransactionListRecent extends React.PureComponent<Props> {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.fetchTransactions();
|
this.props.fetchTransactions();
|
||||||
}
|
}
|
||||||
|
@ -13,28 +21,20 @@ class TransactionListRecent extends React.PureComponent {
|
||||||
const { fetchingTransactions, hasTransactions, transactions } = this.props;
|
const { fetchingTransactions, hasTransactions, transactions } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<h2>{__('Recent Transactions')}</h2>
|
||||||
<h3>{__('Recent Transactions')}</h3>
|
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
{fetchingTransactions && <BusyMessage message={__('Loading transactions')} />}
|
{fetchingTransactions && <BusyMessage message={__('Loading transactions')} />}
|
||||||
{!fetchingTransactions && (
|
{!fetchingTransactions && (
|
||||||
<TransactionList
|
<TransactionList
|
||||||
transactions={transactions}
|
transactions={transactions}
|
||||||
emptyMessage={__('You have no recent transactions.')}
|
emptyMessage={__("Looks like you don't have any recent transactions.")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{hasTransactions && (
|
{hasTransactions && (
|
||||||
<div className="card__actions card__actions--bottom">
|
<div className="card__actions">
|
||||||
<Link
|
<Button navigate="/history" label={__('Full History')} icon="Clock" />
|
||||||
navigate="/history"
|
|
||||||
label={__('Full History')}
|
|
||||||
icon={icons.HISTORY}
|
|
||||||
className="no-underline"
|
|
||||||
button="text"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import Button from 'component/link';
|
import Button from 'component/link';
|
||||||
import { buildURI } from 'lbryURI';
|
import { buildURI } from 'lbryURI';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'component/common/icon';
|
// import Icon from 'component/common/icon';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
|
@ -57,7 +57,8 @@ class UriIndicator extends React.PureComponent<Props> {
|
||||||
return <span>Anonymous</span>;
|
return <span>Anonymous</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon;
|
// I'll look at this when working on the file page
|
||||||
|
// let icon;
|
||||||
let channelLink;
|
let channelLink;
|
||||||
let modifier;
|
let modifier;
|
||||||
|
|
||||||
|
@ -65,8 +66,8 @@ class UriIndicator extends React.PureComponent<Props> {
|
||||||
modifier = 'valid';
|
modifier = 'valid';
|
||||||
channelLink = link ? buildURI({ channelName, claimId: channelClaimId }, false) : false;
|
channelLink = link ? buildURI({ channelName, claimId: channelClaimId }, false) : false;
|
||||||
} else {
|
} else {
|
||||||
icon = 'icon-times-circle';
|
// icon = 'icon-times-circle';
|
||||||
modifier = 'invalid';
|
// modifier = 'invalid';
|
||||||
}
|
}
|
||||||
|
|
||||||
// {!signatureIsValid ? (
|
// {!signatureIsValid ? (
|
||||||
|
@ -94,7 +95,7 @@ class UriIndicator extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button navigate="/show" navigateParams={{ uri: channelLink }} fakeLink>
|
<Button navigate="/show" navigateParams={{ uri: channelLink }} noStyle>
|
||||||
{inner}
|
{inner}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import { Form, FormRow, Submit } from 'component/common/form';
|
||||||
|
|
||||||
class UserEmailNew extends React.PureComponent {
|
class UserEmailNew extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -53,3 +55,4 @@ class UserEmailNew extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserEmailNew;
|
export default UserEmailNew;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import { Form, FormField, Submit } from 'component/common/form';
|
||||||
|
|
||||||
class UserEmailVerify extends React.PureComponent {
|
class UserEmailVerify extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -29,19 +31,22 @@ class UserEmailVerify extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { cancelButton, errorMessage, email, isPending } = this.props;
|
const { cancelButton, errorMessage, email, isPending } = this.props;
|
||||||
|
// <FormField
|
||||||
|
// label={__('Verification Code')}
|
||||||
|
// errorMessage={errorMessage}
|
||||||
|
// render{() => (
|
||||||
|
// <input
|
||||||
|
// name="code"
|
||||||
|
// value={this.state.code}
|
||||||
|
// onChange={event => {
|
||||||
|
// this.handleCodeChanged(event);
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
|
// )}
|
||||||
|
// />
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
<p>Please enter the verification code emailed to {email}.</p>
|
<p>Please enter the verification code emailed to {email}.</p>
|
||||||
<FormRow
|
|
||||||
type="text"
|
|
||||||
label={__('Verification Code')}
|
|
||||||
name="code"
|
|
||||||
value={this.state.code}
|
|
||||||
onChange={event => {
|
|
||||||
this.handleCodeChanged(event);
|
|
||||||
}}
|
|
||||||
errorMessage={errorMessage}
|
|
||||||
/>
|
|
||||||
{/* render help separately so it always shows */}
|
{/* render help separately so it always shows */}
|
||||||
<div className="form-field__helper">
|
<div className="form-field__helper">
|
||||||
<p>
|
<p>
|
||||||
|
@ -60,3 +65,4 @@ class UserEmailVerify extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserEmailVerify;
|
export default UserEmailVerify;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import { Form, FormRow, FormField } from 'component/common/form';
|
||||||
import FormField from 'component/formField';
|
|
||||||
|
|
||||||
const os = require('os').type();
|
const os = require('os').type();
|
||||||
const countryCodes = require('country-data')
|
const countryCodes = require('country-data')
|
||||||
|
@ -77,29 +78,36 @@ class UserPhoneNew extends React.PureComponent {
|
||||||
</p>
|
</p>
|
||||||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
<div className="form-row-phone">
|
<div className="form-row-phone">
|
||||||
<FormField type="select" onChange={this.handleSelect.bind(this)}>
|
<FormField
|
||||||
|
onChange={this.handleSelect.bind(this)}
|
||||||
|
render={() => (
|
||||||
|
<select>
|
||||||
{countryCodes.map((country, index) => (
|
{countryCodes.map((country, index) => (
|
||||||
<option key={index} value={country.countryCallingCode}>
|
<option key={index} value={country.countryCallingCode}>
|
||||||
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`}{' '}
|
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`}{' '}
|
||||||
{country.countryCallingCode}
|
{country.countryCallingCode}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</FormField>
|
</select>
|
||||||
<FormRow
|
)}
|
||||||
type="text"
|
/>
|
||||||
placeholder={this.state.country_code === '+1' ? '(555) 555-5555' : '5555555555'}
|
<FormField
|
||||||
name="phone"
|
|
||||||
value={this.state.phone}
|
|
||||||
errorMessage={phoneErrorMessage}
|
errorMessage={phoneErrorMessage}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
this.handleChanged(event);
|
this.handleChanged(event);
|
||||||
}}
|
}}
|
||||||
|
render={() => (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder={this.state.country_code === '+1' ? '(555) 555-5555' : '5555555555'}
|
||||||
|
name="phone"
|
||||||
|
value={this.state.phone}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row-submit">
|
|
||||||
<Submit label="Submit" disabled={isPending} />
|
<Submit label="Submit" disabled={isPending} />
|
||||||
{cancelButton}
|
{cancelButton}
|
||||||
</div>
|
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -107,3 +115,4 @@ class UserPhoneNew extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserPhoneNew;
|
export default UserPhoneNew;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import { Form, FormRow, Submit } from 'component/form.js';
|
import { Form, FormElement, Submit } from 'component/common/form';
|
||||||
|
|
||||||
class UserPhoneVerify extends React.PureComponent {
|
class UserPhoneVerify extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -33,21 +35,23 @@ class UserPhoneVerify extends React.PureComponent {
|
||||||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
`Please enter the verification code sent to +${countryCode}${
|
`Please enter the verification code sent to +${countryCode}${phone}. Didn't receive it? `
|
||||||
phone
|
|
||||||
}. Didn't receive it? `
|
|
||||||
)}
|
)}
|
||||||
<Link onClick={this.reset.bind(this)} label="Go back." />
|
<Link onClick={this.reset.bind(this)} label="Go back." />
|
||||||
</p>
|
</p>
|
||||||
<FormRow
|
<FormElement
|
||||||
type="text"
|
|
||||||
label={__('Verification Code')}
|
label={__('Verification Code')}
|
||||||
|
errorMessage={phoneErrorMessage}
|
||||||
|
render={() => (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
name="code"
|
name="code"
|
||||||
value={this.state.code}
|
value={this.state.code}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
this.handleCodeChanged(event);
|
this.handleCodeChanged(event);
|
||||||
}}
|
}}
|
||||||
errorMessage={phoneErrorMessage}
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
{/* render help separately so it always shows */}
|
{/* render help separately so it always shows */}
|
||||||
<div className="form-field__helper">
|
<div className="form-field__helper">
|
||||||
|
@ -67,3 +71,4 @@ class UserPhoneVerify extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserPhoneVerify;
|
export default UserPhoneVerify;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// I'll come back to This
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import CardVerify from 'component/cardVerify';
|
import CardVerify from 'component/cardVerify';
|
||||||
|
@ -25,8 +27,8 @@ class UserVerify extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { errorMessage, isPending, navigate, verifyPhone, modal } = this.props;
|
const { errorMessage, isPending, navigate, verifyPhone, modal } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<React.Fragment>
|
||||||
<section className="card card--form">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h1>{__('Final Human Proof')}</h1>
|
<h1>{__('Final Human Proof')}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +38,7 @@ class UserVerify extends React.PureComponent {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('1) Proof via Credit')}</h3>
|
<h3>{__('1) Proof via Credit')}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,7 +66,7 @@ class UserVerify extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('2) Proof via Phone')}</h3>
|
<h3>{__('2) Proof via Phone')}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -117,7 +119,7 @@ class UserVerify extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('4) Proof via Chat')}</h3>
|
<h3>{__('4) Proof via Chat')}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,7 +144,7 @@ class UserVerify extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h5>{__('Or, Skip It Entirely')}</h5>
|
<h5>{__('Or, Skip It Entirely')}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
@ -157,9 +159,10 @@ class UserVerify extends React.PureComponent {
|
||||||
<Link onClick={() => navigate('/discover')} button="alt" label={__('Skip Rewards')} />
|
<Link onClick={() => navigate('/discover')} button="alt" label={__('Skip Rewards')} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserVerify;
|
export default UserVerify;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import Address from 'component/address';
|
import Address from 'component/address';
|
||||||
|
|
||||||
class WalletAddress extends React.PureComponent {
|
type Props = {
|
||||||
|
checkAddressIsMine: string => void,
|
||||||
|
receiveAddress: string,
|
||||||
|
getNewAddress: () => void,
|
||||||
|
gettingNewAddress: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
class WalletAddress extends React.PureComponent<Props> {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.checkAddressIsMine(this.props.receiveAddress);
|
this.props.checkAddressIsMine(this.props.receiveAddress);
|
||||||
}
|
}
|
||||||
|
@ -11,21 +19,22 @@ class WalletAddress extends React.PureComponent {
|
||||||
const { receiveAddress, getNewAddress, gettingNewAddress } = this.props;
|
const { receiveAddress, getNewAddress, gettingNewAddress } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Receive Credits')}</h3>
|
<h2>{__('Receive Credits')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<p className="card__subtitle">
|
||||||
<p>
|
|
||||||
{__('Use this wallet address to receive credits sent by another user (or yourself).')}
|
{__('Use this wallet address to receive credits sent by another user (or yourself).')}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="card__content">
|
||||||
<Address address={receiveAddress} showCopyButton />
|
<Address address={receiveAddress} showCopyButton />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
<Link
|
<Link
|
||||||
label={__('Get New Address')}
|
label={__('Get New Address')}
|
||||||
button="primary"
|
icon="RefreshCw"
|
||||||
icon="icon-refresh"
|
|
||||||
onClick={getNewAddress}
|
onClick={getNewAddress}
|
||||||
disabled={gettingNewAddress}
|
disabled={gettingNewAddress}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,33 +1,19 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
import { CreditAmount } from 'component/common';
|
|
||||||
|
|
||||||
const WalletBalance = props => {
|
type Props = {
|
||||||
const { balance, navigate } = props;
|
balance: number,
|
||||||
/*
|
};
|
||||||
<div className="help">
|
|
||||||
<Link
|
const WalletBalance = (props: Props) => {
|
||||||
onClick={() => navigate("/backup")}
|
const { balance } = props;
|
||||||
label={__("Backup Your Wallet")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
*/
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<h2>{__('Balance')}</h2>
|
||||||
<h3>{__('Balance')}</h3>
|
<span className="card__subtitle">{__('You currently have')}</span>
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
{(balance || balance === 0) && <CreditAmount amount={balance} precision={8} />}
|
{(balance || balance === 0) && <CreditAmount large amount={balance} precision={8} />}
|
||||||
</div>
|
|
||||||
<div className="card__actions">
|
|
||||||
<Link button="alt" navigate="/getcredits" label={__('Get Credits')} />
|
|
||||||
<Link
|
|
||||||
button="alt"
|
|
||||||
disabled={balance === 0}
|
|
||||||
navigate="/backup"
|
|
||||||
label={__('Backup Wallet')}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,28 +1,9 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import { doSendDraftTransaction } from 'redux/actions/wallet';
|
||||||
doSendDraftTransaction,
|
|
||||||
doSetDraftTransactionAmount,
|
|
||||||
doSetDraftTransactionAddress,
|
|
||||||
} from 'redux/actions/wallet';
|
|
||||||
import {
|
|
||||||
selectDraftTransactionAmount,
|
|
||||||
selectDraftTransactionAddress,
|
|
||||||
selectDraftTransactionError,
|
|
||||||
} from 'redux/selectors/wallet';
|
|
||||||
|
|
||||||
import WalletSend from './view';
|
import WalletSend from './view';
|
||||||
|
|
||||||
const select = state => ({
|
|
||||||
address: selectDraftTransactionAddress(state),
|
|
||||||
amount: selectDraftTransactionAmount(state),
|
|
||||||
error: selectDraftTransactionError(state),
|
|
||||||
});
|
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
sendToAddress: () => dispatch(doSendDraftTransaction()),
|
sendToAddress: values => dispatch(doSendDraftTransaction(values)),
|
||||||
setAmount: event => dispatch(doSetDraftTransactionAmount(event.target.value)),
|
|
||||||
setAddress: event => dispatch(doSetDraftTransactionAddress(event.target.value)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(WalletSend);
|
export default connect(null, perform)(WalletSend);
|
||||||
|
|
|
@ -1,55 +1,105 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, FormRow, Submit } from 'component/form';
|
import Button from 'component/link';
|
||||||
import { regexAddress } from 'lbryURI';
|
import { Form, FormRow, FormField } from 'component/common/form';
|
||||||
|
import { Formik } from 'formik';
|
||||||
|
import { validateSendTx } from 'util/form-validation';
|
||||||
|
|
||||||
class WalletSend extends React.PureComponent {
|
type DraftTransaction = {
|
||||||
handleSubmit() {
|
address: string,
|
||||||
const { amount, address, sendToAddress } = this.props;
|
amount: number | string, // So we can use a placeholder in the input
|
||||||
const validSubmit = parseFloat(amount) > 0.0 && address;
|
};
|
||||||
|
|
||||||
if (validSubmit) {
|
type Props = {
|
||||||
sendToAddress();
|
sendToAddress: DraftTransaction => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class WalletSend extends React.PureComponent<Props> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSubmit(values: DraftTransaction) {
|
||||||
|
const { sendToAddress } = this.props;
|
||||||
|
sendToAddress(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, modal, setAmount, setAddress, amount, address, error } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Send Credits')}</h3>
|
<h2>{__('Send Credits')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<FormRow
|
<Formik
|
||||||
|
initialValues={{
|
||||||
|
address: '',
|
||||||
|
amount: '',
|
||||||
|
}}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
validate={validateSendTx}
|
||||||
|
render={({
|
||||||
|
values,
|
||||||
|
errors,
|
||||||
|
touched,
|
||||||
|
handleChange,
|
||||||
|
handleBlur,
|
||||||
|
handleSubmit,
|
||||||
|
isSubmitting,
|
||||||
|
}) => (
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<FormRow>
|
||||||
|
<FormField
|
||||||
label={__('Amount')}
|
label={__('Amount')}
|
||||||
postfix={__('LBC')}
|
postfix={__('LBC')}
|
||||||
step="any"
|
error={!!values.amount && touched.amount && errors.amount}
|
||||||
min="0"
|
render={() => (
|
||||||
|
<input
|
||||||
|
className="input--lbc-amount"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="1.23"
|
name="amount"
|
||||||
size="10"
|
min="0"
|
||||||
onChange={setAmount}
|
onChange={handleChange}
|
||||||
value={amount}
|
onBlur={handleBlur}
|
||||||
|
value={values.amount}
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
<div className="card__content">
|
/>
|
||||||
<FormRow
|
|
||||||
label={__('Recipient Address')}
|
<FormField
|
||||||
placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs"
|
label={__('Recipient address')}
|
||||||
|
error={!!values.address && touched.address && errors.address}
|
||||||
|
render={() => (
|
||||||
|
<input
|
||||||
|
className="input--address"
|
||||||
type="text"
|
type="text"
|
||||||
size="60"
|
name="address"
|
||||||
onChange={setAddress}
|
placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs"
|
||||||
value={address}
|
onChange={handleChange}
|
||||||
regexp={regexAddress}
|
onBlur={handleBlur}
|
||||||
trim
|
value={values.address}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
icon="Send"
|
||||||
|
label={__('Send')}
|
||||||
|
disabled={
|
||||||
|
!values.address ||
|
||||||
|
!!Object.keys(errors).length ||
|
||||||
|
!(parseFloat(values.amount) > 0.0)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<div className="form-row-submit">
|
|
||||||
<Submit label={__('Send')} disabled={!(parseFloat(amount) > 0.0) || !address} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import { FormRow } from 'component/form';
|
import { FormRow } from 'component/common/form';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
|
|
||||||
class WalletSendTip extends React.PureComponent {
|
class WalletSendTip extends React.PureComponent {
|
||||||
|
@ -67,3 +69,4 @@ class WalletSendTip extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WalletSendTip;
|
export default WalletSendTip;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -466,6 +466,7 @@ export default class Autocomplete extends React.Component {
|
||||||
const menu = this.props.renderMenu(items, this.props.value, style);
|
const menu = this.props.renderMenu(items, this.props.value, style);
|
||||||
return React.cloneElement(menu, {
|
return React.cloneElement(menu, {
|
||||||
ref: e => (this.refs.menu = e),
|
ref: e => (this.refs.menu = e),
|
||||||
|
className: 'wunderbar__menu',
|
||||||
// Ignore blur to prevent menu from de-rendering before we can process click
|
// Ignore blur to prevent menu from de-rendering before we can process click
|
||||||
onMouseEnter: () => this.setIgnoreBlur(true),
|
onMouseEnter: () => this.setIgnoreBlur(true),
|
||||||
onMouseLeave: () => this.setIgnoreBlur(false),
|
onMouseLeave: () => this.setIgnoreBlur(false),
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { normalizeURI } from 'lbryURI';
|
import { normalizeURI } from 'lbryURI';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import throttle from 'util/throttle';
|
||||||
|
import Icon from 'component/common/icon';
|
||||||
import Autocomplete from './internal/autocomplete';
|
import Autocomplete from './internal/autocomplete';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -16,29 +18,22 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class WunderBar extends React.PureComponent<Props> {
|
class WunderBar extends React.PureComponent<Props> {
|
||||||
constructor() {
|
constructor(props: Props) {
|
||||||
super();
|
super(props);
|
||||||
|
|
||||||
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||||
(this: any).handleChange = this.handleChange.bind(this);
|
(this: any).handleChange = this.handleChange.bind(this);
|
||||||
(this: any).focus = this.focus.bind(this);
|
(this: any).focus = this.focus.bind(this);
|
||||||
|
(this: any).throttledGetSearchSuggestions = throttle(this.props.getSearchSuggestions, 1000);
|
||||||
this.input = undefined;
|
this.input = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
input: ?HTMLInputElement;
|
|
||||||
|
|
||||||
handleChange(e: SyntheticInputEvent<*>) {
|
handleChange(e: SyntheticInputEvent<*>) {
|
||||||
const { updateSearchQuery, getSearchSuggestions } = this.props;
|
const { updateSearchQuery, getSearchSuggestions } = this.props;
|
||||||
const { value } = e.target;
|
const { value } = e.target;
|
||||||
|
|
||||||
updateSearchQuery(value);
|
updateSearchQuery(value);
|
||||||
getSearchSuggestions(value);
|
this.throttledGetSearchSuggestions(value);
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
const { input } = this;
|
|
||||||
if (input) {
|
|
||||||
input.focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(value: string) {
|
handleSubmit(value: string) {
|
||||||
|
@ -70,6 +65,16 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
const { input } = this;
|
||||||
|
if (input) {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input: ?HTMLInputElement;
|
||||||
|
throttledGetSearchSuggestions: string => void;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { searchQuery, isActive, address, suggestions } = this.props;
|
const { searchQuery, isActive, address, suggestions } = this.props;
|
||||||
|
|
||||||
|
@ -83,12 +88,13 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
'header__wunderbar--active': isActive,
|
'header__wunderbar--active': isActive,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
<Icon icon="Search" />
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
autoHighlight
|
autoHighlight
|
||||||
ref={ref => {
|
ref={ref => {
|
||||||
this.input = ref;
|
this.input = ref;
|
||||||
}}
|
}}
|
||||||
wrapperStyle={{ flex: 1, minHeight: 0 }}
|
wrapperStyle={{ flex: 1 }}
|
||||||
value={wunderbarValue}
|
value={wunderbarValue}
|
||||||
items={suggestions}
|
items={suggestions}
|
||||||
getItemValue={item => item.value}
|
getItemValue={item => item.value}
|
||||||
|
@ -108,7 +114,8 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
'wunderbar__active-suggestion': isHighlighted,
|
'wunderbar__active-suggestion': isHighlighted,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{item.label}
|
<Icon icon={item.icon} />
|
||||||
|
<span className="wunderbar__suggestion-label">{item.label}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -37,8 +37,6 @@ export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
|
||||||
export const UPDATE_BALANCE = 'UPDATE_BALANCE';
|
export const UPDATE_BALANCE = 'UPDATE_BALANCE';
|
||||||
export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';
|
export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';
|
||||||
export const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED';
|
export const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED';
|
||||||
export const SET_DRAFT_TRANSACTION_AMOUNT = 'SET_DRAFT_TRANSACTION_AMOUNT';
|
|
||||||
export const SET_DRAFT_TRANSACTION_ADDRESS = 'SET_DRAFT_TRANSACTION_ADDRESS';
|
|
||||||
export const SEND_TRANSACTION_STARTED = 'SEND_TRANSACTION_STARTED';
|
export const SEND_TRANSACTION_STARTED = 'SEND_TRANSACTION_STARTED';
|
||||||
export const SEND_TRANSACTION_COMPLETED = 'SEND_TRANSACTION_COMPLETED';
|
export const SEND_TRANSACTION_COMPLETED = 'SEND_TRANSACTION_COMPLETED';
|
||||||
export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED';
|
export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const FEATURED = 'rocket';
|
export const FEATURED = 'Award';
|
||||||
export const LOCAL = 'folder';
|
export const LOCAL = 'Folder';
|
||||||
export const FILE = 'file';
|
export const FILE = 'file';
|
||||||
export const HISTORY = 'history';
|
export const HISTORY = 'history';
|
||||||
export const HELP_CIRCLE = 'question-circle';
|
export const HELP_CIRCLE = 'question-circle';
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
// I'll come back to this
|
||||||
|
/* esline-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import { CreditAmount, CurrencySymbol } from 'component/common';
|
import { CurrencySymbol } from 'component/common';
|
||||||
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
import Link from 'component/link/index';
|
import Link from 'component/link/index';
|
||||||
|
|
||||||
const ModalCreditIntro = props => {
|
const ModalCreditIntro = props => {
|
||||||
|
@ -46,3 +49,4 @@ const ModalCreditIntro = props => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ModalCreditIntro;
|
export default ModalCreditIntro;
|
||||||
|
/* esline-enable */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
// I"ll come back to This
|
||||||
|
/* esline-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import { CreditAmount } from 'component/common';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
|
|
||||||
class ModalFirstReward extends React.PureComponent {
|
class ModalFirstReward extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
|
@ -42,3 +44,4 @@ class ModalFirstReward extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ModalFirstReward;
|
export default ModalFirstReward;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Link from 'component/link';
|
||||||
import UserEmailNew from 'component/userEmailNew';
|
import UserEmailNew from 'component/userEmailNew';
|
||||||
import UserEmailVerify from 'component/userEmailVerify';
|
import UserEmailVerify from 'component/userEmailVerify';
|
||||||
import UserVerify from 'component/userVerify';
|
import UserVerify from 'component/userVerify';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
export class AuthPage extends React.PureComponent {
|
export class AuthPage extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -58,9 +59,10 @@ export class AuthPage extends React.PureComponent {
|
||||||
const { email, user, isPending, navigate } = this.props;
|
const { email, user, isPending, navigate } = this.props;
|
||||||
const [innerContent, useTemplate] = this.renderMain();
|
const [innerContent, useTemplate] = this.renderMain();
|
||||||
|
|
||||||
return useTemplate ? (
|
return (
|
||||||
<main>
|
<Page>
|
||||||
<section className="card card--form">
|
{useTemplate ? (
|
||||||
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h1>{this.getTitle()}</h1>
|
<h1>{this.getTitle()}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -74,9 +76,10 @@ export class AuthPage extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
|
||||||
) : (
|
) : (
|
||||||
innerContent
|
innerContent
|
||||||
|
)}
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
class BackupPage extends React.PureComponent {
|
class BackupPage extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
|
@ -16,9 +16,8 @@ class BackupPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
<section className="card card--section">
|
||||||
<section className="card">
|
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Backup Your LBRY Credits')}</h3>
|
<h3>{__('Backup Your LBRY Credits')}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,7 +56,7 @@ class BackupPage extends React.PureComponent {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import Link from 'component/link';
|
||||||
import { FileTile } from 'component/fileTile';
|
import { FileTile } from 'component/fileTile';
|
||||||
import { BusyMessage, Thumbnail } from 'component/common.js';
|
import { BusyMessage, Thumbnail } from 'component/common.js';
|
||||||
import FileList from 'component/fileList';
|
import FileList from 'component/fileList';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
|
|
||||||
class FileListDownloaded extends React.PureComponent {
|
class FileListDownloaded extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -31,12 +30,7 @@ class FileListDownloaded extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <main className="main--single-column">{content}</main>;
|
||||||
<main className="main--single-column">
|
|
||||||
<SubHeader />
|
|
||||||
{content}
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import Link from 'component/link';
|
||||||
import FileTile from 'component/fileTile';
|
import FileTile from 'component/fileTile';
|
||||||
import { BusyMessage, Thumbnail } from 'component/common.js';
|
import { BusyMessage, Thumbnail } from 'component/common.js';
|
||||||
import FileList from 'component/fileList';
|
import FileList from 'component/fileList';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
|
|
||||||
class FileListPublished extends React.PureComponent {
|
class FileListPublished extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -41,12 +40,7 @@ class FileListPublished extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <main className="main--single-column">{content}</main>;
|
||||||
<main className="main--single-column">
|
|
||||||
<SubHeader />
|
|
||||||
{content}
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import RewardSummary from 'component/rewardSummary';
|
import RewardSummary from 'component/rewardSummary';
|
||||||
import ShapeShift from 'component/shapeShift';
|
import ShapeShift from 'component/shapeShift';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
const GetCreditsPage = props => (
|
const GetCreditsPage = props => (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
|
||||||
<RewardSummary />
|
<RewardSummary />
|
||||||
<ShapeShift />
|
<ShapeShift />
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('From External Wallet')}</h3>
|
<h2>{__('From External Wallet')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
<Link button="alt" navigate="/send" icon="icon-send" label={__('Send / Receive')} />
|
<Link navigate="/send" label={__('Send / Receive')} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('More ways to get LBRY Credits')}</h3>
|
<h2>{__('More ways to get LBRY Credits')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<p>
|
<p>
|
||||||
|
@ -29,10 +28,10 @@ const GetCreditsPage = props => (
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
<Link button="alt" href="https://lbry.io/faq/earn-credits" label={__('Read More')} />
|
<Link fakeLink href="https://lbry.io/faq/earn-credits" label={__('Read More')} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default GetCreditsPage;
|
export default GetCreditsPage;
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import lbry from 'lbry.js';
|
import lbry from 'lbry.js';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
class HelpPage extends React.PureComponent {
|
class HelpPage extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -70,8 +70,7 @@ class HelpPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Read the FAQ')}</h3>
|
<h3>{__('Read the FAQ')}</h3>
|
||||||
|
@ -210,7 +209,7 @@ class HelpPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import InviteNew from 'component/inviteNew';
|
import InviteNew from 'component/inviteNew';
|
||||||
import InviteList from 'component/inviteList';
|
import InviteList from 'component/inviteList';
|
||||||
|
|
||||||
|
@ -14,7 +13,6 @@ class InvitePage extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<main className="main--single-column">
|
||||||
<SubHeader />
|
|
||||||
{isPending && <BusyMessage message={__('Checking your invite status')} />}
|
{isPending && <BusyMessage message={__('Checking your invite status')} />}
|
||||||
{!isPending &&
|
{!isPending &&
|
||||||
isFailed && <span className="empty">{__('Failed to retrieve invite status.')}</span>}
|
isFailed && <span className="empty">{__('Failed to retrieve invite status.')}</span>}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import { FormRow } from 'component/form';
|
import { FormRow } from 'component/common/form';
|
||||||
import { doShowSnackBar } from 'redux/actions/app';
|
import { doShowSnackBar } from 'redux/actions/app';
|
||||||
import lbry from '../lbry.js';
|
import lbry from '../lbry.js';
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import RewardListClaimed from 'component/rewardListClaimed';
|
import RewardListClaimed from 'component/rewardListClaimed';
|
||||||
import RewardTile from 'component/rewardTile';
|
import RewardTile from 'component/rewardTile';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
class RewardsPage extends React.PureComponent {
|
class RewardsPage extends React.PureComponent {
|
||||||
/*
|
/*
|
||||||
|
@ -34,7 +34,7 @@ class RewardsPage extends React.PureComponent {
|
||||||
if (user && !user.is_reward_approved) {
|
if (user && !user.is_reward_approved) {
|
||||||
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
|
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
|
||||||
return (
|
return (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Humans Only')}</h3>
|
<h3>{__('Humans Only')}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,6 +102,7 @@ class RewardsPage extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
// TODO: come back to me and actually implement a grid
|
||||||
<div className="card-grid">
|
<div className="card-grid">
|
||||||
{rewards.map(reward => <RewardTile key={reward.reward_type} reward={reward} />)}
|
{rewards.map(reward => <RewardTile key={reward.reward_type} reward={reward} />)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,12 +111,11 @@ class RewardsPage extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
|
||||||
{this.renderPageHeader()}
|
{this.renderPageHeader()}
|
||||||
{this.renderUnclaimedRewards()}
|
{this.renderUnclaimedRewards()}
|
||||||
{<RewardListClaimed />}
|
{<RewardListClaimed />}
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import WalletSend from 'component/walletSend';
|
import WalletSend from 'component/walletSend';
|
||||||
import WalletAddress from 'component/walletAddress';
|
import WalletAddress from 'component/walletAddress';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
const SendReceivePage = props => (
|
const SendReceivePage = props => (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
|
||||||
<WalletSend />
|
<WalletSend />
|
||||||
<WalletAddress />
|
<WalletAddress />
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default SendReceivePage;
|
export default SendReceivePage;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FormField from 'component/formField';
|
import FormField from 'component/formField';
|
||||||
import { FormRow } from 'component/form.js';
|
import { FormRow } from 'component/common/form';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import lbry from 'lbry.js';
|
import lbry from 'lbry.js';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import FormFieldPrice from 'component/formFieldPrice';
|
import FormFieldPrice from 'component/formFieldPrice';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
class SettingsPage extends React.PureComponent {
|
class SettingsPage extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -144,8 +144,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
|
||||||
{/*
|
{/*
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
@ -348,7 +347,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SubHeader from 'component/subHeader';
|
import Page from 'component/page';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import CategoryList from 'component/common/category-list';
|
import CategoryList from 'component/common/category-list';
|
||||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
import type { Subscription } from 'redux/reducers/subscriptions';
|
||||||
|
@ -61,16 +61,10 @@ export default class extends React.PureComponent<Props> {
|
||||||
(subscriptions.length !== savedSubscriptions.length || someClaimsNotLoaded);
|
(subscriptions.length !== savedSubscriptions.length || someClaimsNotLoaded);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main main--no-margin">
|
<Page noPadding isLoading={fetchingSubscriptions}>
|
||||||
<SubHeader fullWidth smallMargin />
|
|
||||||
{!savedSubscriptions.length && (
|
{!savedSubscriptions.length && (
|
||||||
<span>{__("You haven't subscribed to any channels yet")}</span>
|
<span>{__("You haven't subscribed to any channels yet")}</span>
|
||||||
)}
|
)}
|
||||||
{fetchingSubscriptions && (
|
|
||||||
<div className="card-row__placeholder">
|
|
||||||
<BusyMessage message={__('Fetching subscriptions')} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!!savedSubscriptions.length && (
|
{!!savedSubscriptions.length && (
|
||||||
<div>
|
<div>
|
||||||
{!!subscriptions.length &&
|
{!!subscriptions.length &&
|
||||||
|
@ -93,7 +87,7 @@ export default class extends React.PureComponent<Props> {
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BusyMessage } from 'component/common';
|
import { BusyMessage } from 'component/common';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import TransactionList from 'component/transactionList';
|
import TransactionList from 'component/transactionList';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
class TransactionHistoryPage extends React.PureComponent {
|
class TransactionHistoryPage extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -12,9 +12,8 @@ class TransactionHistoryPage extends React.PureComponent {
|
||||||
const { fetchingTransactions, transactions } = this.props;
|
const { fetchingTransactions, transactions } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<Page>
|
||||||
<SubHeader />
|
<section className="card card--section">
|
||||||
<section className="card">
|
|
||||||
<div
|
<div
|
||||||
className={`card__title-primary ${
|
className={`card__title-primary ${
|
||||||
fetchingTransactions && transactions.length ? 'reloading' : ''
|
fetchingTransactions && transactions.length ? 'reloading' : ''
|
||||||
|
@ -35,7 +34,7 @@ class TransactionHistoryPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SubHeader from 'component/subHeader';
|
|
||||||
import WalletBalance from 'component/walletBalance';
|
import WalletBalance from 'component/walletBalance';
|
||||||
import RewardSummary from 'component/rewardSummary';
|
import RewardSummary from 'component/rewardSummary';
|
||||||
import TransactionListRecent from 'component/transactionListRecent';
|
import TransactionListRecent from 'component/transactionListRecent';
|
||||||
|
import WalletAddress from 'component/walletAddress';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
const WalletPage = props => (
|
const WalletPage = () => (
|
||||||
<main className="main--single-column page--wallet">
|
<Page>
|
||||||
<SubHeader />
|
<div className="columns">
|
||||||
<div className="card-grid">
|
|
||||||
<WalletBalance />
|
<WalletBalance />
|
||||||
<RewardSummary />
|
<RewardSummary />
|
||||||
</div>
|
</div>
|
||||||
|
<WalletAddress />
|
||||||
<TransactionListRecent />
|
<TransactionListRecent />
|
||||||
</main>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default WalletPage;
|
export default WalletPage;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import { normalizeURI } from 'lbryURI';
|
import { normalizeURI, buildURI } from 'lbryURI';
|
||||||
import { doResolveUri } from 'redux/actions/content';
|
import { doResolveUri } from 'redux/actions/content';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectCurrentPage } from 'redux/selectors/navigation';
|
import { selectCurrentPage } from 'redux/selectors/navigation';
|
||||||
|
@ -89,10 +89,17 @@ export const getSearchSuggestions = value => dispatch => {
|
||||||
fetch(`https://lighthouse.lbry.io/autocomplete?s=${searchValue}`)
|
fetch(`https://lighthouse.lbry.io/autocomplete?s=${searchValue}`)
|
||||||
.then(handleSearchApiResponse)
|
.then(handleSearchApiResponse)
|
||||||
.then(suggestions => {
|
.then(suggestions => {
|
||||||
const formattedSuggestions = suggestions.slice(0, 5).map(suggestion => ({
|
const formattedSuggestions = suggestions.slice(0, 5).map(suggestion => {
|
||||||
label: suggestion,
|
// This will need to be more robust when the api starts returning lbry uris
|
||||||
|
const isChannel = suggestion.startsWith('@');
|
||||||
|
const suggestionObj = {
|
||||||
value: suggestion,
|
value: suggestion,
|
||||||
}));
|
label: isChannel ? suggestion.slice(1) : suggestion,
|
||||||
|
icon: isChannel ? 'AtSign' : 'Search',
|
||||||
|
};
|
||||||
|
|
||||||
|
return suggestionObj;
|
||||||
|
});
|
||||||
|
|
||||||
// Should we add lbry://{query} as the first result?
|
// Should we add lbry://{query} as the first result?
|
||||||
// If it's not a valid uri, then add a "search for {query}" result
|
// If it's not a valid uri, then add a "search for {query}" result
|
||||||
|
@ -100,12 +107,12 @@ export const getSearchSuggestions = value => dispatch => {
|
||||||
try {
|
try {
|
||||||
const uri = normalizeURI(value);
|
const uri = normalizeURI(value);
|
||||||
formattedSuggestions.unshift(
|
formattedSuggestions.unshift(
|
||||||
{ label: uri, value: uri },
|
{ label: uri, value: uri, icon: 'Compass' },
|
||||||
{ label: searchLabel, value: `${value}?search` }
|
{ label: searchLabel, value: `${value}?search`, icon: 'Search' }
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (value) {
|
if (value) {
|
||||||
formattedSuggestions.unshift({ label: searchLabel, value });
|
formattedSuggestions.unshift({ label: searchLabel, value, icon: 'Search' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ import { doOpenModal, doShowSnackBar } from 'redux/actions/app';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import {
|
import {
|
||||||
selectBalance,
|
selectBalance,
|
||||||
selectDraftTransaction,
|
|
||||||
selectDraftTransactionAmount,
|
|
||||||
} from 'redux/selectors/wallet';
|
} from 'redux/selectors/wallet';
|
||||||
|
|
||||||
export function doUpdateBalance() {
|
export function doUpdateBalance() {
|
||||||
|
@ -89,12 +87,10 @@ export function doCheckAddressIsMine(address) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doSendDraftTransaction() {
|
export function doSendDraftTransaction({ amount, address }) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const draftTx = selectDraftTransaction(state);
|
|
||||||
const balance = selectBalance(state);
|
const balance = selectBalance(state);
|
||||||
const amount = selectDraftTransactionAmount(state);
|
|
||||||
|
|
||||||
if (balance - amount <= 0) {
|
if (balance - amount <= 0) {
|
||||||
dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS));
|
dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS));
|
||||||
|
@ -135,26 +131,12 @@ export function doSendDraftTransaction() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Lbry.wallet_send({
|
Lbry.wallet_send({
|
||||||
amount: draftTx.amount,
|
amount,
|
||||||
address: draftTx.address,
|
address,
|
||||||
}).then(successCallback, errorCallback);
|
}).then(successCallback, errorCallback);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doSetDraftTransactionAmount(amount) {
|
|
||||||
return {
|
|
||||||
type: ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT,
|
|
||||||
data: { amount },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function doSetDraftTransactionAddress(address) {
|
|
||||||
return {
|
|
||||||
type: ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS,
|
|
||||||
data: { address },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function doSendSupport(amount, claimId, uri) {
|
export function doSendSupport(amount, claimId, uri) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
|
@ -2,10 +2,6 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const receiveAddress = localStorage.getItem('receiveAddress');
|
const receiveAddress = localStorage.getItem('receiveAddress');
|
||||||
const buildDraftTransaction = () => ({
|
|
||||||
amount: undefined,
|
|
||||||
address: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
balance: undefined,
|
balance: undefined,
|
||||||
|
@ -14,8 +10,8 @@ const defaultState = {
|
||||||
fetchingTransactions: false,
|
fetchingTransactions: false,
|
||||||
receiveAddress,
|
receiveAddress,
|
||||||
gettingNewAddress: false,
|
gettingNewAddress: false,
|
||||||
draftTransaction: buildDraftTransaction(),
|
|
||||||
sendingSupport: false,
|
sendingSupport: false,
|
||||||
|
sendingTx: false
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = state =>
|
reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = state =>
|
||||||
|
@ -68,51 +64,21 @@ reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED] = state =>
|
||||||
checkingAddressOwnership: false,
|
checkingAddressOwnership: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT] = (state, action) => {
|
|
||||||
const oldDraft = state.draftTransaction;
|
|
||||||
const newDraft = Object.assign({}, oldDraft, {
|
|
||||||
amount: parseFloat(action.data.amount),
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
draftTransaction: newDraft,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
reducers[ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS] = (state, action) => {
|
|
||||||
const oldDraft = state.draftTransaction;
|
|
||||||
const newDraft = Object.assign({}, oldDraft, {
|
|
||||||
address: action.data.address,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
draftTransaction: newDraft,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
reducers[ACTIONS.SEND_TRANSACTION_STARTED] = state => {
|
reducers[ACTIONS.SEND_TRANSACTION_STARTED] = state => {
|
||||||
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
|
|
||||||
sending: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
draftTransaction: newDraftTransaction,
|
sendingTx: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = state =>
|
reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = state =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
draftTransaction: buildDraftTransaction(),
|
sendingTx: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state, action) => {
|
reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state, action) => {
|
||||||
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
|
|
||||||
sending: false,
|
|
||||||
error: action.data.error,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
draftTransaction: newDraftTransaction,
|
sendingTx: false,
|
||||||
|
error: action.data.error
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { parseQueryParams, toQueryString } from 'util/query_params';
|
import { parseQueryParams } from 'util/query_params';
|
||||||
import { normalizeURI } from 'lbryURI';
|
|
||||||
|
|
||||||
export const selectState = state => state.navigation || {};
|
export const selectState = state => state.navigation || {};
|
||||||
|
|
||||||
|
@ -22,72 +21,6 @@ export const selectCurrentParams = createSelector(selectCurrentPath, path => {
|
||||||
export const makeSelectCurrentParam = param =>
|
export const makeSelectCurrentParam = param =>
|
||||||
createSelector(selectCurrentParams, params => (params ? params[param] : undefined));
|
createSelector(selectCurrentParams, params => (params ? params[param] : undefined));
|
||||||
|
|
||||||
export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
|
|
||||||
// This contains intentional fall throughs
|
|
||||||
switch (page) {
|
|
||||||
case 'wallet':
|
|
||||||
case 'history':
|
|
||||||
case 'send':
|
|
||||||
case 'getcredits':
|
|
||||||
case 'invite':
|
|
||||||
case 'rewards':
|
|
||||||
case 'backup':
|
|
||||||
return {
|
|
||||||
wallet: __('Overview'),
|
|
||||||
getcredits: __('Get Credits'),
|
|
||||||
send: __('Send / Receive'),
|
|
||||||
rewards: __('Rewards'),
|
|
||||||
invite: __('Invites'),
|
|
||||||
history: __('History'),
|
|
||||||
};
|
|
||||||
case 'downloaded':
|
|
||||||
case 'published':
|
|
||||||
return {
|
|
||||||
downloaded: __('Downloaded'),
|
|
||||||
published: __('Published'),
|
|
||||||
};
|
|
||||||
case 'settings':
|
|
||||||
case 'help':
|
|
||||||
return {
|
|
||||||
settings: __('Settings'),
|
|
||||||
help: __('Help'),
|
|
||||||
};
|
|
||||||
case 'discover':
|
|
||||||
case 'subscriptions':
|
|
||||||
return {
|
|
||||||
discover: __('Discover'),
|
|
||||||
subscriptions: __('Subscriptions'),
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectPageTitle = createSelector(
|
|
||||||
selectCurrentPage,
|
|
||||||
selectCurrentParams,
|
|
||||||
(page, params) => {
|
|
||||||
switch (page) {
|
|
||||||
case 'show': {
|
|
||||||
const parts = [normalizeURI(params.uri)];
|
|
||||||
// If the params has any keys other than "uri"
|
|
||||||
if (Object.keys(params).length > 1) {
|
|
||||||
parts.push(toQueryString(Object.assign({}, params, { uri: null })));
|
|
||||||
}
|
|
||||||
return parts.join('?');
|
|
||||||
}
|
|
||||||
case 'discover':
|
|
||||||
return __('Discover');
|
|
||||||
case false:
|
|
||||||
case null:
|
|
||||||
case '':
|
|
||||||
return '';
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth);
|
export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth);
|
||||||
|
|
||||||
export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0);
|
export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0);
|
||||||
|
@ -97,6 +30,8 @@ export const selectIsForwardDisabled = createSelector(
|
||||||
state => state.index === state.stack.length - 1
|
state => state.index === state.stack.length - 1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectIsHome = createSelector(selectCurrentPage, page => page === 'discover');
|
||||||
|
|
||||||
export const selectHistoryIndex = createSelector(selectState, state => state.index);
|
export const selectHistoryIndex = createSelector(selectState, state => state.index);
|
||||||
|
|
||||||
export const selectHistoryStack = createSelector(selectState, state => state.stack);
|
export const selectHistoryStack = createSelector(selectState, state => state.stack);
|
||||||
|
@ -106,3 +41,126 @@ export const selectActiveHistoryEntry = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.stack[state.index]
|
state => state.stack[state.index]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectPageTitle = createSelector(
|
||||||
|
selectCurrentPage,
|
||||||
|
(page) => {
|
||||||
|
switch (page) {
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectNavLinks = createSelector(
|
||||||
|
selectCurrentPage,
|
||||||
|
selectHistoryStack,
|
||||||
|
(currentPage, historyStack) => {
|
||||||
|
const isWalletPage = page =>
|
||||||
|
page === 'wallet' ||
|
||||||
|
page === 'send' ||
|
||||||
|
page === 'getcredits' ||
|
||||||
|
page === 'rewards' ||
|
||||||
|
page === 'history';
|
||||||
|
|
||||||
|
let walletLink;
|
||||||
|
if (isWalletPage(currentPage)) {
|
||||||
|
// If they are on a wallet page, the top level link should direct them to the overview page
|
||||||
|
walletLink = '/wallet';
|
||||||
|
} else {
|
||||||
|
// check to see if they've recently been on a wallet sub-link
|
||||||
|
const previousStack = historyStack.slice().reverse();
|
||||||
|
for (let i = 0; i < previousStack.length; i += 1) {
|
||||||
|
const currentStackItem = previousStack[i];
|
||||||
|
|
||||||
|
// Trim off the "/" from the path
|
||||||
|
const pageInStack = currentStackItem.path.slice(1);
|
||||||
|
if (isWalletPage(pageInStack)) {
|
||||||
|
walletLink = currentStackItem.path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const walletSubLinks = [
|
||||||
|
{
|
||||||
|
label: 'Overview',
|
||||||
|
path: '/wallet',
|
||||||
|
active: currentPage === 'wallet',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Send & Recieve',
|
||||||
|
path: '/send',
|
||||||
|
active: currentPage === 'send',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Get Credits',
|
||||||
|
path: '/getcredits',
|
||||||
|
active: currentPage === 'getcredits',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rewards',
|
||||||
|
path: '/rewards',
|
||||||
|
active: currentPage === 'rewards',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'My Transactions',
|
||||||
|
path: '/history',
|
||||||
|
active: currentPage === 'history',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const navLinks = {
|
||||||
|
primary: [
|
||||||
|
{
|
||||||
|
label: 'Explore',
|
||||||
|
path: '/discover',
|
||||||
|
active: currentPage === 'discover',
|
||||||
|
icon: 'Compass',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subscriptions',
|
||||||
|
path: '/subscriptions',
|
||||||
|
active: currentPage === 'subscriptions',
|
||||||
|
icon: 'AtSign',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
label: 'Wallet',
|
||||||
|
path: walletLink || '/wallet', // If they've never been to a wallet page, take them to the overview
|
||||||
|
active:
|
||||||
|
currentPage === 'wallet' ||
|
||||||
|
!!walletSubLinks.find(({ path }) => currentPage === path.slice(1)),
|
||||||
|
subLinks: walletSubLinks,
|
||||||
|
icon: 'CreditCard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Publish',
|
||||||
|
path: '/publish',
|
||||||
|
active: currentPage === 'publish',
|
||||||
|
icon: 'UploadCloud',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Settings',
|
||||||
|
path: '/settings',
|
||||||
|
active: currentPage === 'settings',
|
||||||
|
icon: 'Settings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Backup Wallet',
|
||||||
|
path: '/backup',
|
||||||
|
active: currentPage === 'backup',
|
||||||
|
icon: 'Save',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Help',
|
||||||
|
path: '/help',
|
||||||
|
active: currentPage === 'help',
|
||||||
|
icon: 'HelpCircle',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return navLinks;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -96,26 +96,6 @@ export const selectGettingNewAddress = createSelector(
|
||||||
state => state.gettingNewAddress
|
state => state.gettingNewAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectDraftTransaction = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.draftTransaction || {}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectDraftTransactionAmount = createSelector(
|
|
||||||
selectDraftTransaction,
|
|
||||||
draft => draft.amount
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectDraftTransactionAddress = createSelector(
|
|
||||||
selectDraftTransaction,
|
|
||||||
draft => draft.address
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectDraftTransactionError = createSelector(
|
|
||||||
selectDraftTransaction,
|
|
||||||
draft => draft.error
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectBlocks = createSelector(selectState, state => state.blocks);
|
export const selectBlocks = createSelector(selectState, state => state.blocks);
|
||||||
|
|
||||||
export const makeSelectBlockDate = block =>
|
export const makeSelectBlockDate = block =>
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
// Generic html styles used accross the App
|
// Generic html styles used accross the App
|
||||||
// component specific styling should go in the component scss file
|
// component specific styling should go in the component scss file
|
||||||
|
|
||||||
// The actual fonts used will change ex: medium vs regular
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Metropolis';
|
font-family: 'Metropolis';
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
|
src: url('../../../static/font/metropolis/Metropolis-Regular.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Metropolis';
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
src: url('../../../static/font/metropolis/Metropolis-Medium.woff2') format('woff2');
|
src: url('../../../static/font/metropolis/Metropolis-Medium.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Metropolis';
|
font-family: 'Metropolis';
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
src: url('../../../static/font/metropolis/Metropolis-SemiBold.woff2') format('woff2');
|
src: url('../../../static/font/metropolis/Metropolis-SemiBold.woff2') format('woff2');
|
||||||
|
@ -63,19 +70,6 @@ h5 {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
sup,
|
|
||||||
sub {
|
|
||||||
vertical-align: baseline;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.4em;
|
|
||||||
}
|
|
||||||
sub {
|
|
||||||
top: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font: 0.8em Consolas, 'Lucida Console', 'Source Sans', monospace;
|
font: 0.8em Consolas, 'Lucida Console', 'Source Sans', monospace;
|
||||||
background-color: var(--color-bg-alt);
|
background-color: var(--color-bg-alt);
|
||||||
|
@ -83,35 +77,61 @@ code {
|
||||||
|
|
||||||
// Without this buttons don't have the Metropolis font
|
// Without this buttons don't have the Metropolis font
|
||||||
button {
|
button {
|
||||||
|
font-weight: inherit;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#window {
|
ul {
|
||||||
height: 100%;
|
list-style-type: none;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-content {
|
input {
|
||||||
height: 100%;
|
width: 100%;
|
||||||
overflow-y: auto;
|
cursor: text;
|
||||||
position: absolute;
|
border-bottom: var(--input-border-size) solid var(--input-border-color);
|
||||||
left: 0px;
|
color: var(--input-color);
|
||||||
right: 0px;
|
line-height: 1;
|
||||||
// don't use {bottom/top} here
|
|
||||||
// they cause flashes of un-rendered content when scrolling
|
&.input-copyable {
|
||||||
margin-top: var(--header-height);
|
background: var(--input-bg);
|
||||||
// TODO: fix this scrollbar extends beyond screen at the bottom
|
color: var(--input-disabled-color);
|
||||||
padding-bottom: var(--header-height);
|
width: 100%;
|
||||||
|
font-family: 'Consolas', 'Lucida Console', 'Adobe Source Code Pro', monospace;
|
||||||
|
border-bottom: 1px dotted var(--color-divider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
.page {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: var(--header-height) calc(100vh - var(--header-height));
|
||||||
|
grid-template-columns: 170px auto;
|
||||||
|
grid-template-areas:
|
||||||
|
'nav header'
|
||||||
|
'nav content';
|
||||||
background-color: var(--color-bg);
|
background-color: var(--color-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Page content
|
||||||
|
*/
|
||||||
|
.content {
|
||||||
|
grid-area: content;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding: 0 $spacing-vertical * 2/3;
|
padding: 0 $spacing-vertical $spacing-vertical;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main--no-padding {
|
.main--no-padding {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
margin: 0;
|
||||||
|
max-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page__header {
|
.page__header {
|
||||||
|
@ -124,26 +144,66 @@ button {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.columns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: 0;
|
||||||
|
|
||||||
|
&:not(:first-of-type):not(:last-of-type) {
|
||||||
|
margin: 0 $spacing-vertical / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-right: $spacing-vertical / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-left: $spacing-vertical / 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Custom text selection */
|
/* Custom text selection */
|
||||||
*::selection {
|
*::selection {
|
||||||
background: var(--text-selection-bg);
|
background: var(--text-selection-bg);
|
||||||
color: var(--text-selection-color);
|
color: var(--text-selection-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-amount--indicator {
|
.credit-amount {
|
||||||
font-weight: 500;
|
padding: 5px;
|
||||||
color: var(--color-money);
|
border-radius: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.credit-amount--fee {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: var(--color-meta-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.credit-amount--bold {
|
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
font-size: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.credit-amount--free {
|
||||||
|
color: var(--color-black);
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.credit-amount--cost {
|
||||||
|
color: var(--color-black);
|
||||||
|
background-color: var(--color-third);
|
||||||
|
}
|
||||||
|
|
||||||
|
.credit-amount--large {
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// .credit-amount--fee {
|
||||||
|
// font-size: 0.9em;
|
||||||
|
// color: var(--color-meta-light);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// .credit-amount--bold {
|
||||||
|
// font-weight: 700;
|
||||||
|
// }
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,33 +3,39 @@ Both of these should probably die and become variables as well
|
||||||
*/
|
*/
|
||||||
$spacing-vertical: 24px;
|
$spacing-vertical: 24px;
|
||||||
$width-page-constrained: 800px;
|
$width-page-constrained: 800px;
|
||||||
$text-color: #000;
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--spacing-vertical: 24px;
|
|
||||||
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
|
--color-white: #fff;
|
||||||
|
--color-black: #000; // I shouldn't use color names like this
|
||||||
|
--color-grey: #d6d6d6;
|
||||||
|
--color-grey-dark: #8e8e8e;
|
||||||
|
--color-primary: #44b098;
|
||||||
|
--color-primary-dark: #2c6e60;
|
||||||
|
--color-secondary: #6afbda;
|
||||||
|
--color-third: #fbd55e;
|
||||||
|
--color-divider: #e3e3e3;
|
||||||
|
|
||||||
|
--text-color: var(--color-black);
|
||||||
--color-brand: #155b4a;
|
--color-brand: #155b4a;
|
||||||
--color-primary: #155b4a;
|
// --color-dark-overlay: rgba(32, 32, 32, 0.9);
|
||||||
--color-primary-light: saturate(lighten(#155b4a, 50%), 20%);
|
|
||||||
--color-light-alt: hsl(hue(#155b4a), 15, 85);
|
|
||||||
--color-dark-overlay: rgba(32, 32, 32, 0.9);
|
|
||||||
--color-help: rgba(0, 0, 0, 0.54);
|
--color-help: rgba(0, 0, 0, 0.54);
|
||||||
--color-notice: #8a6d3b;
|
// --color-notice: #8a6d3b;
|
||||||
--color-error: #a94442;
|
--color-error: #a94442;
|
||||||
--color-load-screen-text: #c3c3c3;
|
// --color-load-screen-text: #c3c3c3;
|
||||||
--color-meta-light: #505050;
|
// --color-meta-light: #505050;
|
||||||
--color-money: #216c2a;
|
// --color-money: #216c2a;
|
||||||
--color-download: rgba(0, 0, 0, 0.75);
|
// --color-download: rgba(0, 0, 0, 0.75);
|
||||||
--color-canvas: #f5f5f5;
|
// --color-canvas: #f5f5f5;
|
||||||
--color-bg: #ffffff;
|
--color-bg: #fafafa;
|
||||||
--color-bg-alt: #f6f6f6;
|
--color-bg-alt: #f6f6f6;
|
||||||
--color-placeholder: #ececec;
|
--color-placeholder: #ececec;
|
||||||
|
--color-nav-bg: #f6f6f6;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
--content-max-width: 1000px;
|
// --content-max-width: 1000px;
|
||||||
--nsfw-blur-intensity: 20px;
|
// --nsfw-blur-intensity: 20px;
|
||||||
--height-video-embedded: $width-page-constrained * 9 / 16;
|
// --height-video-embedded: $width-page-constrained * 9 / 16;
|
||||||
|
|
||||||
/* Font */
|
/* Font */
|
||||||
--font-size: 16px;
|
--font-size: 16px;
|
||||||
|
@ -37,16 +43,10 @@ $text-color: #000;
|
||||||
--font-size-subtext-multiple: 0.82;
|
--font-size-subtext-multiple: 0.82;
|
||||||
|
|
||||||
/* Shadows */
|
/* Shadows */
|
||||||
--box-shadow-layer: 0px 1px 3px 0px rgba(0, 0, 0, 0.2);
|
// --box-shadow-layer: 0px 1px 3px 0px rgba(0, 0, 0, 0.2);
|
||||||
--box-shadow-focus: 2px 4px 4px 0 rgba(0, 0, 0, 0.14), 2px 5px 3px -2px rgba(0, 0, 0, 0.2),
|
--box-shadow-layer: 0 4px 9px -2px var(--color-grey);
|
||||||
2px 3px 7px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
|
|
||||||
/* Transition */
|
|
||||||
--transition-duration: 0.225s;
|
|
||||||
--transition-type: ease;
|
|
||||||
|
|
||||||
/* Text */
|
/* Text */
|
||||||
--text-color: $text-color;
|
|
||||||
--text-help-color: #eee;
|
--text-help-color: #eee;
|
||||||
--text-max-width: 660px;
|
--text-max-width: 660px;
|
||||||
--text-link-padding: 4px;
|
--text-link-padding: 4px;
|
||||||
|
@ -58,10 +58,10 @@ $text-color: #000;
|
||||||
|
|
||||||
/* Input */
|
/* Input */
|
||||||
--input-bg: transparent;
|
--input-bg: transparent;
|
||||||
--input-width: 330px;
|
--input-label-color: var(--color-grey-dark);
|
||||||
--input-color: var(--text-color);
|
--input-color: var(--text-color);
|
||||||
--input-border-size: 2px;
|
--input-border-size: 1px;
|
||||||
--input-border-color: rgba(0, 0, 0, 0.54);
|
--input-border-color: var(--color-grey-dark);
|
||||||
|
|
||||||
/* input:active */
|
/* input:active */
|
||||||
--input-active-bg: transparent;
|
--input-active-bg: transparent;
|
||||||
|
@ -81,39 +81,28 @@ $text-color: #000;
|
||||||
--select-color: var(--text-color);
|
--select-color: var(--text-color);
|
||||||
--select-height: 30px;
|
--select-height: 30px;
|
||||||
|
|
||||||
//TODO: determine proper button variables;
|
|
||||||
/* Button */
|
/* Button */
|
||||||
--btn-primary-color: #fff;
|
--btn-primary-color: #fff;
|
||||||
--button-alt-color: var(--text-color);
|
--button-alt-color: var(--text-color);
|
||||||
--btn-primary-bg: var(--color-primary);
|
--btn-primary-bg: var(--color-primary-dark);
|
||||||
--btn-alt-bg: red;
|
--btn-inverse-color: var(--color-primary-dark);
|
||||||
--btn-radius: 10px;
|
--btn-inverse-bg: var(--color-white);
|
||||||
// below needed?
|
--btn-radius: 20px;
|
||||||
--btn-padding: $spacing-vertical * 2/3;
|
--btn-height: 40px;
|
||||||
--btn-height: $spacing-vertical * 1.5;
|
|
||||||
--btn-intra-margin: $spacing-vertical;
|
|
||||||
|
|
||||||
/* Header */
|
/* Header */
|
||||||
--header-bg: var(--color-bg);
|
--header-bg: var(--color-white);
|
||||||
--header-color: #666;
|
--header-color: var(--color-text);
|
||||||
--header-active-color: rgba(0, 0, 0, 0.85);
|
--header-active-color: rgba(0, 0, 0, 0.85);
|
||||||
--header-height: 65px;
|
--header-height: $spacing-vertical * 3;
|
||||||
--header-button-bg: transparent; //var(--button-bg);
|
--header-button-bg: transparent; //var(--button-bg);
|
||||||
--header-button-hover-bg: rgba(100, 100, 100, 0.15);
|
--header-button-hover-bg: rgba(100, 100, 100, 0.15);
|
||||||
|
|
||||||
/* Header -> search */
|
/* Header -> search */
|
||||||
--search-bg: rgba(255, 255, 255, 0.7);
|
|
||||||
--search-border: 1px solid #ccc;
|
|
||||||
--search-color: #666;
|
--search-color: #666;
|
||||||
|
--search-bg-color: #fff;
|
||||||
--search-active-color: var(--header-active-color);
|
--search-active-color: var(--header-active-color);
|
||||||
--search-active-shadow: 0 0 3px 0px var(--text-selection-bg);
|
--search-active-shadow: 0 6px 9px -2px var(--color-grey--dark);
|
||||||
|
|
||||||
/* Tabs */
|
|
||||||
--tab-bg: transparent;
|
|
||||||
--tab-color: rgba(0, 0, 0, 0.5);
|
|
||||||
--tab-active-color: var(--color-primary);
|
|
||||||
--tab-border-size: 2px;
|
|
||||||
--tab-border: var(--tab-border-size) solid var(--tab-active-color);
|
|
||||||
|
|
||||||
/* Table */
|
/* Table */
|
||||||
--table-border: 1px solid #e2e2e2;
|
--table-border: 1px solid #e2e2e2;
|
||||||
|
@ -121,13 +110,10 @@ $text-color: #000;
|
||||||
--table-item-odd: #f4f4f4;
|
--table-item-odd: #f4f4f4;
|
||||||
|
|
||||||
/* Card */
|
/* Card */
|
||||||
--card-bg: var(--color-bg);
|
|
||||||
--card-hover-translate: 10px;
|
--card-hover-translate: 10px;
|
||||||
--card-margin: $spacing-vertical * 2/3;
|
--card-margin: $spacing-vertical * 2/3;
|
||||||
--card-max-width: $width-page-constrained;
|
--card-max-width: $width-page-constrained;
|
||||||
--card-padding: $spacing-vertical * 2/3;
|
|
||||||
--card-radius: 2px;
|
--card-radius: 2px;
|
||||||
--card-link-scaling: 1.1;
|
|
||||||
--card-small-width: $spacing-vertical * 10;
|
--card-small-width: $spacing-vertical * 10;
|
||||||
|
|
||||||
/* Modal */
|
/* Modal */
|
||||||
|
@ -136,12 +122,7 @@ $text-color: #000;
|
||||||
--modal-overlay-bg: rgba(#f5f5f5, 0.75); // --color-canvas: #F5F5F5
|
--modal-overlay-bg: rgba(#f5f5f5, 0.75); // --color-canvas: #F5F5F5
|
||||||
--modal-border: 1px solid rgb(204, 204, 204);
|
--modal-border: 1px solid rgb(204, 204, 204);
|
||||||
|
|
||||||
/* Menu */
|
// /* Tooltip */
|
||||||
--menu-bg: var(--color-bg);
|
|
||||||
--menu-radius: 2px;
|
|
||||||
--menu-item-hover-bg: var(--color-bg-alt);
|
|
||||||
|
|
||||||
/* Tooltip */
|
|
||||||
--tooltip-width: 300px;
|
--tooltip-width: 300px;
|
||||||
--tooltip-bg: var(--color-bg);
|
--tooltip-bg: var(--color-bg);
|
||||||
--tooltip-color: var(--text-color);
|
--tooltip-color: var(--text-color);
|
||||||
|
@ -153,10 +134,10 @@ $text-color: #000;
|
||||||
--scrollbar-thumb-active-bg: var(--color-primary);
|
--scrollbar-thumb-active-bg: var(--color-primary);
|
||||||
--scrollbar-track-bg: transparent;
|
--scrollbar-track-bg: transparent;
|
||||||
|
|
||||||
/* Divider */
|
// /* Divider */
|
||||||
--divider: 1px solid rgba(0, 0, 0, 0.12);
|
// --divider: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
//
|
||||||
/* Animation :) */
|
// /* Animation :) */
|
||||||
--animation-duration: 0.3s;
|
// --animation-duration: 0.3s;
|
||||||
--animation-style: cubic-bezier(0.55, 0, 0.1, 1);
|
// --animation-style: cubic-bezier(0.55, 0, 0.1, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
@import '_reset';
|
@import '_reset';
|
||||||
@import '_vars';
|
@import '_vars';
|
||||||
@import '_icons';
|
|
||||||
@import '_gui';
|
@import '_gui';
|
||||||
@import 'component/_table';
|
@import 'component/_table';
|
||||||
@import 'component/_button.scss';
|
@import 'component/_button.scss';
|
||||||
|
@ -28,4 +27,5 @@
|
||||||
@import 'component/_radio.scss';
|
@import 'component/_radio.scss';
|
||||||
@import 'component/_shapeshift.scss';
|
@import 'component/_shapeshift.scss';
|
||||||
@import 'component/_spinner.scss';
|
@import 'component/_spinner.scss';
|
||||||
|
@import 'component/_nav.scss';
|
||||||
@import 'page/_show.scss';
|
@import 'page/_show.scss';
|
||||||
|
|
|
@ -3,34 +3,35 @@ TODO:
|
||||||
Determine [disabled] or .disabled
|
Determine [disabled] or .disabled
|
||||||
Add <a> support (probably just get rid of button prefix)
|
Add <a> support (probably just get rid of button prefix)
|
||||||
*/
|
*/
|
||||||
|
.btn {
|
||||||
button {
|
|
||||||
border: none;
|
border: none;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
font-weight: 600;
|
||||||
|
|
||||||
button:disabled.btn--disabled {
|
|
||||||
cursor: default;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn {
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 0 5px;
|
height: var(--btn-height);
|
||||||
|
min-width: var(--btn-height);
|
||||||
border-radius: var(--btn-radius);
|
border-radius: var(--btn-radius);
|
||||||
color: var(--btn-primary-color);
|
color: var(--btn-primary-color);
|
||||||
background-color: var(--btn-primary-bg);
|
background-color: var(--btn-primary-bg);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
fill: currentColor; // for proper icon color
|
||||||
|
|
||||||
&:hover:not(.btn--disabled) {
|
&:hover {
|
||||||
box-shadow: var(--box-shadow-layer);
|
box-shadow: var(--box-shadow-layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon + .btn__label {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn.btn--alt {
|
.btn.btn--alt {
|
||||||
color: var(--btn-alt-color);
|
color: var(--btn-alt-color);
|
||||||
background-color: #efefef;
|
background-color: var(--color-white);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #111;
|
color: #111;
|
||||||
|
@ -46,30 +47,71 @@ button.btn.btn--alt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn.btn--circle {
|
.btn.btn--inverse {
|
||||||
border-radius: 50%;
|
background-color: transparent;
|
||||||
transition: all 0.2s;
|
color: var(--btn-inverse-color);
|
||||||
|
|
||||||
&:hover:not([disabled]) {
|
&:hover {
|
||||||
border-radius: var(--btn-radius);
|
background-color: var(--btn-inverse-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn.btn--inverse {
|
.btn.btn--link {
|
||||||
box-shadow: none;
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--btn-primary-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn--link {
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
font-size: 0.9em;
|
font-size: 1em;
|
||||||
color: var(--btn-primary-bg); // this should be a different color
|
color: var(--btn-inverse-color);
|
||||||
|
border-radius: 0;
|
||||||
|
display: inline;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--no-style {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
color: inherit;
|
||||||
|
background-color: inherit;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--link.btn--no-underline:hover {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--link,
|
||||||
|
.btn--no-style {
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
.btn__label {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--disabled:disabled {
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&.btn--primary {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn--alt {
|
||||||
|
// Come back to me
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
.card {
|
.card {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-width: var(--card-max-width);
|
|
||||||
border-radius: var(--card-radius);
|
border-radius: var(--card-radius);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card--placeholder {
|
.card--section {
|
||||||
background-color: black;
|
flex-direction: column;
|
||||||
|
background-color: var(--color-white);
|
||||||
|
padding: $spacing-vertical;
|
||||||
|
margin-top: $spacing-vertical * 2/3;
|
||||||
|
box-shadow: var(--box-shadow-layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card--small {
|
.card--small {
|
||||||
width: var(--card-small-width);
|
width: var(--card-small-width);
|
||||||
min-height: var(--card-small-width);
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +51,8 @@
|
||||||
margin-top: $spacing-vertical * 1/3;
|
margin-top: $spacing-vertical * 1/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: regular .card__title for show page
|
// TODO: regular .card__title
|
||||||
|
// maybe not needed?
|
||||||
.card__title--small {
|
.card__title--small {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
@ -60,145 +64,24 @@
|
||||||
padding-top: $spacing-vertical * 1/3;
|
padding-top: $spacing-vertical * 1/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// .card__title-primary .meta {
|
.card-media__internal-links {
|
||||||
// white-space: nowrap;
|
position: absolute;
|
||||||
// overflow: hidden;
|
top: 5px;
|
||||||
// text-overflow: ellipsis;
|
right: 5px;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
|
|
||||||
//
|
.card__content {
|
||||||
// .card__actions {
|
margin-top: var(--card-margin);
|
||||||
// margin-top: var(--card-margin);
|
margin-bottom: var(--card-margin);
|
||||||
// margin-bottom: var(--card-margin);
|
}
|
||||||
// user-select: none;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__actions--bottom {
|
|
||||||
// margin-top: $spacing-vertical * 1/3;
|
|
||||||
// margin-bottom: $spacing-vertical * 1/3;
|
|
||||||
// border-top: var(--divider);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__actions--form-submit {
|
|
||||||
// margin-top: $spacing-vertical;
|
|
||||||
// margin-bottom: var(--card-margin);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__action--right {
|
|
||||||
// float: right;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__content {
|
|
||||||
// margin-top: var(--card-margin);
|
|
||||||
// margin-bottom: var(--card-margin);
|
|
||||||
// table:not(:last-child) {
|
|
||||||
// margin-bottom: var(--card-margin);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__actions--only-vertical {
|
|
||||||
// margin-left: 0;
|
|
||||||
// margin-right: 0;
|
|
||||||
// padding-left: 0;
|
|
||||||
// padding-right: 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__content--extra-vertical-space {
|
|
||||||
// margin: $spacing-vertical 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// $font-size-subtext-multiple: 0.82;
|
|
||||||
// .card__subtext {
|
|
||||||
// color: var(--color-meta-light);
|
|
||||||
// font-size: calc(var(--font-size-subtext-multiple) * 1em);
|
|
||||||
// margin-top: $spacing-vertical * 1/3;
|
|
||||||
// margin-bottom: $spacing-vertical * 1/3;
|
|
||||||
// }
|
|
||||||
// .card__subtext--allow-newlines {
|
|
||||||
// white-space: pre-wrap;
|
|
||||||
// }
|
|
||||||
// .card__subtext--two-lines {
|
|
||||||
// height: calc(
|
|
||||||
// var(--font-size) * var(--font-size-subtext-multiple) * var(--font-line-height) * 2
|
|
||||||
// ); /*this is so one line text still has the proper height*/
|
|
||||||
// }
|
|
||||||
// .card-overlay {
|
|
||||||
// position: absolute;
|
|
||||||
// left: 0px;
|
|
||||||
// right: 0px;
|
|
||||||
// top: 0px;
|
|
||||||
// bottom: 0px;
|
|
||||||
// padding: 20px;
|
|
||||||
// background-color: var(--color-dark-overlay);
|
|
||||||
// color: #fff;
|
|
||||||
// display: flex;
|
|
||||||
// align-items: center;
|
|
||||||
// font-weight: 600;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// .card__media--autothumb {
|
|
||||||
// position: relative;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.purple {
|
|
||||||
// background-color: #9c27b0;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.red {
|
|
||||||
// background-color: #e53935;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.pink {
|
|
||||||
// background-color: #e91e63;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.indigo {
|
|
||||||
// background-color: #3f51b5;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.blue {
|
|
||||||
// background-color: #2196f3;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.light-blue {
|
|
||||||
// background-color: #039be5;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.cyan {
|
|
||||||
// background-color: #00acc1;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.teal {
|
|
||||||
// background-color: #009688;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.green {
|
|
||||||
// background-color: #43a047;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.yellow {
|
|
||||||
// background-color: #ffeb3b;
|
|
||||||
// }
|
|
||||||
// .card__media--autothumb.orange {
|
|
||||||
// background-color: #ffa726;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card__media--autothumb .card__autothumb__text {
|
|
||||||
// font-size: 2em;
|
|
||||||
// width: 100%;
|
|
||||||
// color: #ffffff;
|
|
||||||
// text-align: center;
|
|
||||||
// position: absolute;
|
|
||||||
// top: 36%;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .card--form {
|
|
||||||
// width: calc(var(--input-width) + var(--card-padding) * 2);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
.card__actions {
|
||||||
// .card-series-submit {
|
margin-top: var(--card-margin);
|
||||||
// margin-left: auto;
|
display: flex;
|
||||||
// margin-right: auto;
|
}
|
||||||
// max-width: var(--card-max-width);
|
|
||||||
// padding: $spacing-vertical / 2;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
.card-row is used on the discover page
|
.card-row is used on the discover/subscriptions page
|
||||||
It is a list of cards that extend past the right edge of the screen
|
It is a list of cards that extend past the right edge of the screen
|
||||||
There are left/right arrows to scroll the cards and view hidden content
|
There are left/right arrows to scroll the cards and view hidden content
|
||||||
*/
|
*/
|
||||||
|
@ -208,6 +91,14 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: var(--card-small-width);
|
min-width: var(--card-small-width);
|
||||||
padding-top: $spacing-vertical;
|
padding-top: $spacing-vertical;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
padding-top: $spacing-vertical * 2/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
padding-bottom: $spacing-vertical * 2/3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-row__header {
|
.card-row__header {
|
||||||
|
@ -225,6 +116,10 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-row__scroll-btns {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.card-row__scrollhouse {
|
.card-row__scrollhouse {
|
||||||
padding-top: $spacing-vertical * 2/3;
|
padding-top: $spacing-vertical * 2/3;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -233,26 +128,10 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-left: $spacing-vertical * 2/3;
|
margin-left: $spacing-vertical * 2/3;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:last-of-type {
|
.card:last-of-type {
|
||||||
padding-right: $spacing-vertical * 2/3;
|
margin-right: $spacing-vertical * 2/3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if we keep doing things like this, we should add a real grid system, but I'm going to be a selective dick about it - Jeremy
|
|
||||||
*/
|
|
||||||
//TODO: css grid
|
|
||||||
// .card-grid {
|
|
||||||
// $margin-card-grid: $spacing-vertical * 2/3;
|
|
||||||
// display: flex;
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
// > .card {
|
|
||||||
// width: $width-page-constrained / 2 - $margin-card-grid / 2;
|
|
||||||
// flex-grow: 1;
|
|
||||||
// }
|
|
||||||
// > .card:nth-of-type(2n - 1):not(:last-child) {
|
|
||||||
// margin-right: $margin-card-grid;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,195 +1,40 @@
|
||||||
.form-row-submit {
|
.form-row {
|
||||||
margin-top: $spacing-vertical;
|
|
||||||
}
|
|
||||||
.form-row-submit--with-footer {
|
|
||||||
margin-bottom: $spacing-vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row-phone {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
.form-field__input-text {
|
.form-field:not(:first-of-type) {
|
||||||
margin-left: 5px;
|
padding-left: $spacing-vertical;
|
||||||
width: calc(0.85 * var(--input-width));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-row__label-row {
|
.form-field__wrapper {
|
||||||
margin-top: $spacing-vertical * 5/6;
|
display: flex;
|
||||||
margin-bottom: 0px;
|
padding: $spacing-vertical / 3 0;
|
||||||
line-height: 1;
|
|
||||||
font-size: calc(0.9 * var(--font-size));
|
|
||||||
}
|
|
||||||
.form-row__label-row--prefix {
|
|
||||||
float: left;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row--focus {
|
|
||||||
.form-field__label,
|
|
||||||
.form-field__prefix {
|
|
||||||
color: var(--color-primary) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 8px 0;
|
|
||||||
|
|
||||||
select {
|
|
||||||
transition: outline var(--transition-duration) var(--transition-type);
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
height: var(--select-height);
|
|
||||||
background: var(--select-bg);
|
|
||||||
color: var(--select-color);
|
|
||||||
&:focus {
|
|
||||||
outline: var(--input-border-size) solid var(--color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='radio'],
|
|
||||||
input[type='checkbox'] {
|
|
||||||
&:checked + .form-field__label {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='text'].input-copyable {
|
|
||||||
background: var(--input-bg);
|
|
||||||
color: var(--input-disabled-color);
|
|
||||||
line-height: 1;
|
|
||||||
padding-top: $spacing-vertical * 1/3;
|
|
||||||
padding-bottom: $spacing-vertical * 1/3;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
width: 100%;
|
|
||||||
font-family: 'Consolas', 'Lucida Console', 'Adobe Source Code Pro', monospace;
|
|
||||||
|
|
||||||
&.input-copyable--with-copy-btn {
|
|
||||||
width: 85%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[readonly] {
|
|
||||||
color: var(--input-disabled-color) !important;
|
|
||||||
border-bottom: 1px dashed var(--input-disabled-border-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[readonly]:focus {
|
|
||||||
background: var(--input-bg) !important;
|
|
||||||
border-bottom: 1px dashed var(--input-disabled-border-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea,
|
|
||||||
input[type='text'],
|
|
||||||
input[type='password'],
|
|
||||||
input[type='email'],
|
|
||||||
input[type='number'],
|
|
||||||
input[type='search'],
|
|
||||||
input[type='date'] {
|
|
||||||
background: var(--input-bg);
|
|
||||||
border-bottom: var(--input-border-size) solid var(--input-border-color);
|
|
||||||
caret-color: var(--color-primary);
|
|
||||||
color: var(--input-color);
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 0 1px 8px 1px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
transition: all var(--transition-duration) var(--transition-type);
|
|
||||||
|
|
||||||
&::-webkit-input-placeholder {
|
|
||||||
color: var(--input-placeholder-color);
|
|
||||||
opacity: var(--input-placeholder-opacity) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: var(--color-primary);
|
|
||||||
background: var(--input-active-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover:not(:focus) {
|
|
||||||
border-color: var(--input-hover-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.form-field__input--error {
|
|
||||||
border-color: var(--color-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.form-field__input--inline {
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
border-bottom-width: var(--input-border-size);
|
|
||||||
margin-left: 8px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
padding: 2px;
|
|
||||||
border: var(--input-border-size) solid var(--input-border-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.form-field--address {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field--SimpleMDE {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field__label,
|
|
||||||
.form-row__label {
|
|
||||||
color: var(--form-label-color);
|
|
||||||
&[for] {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row__label-row .form-field__label--error {
|
|
||||||
/*the row restriction is to prevent coloring checkboxes and radio labels*/
|
|
||||||
color: var(--color-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field__input-text {
|
|
||||||
width: var(--input-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field__prefix {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
.form-field__postfix {
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field__input-number {
|
|
||||||
width: 70px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field--textarea {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.form-field__input-textarea {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field__error,
|
|
||||||
.form-field__helper {
|
|
||||||
margin-top: $spacing-vertical * 1/3;
|
|
||||||
font-size: 0.8em;
|
|
||||||
transition: opacity var(--transition-duration) var(--transition-type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field__error {
|
.form-field__error {
|
||||||
color: var(--color-error);
|
color: var(--color-error);
|
||||||
}
|
}
|
||||||
.form-field__helper {
|
|
||||||
color: var(--color-help);
|
.form-field__label {
|
||||||
|
color: var(--color-grey-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field__input.form-field__input-SimpleMDE .CodeMirror-scroll {
|
.form-field__prefix {
|
||||||
height: auto;
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field__postfix {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not sure if I like these
|
||||||
|
// Maybe this should be in gui.scss?
|
||||||
|
.input--lbc-amount {
|
||||||
|
width: 75px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input--address {
|
||||||
|
width: 370px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,86 @@
|
||||||
#header {
|
.header {
|
||||||
|
grid-area: header;
|
||||||
|
display: flex;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: fixed;
|
justify-content: space-between;
|
||||||
top: 0;
|
padding: 0 $spacing-vertical;
|
||||||
left: 0;
|
align-items: center;
|
||||||
width: 100%;
|
justify-content: space-between;
|
||||||
height: var(--header-height);
|
height: 100%;
|
||||||
z-index: 3;
|
background-color: var(--color-bg);
|
||||||
box-sizing: border-box;
|
|
||||||
color: var(--header-color);
|
|
||||||
background-color: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header__actions-left {
|
|
||||||
display: flex;
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__actions-right {
|
.header__actions-right {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
padding-left: $spacing-vertical / 2;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__wunderbar {
|
.header__wunderbar {
|
||||||
|
z-index: 1;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
max-width: 325px;
|
|
||||||
min-width: 175px;
|
min-width: 175px;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px 5px;
|
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
position: relative;
|
||||||
|
|
||||||
.wunderbar__input {
|
.icon {
|
||||||
height: 50%;
|
position: absolute;
|
||||||
width: 100%;
|
left: 10px;
|
||||||
color: var(--search-color);
|
|
||||||
padding: 10px;
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
// TODO: focus style
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wunderbar__input {
|
||||||
|
height: var(--btn-height);
|
||||||
|
border-radius: var(--btn-radius);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 700px;
|
||||||
|
color: var(--search-color);
|
||||||
|
background-color: var(--search-bg-color);
|
||||||
|
box-shadow: var(--box-shadow-layer);
|
||||||
|
padding: 10px;
|
||||||
|
padding-left: 30px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
border-radius: 0;
|
||||||
|
border-bottom: 1px solid var(--color-grey);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wunderbar__menu {
|
||||||
|
max-width: 100px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.wunderbar__suggestion {
|
.wunderbar__suggestion {
|
||||||
padding: 5px;
|
padding: 10px;
|
||||||
background-color: var(--header-bg);
|
background-color: var(--header-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
border-top: 1px solid var(--color-divider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wunderbar__suggestion-label {
|
||||||
|
padding-left: $spacing-vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wunderbar__active-suggestion {
|
.wunderbar__active-suggestion {
|
||||||
background-color: #a3ffb0;
|
background-color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
|
51
src/renderer/scss/component/_nav.scss
Normal file
51
src/renderer/scss/component/_nav.scss
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
.nav {
|
||||||
|
grid-area: nav;
|
||||||
|
background-color: var(--color-nav-bg);
|
||||||
|
padding-top: 16px;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 40px;
|
||||||
|
border: solid 1px var(--color-grey);
|
||||||
|
margin: $spacing-vertical $spacing-vertical * 2/3 $spacing-vertical * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__actions-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__actions-history {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__primary {
|
||||||
|
padding-top: $spacing-vertical * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link {
|
||||||
|
padding: $spacing-vertical / 3 0 $spacing-vertical / 3 $spacing-vertical * 2/3;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--color-grey-dark);
|
||||||
|
|
||||||
|
// The hover effect should be on the li
|
||||||
|
// Need to have the button grow
|
||||||
|
& .btn:hover {
|
||||||
|
color: var(--color-black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link--active {
|
||||||
|
color: var(--color-black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__sub {
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__sub-link {
|
||||||
|
padding: 5px $spacing-vertical * 2/3;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
|
@ -1,17 +1,3 @@
|
||||||
// Can't think of a better way to do this
|
|
||||||
// The initial shapeshift form is 311px tall
|
|
||||||
// the .shapeshift__initial-wrapper class is only added when the form is being loaded
|
|
||||||
// Once the form is rendered, there is a very smooth transition because the height doesn't change
|
|
||||||
.shapeshift__wrapper.shapeshift__initial-wrapper {
|
|
||||||
min-height: 346px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shapeshift__content {
|
|
||||||
.spinner {
|
|
||||||
margin-top: $spacing-vertical * 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.shapeshift__tx-info {
|
.shapeshift__tx-info {
|
||||||
min-height: 63px;
|
min-height: 63px;
|
||||||
}
|
}
|
||||||
|
|
23
src/renderer/util/form-validation.js
Normal file
23
src/renderer/util/form-validation.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// @flow
|
||||||
|
/* eslint-disable prefer-default-export */
|
||||||
|
import { REGEXP_ADDRESS } from 'lbryURI';
|
||||||
|
|
||||||
|
type DraftTxValues = {
|
||||||
|
address: string,
|
||||||
|
// amount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateSendTx = (formValues: DraftTxValues) => {
|
||||||
|
const { address } = formValues
|
||||||
|
const errors = {};
|
||||||
|
|
||||||
|
// All we need to check is if the address is valid
|
||||||
|
// If values are missing, users wont' be able to submit the form
|
||||||
|
if (address && !REGEXP_ADDRESS.test(address)) {
|
||||||
|
errors.address = __('Not a valid LBRY address');
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* eslint-enable prefer-default-export */
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
Before Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7486,6 +7486,10 @@ react-dom@^16.2.0:
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
|
|
||||||
|
react-feather@^1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-1.0.8.tgz#69b13d5c729949f194d33201dee91bab67fa31a2"
|
||||||
|
|
||||||
react-markdown@^2.5.0:
|
react-markdown@^2.5.0:
|
||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-2.5.1.tgz#f7a6c26a3a5faf5d4c2098155d9775e826fd56ee"
|
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-2.5.1.tgz#f7a6c26a3a5faf5d4c2098155d9775e826fd56ee"
|
||||||
|
|
Loading…
Reference in a new issue