diff --git a/.flowconfig b/.flowconfig index 5f5dfd123..18c5bea0e 100644 --- a/.flowconfig +++ b/.flowconfig @@ -18,6 +18,7 @@ module.name_mapper='^types\(.*\)$' -> '/src/renderer/types\1' module.name_mapper='^component\(.*\)$' -> '/src/renderer/component\1' module.name_mapper='^page\(.*\)$' -> '/src/renderer/page\1' module.name_mapper='^lbry\(.*\)$' -> '/src/renderer/lbry\1' +module.name_mapper='^rewards\(.*\)$' -> '/src/renderer/rewards\1' module.name_mapper='^modal\(.*\)$' -> '/src/renderer/modal\1' [strict] diff --git a/flow-typed/react-feather.js b/flow-typed/react-feather.js new file mode 100644 index 000000000..c91a71f66 --- /dev/null +++ b/flow-typed/react-feather.js @@ -0,0 +1,3 @@ +declare module 'react-feather' { + declare module.exports: any; +} diff --git a/npm-debug.log.3540228334 b/npm-debug.log.3540228334 new file mode 100644 index 000000000..4dde20479 --- /dev/null +++ b/npm-debug.log.3540228334 @@ -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 +16 verbose exit [ 1, true ] diff --git a/npm-debug.log.3958211012 b/npm-debug.log.3958211012 new file mode 100644 index 000000000..4dde20479 --- /dev/null +++ b/npm-debug.log.3958211012 @@ -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 +16 verbose exit [ 1, true ] diff --git a/package.json b/package.json index 499b7e9d2..a7900270a 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "rc-progress": "^2.0.6", "react": "^16.2.0", "react-dom": "^16.2.0", + "react-feather": "^1.0.8", "react-markdown": "^2.5.0", "react-modal": "^3.1.7", "react-paginate": "^5.0.0", diff --git a/src/renderer/component/address/view.jsx b/src/renderer/component/address/view.jsx index 65ea563c0..1ed47a92b 100644 --- a/src/renderer/component/address/view.jsx +++ b/src/renderer/component/address/view.jsx @@ -1,52 +1,56 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +// @flow +import * as React from 'react'; import { clipboard } from 'electron'; -import Link from 'component/link'; -import classnames from 'classnames'; +import { FormField } from 'component/common/form'; +import Button from 'component/link'; -export default class Address extends React.PureComponent { - static propTypes = { - address: PropTypes.string, - }; +type Props = { + address: string, + doShowSnackBar: ({ message: string }) => void, +}; - constructor(props) { - super(props); +export default class Address extends React.PureComponent { + constructor() { + super(); - this._inputElem = null; + this.input = null; } + input: ?HTMLInputElement; + render() { - const { address, showCopyButton, doShowSnackBar } = this.props; + const { address, doShowSnackBar } = this.props; return ( -
- { - this._inputElem = input; - }} - onFocus={() => { - this._inputElem.select(); - }} - readOnly="readonly" - value={address || ''} - /> - {showCopyButton && ( - - ( + + { + this.input = input; + }} + onFocus={() => { + if (this.input) { + this.input.select(); + } + }} + /> +
+ /> ); } } diff --git a/src/renderer/component/app/index.js b/src/renderer/component/app/index.js index c7173f606..9589e9280 100644 --- a/src/renderer/component/app/index.js +++ b/src/renderer/component/app/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { selectPageTitle, @@ -10,7 +9,7 @@ import { doAlertError } from 'redux/actions/app'; import { doRecordScroll } from 'redux/actions/navigation'; import App from './view'; -const select = (state, props) => ({ +const select = state => ({ pageTitle: selectPageTitle(state), user: selectUser(state), currentStackIndex: selectHistoryIndex(state), diff --git a/src/renderer/component/app/view.jsx b/src/renderer/component/app/view.jsx index 240db13e2..9669a7795 100644 --- a/src/renderer/component/app/view.jsx +++ b/src/renderer/component/app/view.jsx @@ -1,11 +1,12 @@ // @flow import React from 'react'; import Router from 'component/router/index'; -import Header from 'component/header'; import Theme from 'component/theme'; import ModalRouter from 'modal/modalRouter'; import ReactModal from 'react-modal'; import throttle from 'util/throttle'; +import SideBar from 'component/sideBar'; +import Header from 'component/header'; type Props = { alertError: (string | {}) => void, @@ -33,7 +34,7 @@ class App extends React.PureComponent { } componentDidMount() { - const mainContent = document.getElementById('main-content'); + const mainContent = document.getElementById('content'); this.mainContent = mainContent; if (this.mainContent) { @@ -82,9 +83,14 @@ class App extends React.PureComponent { return (
-
- - +
+ +
+
+ + +
+
); } diff --git a/src/renderer/component/common.js b/src/renderer/component/common.js index 687c6e9da..e9f3c4342 100644 --- a/src/renderer/component/common.js +++ b/src/renderer/component/common.js @@ -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 ( - - {amountText} - {this.props.isEstimate ? ( - - * - - ) : null} - - ); - } -} - export class Thumbnail extends React.PureComponent { static propTypes = { src: PropTypes.string, diff --git a/src/renderer/component/common/category-list.jsx b/src/renderer/component/common/category-list.jsx index f46b2ab31..f8bf76f88 100644 --- a/src/renderer/component/common/category-list.jsx +++ b/src/renderer/component/common/category-list.jsx @@ -200,7 +200,7 @@ class CategoryList extends React.PureComponent {

{categoryLink ? (
{body}
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index b4f188ae8..b7a72bb99 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -78,6 +78,9 @@ class FileCard extends React.PureComponent { })} > +
+ +
@@ -87,8 +90,8 @@ class FileCard extends React.PureComponent {
- {isRewardContent && } - {fileInfo && } + {isRewardContent && } + {fileInfo && }
diff --git a/src/renderer/component/filePrice/view.jsx b/src/renderer/component/filePrice/view.jsx index 5a5947f14..7c4d6836d 100644 --- a/src/renderer/component/filePrice/view.jsx +++ b/src/renderer/component/filePrice/view.jsx @@ -1,35 +1,48 @@ +// @flow 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 { + static defaultProps = { + showFullPrice: false, + }; -class FilePrice extends React.PureComponent { componentWillMount() { this.fetchCost(this.props); } - componentWillReceiveProps(nextProps) { + componentWillReceiveProps(nextProps: Props) { this.fetchCost(nextProps); } - fetchCost(props) { + fetchCost = (props: Props) => { const { costInfo, fetchCostInfo, uri, fetching, claim } = props; if (costInfo === undefined && !fetching && claim) { fetchCostInfo(uri); } - } + }; 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) { - return ???; + return ???; } return ( this.handleSubmit(event)}>{this.props.children}; - } -} - -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 ( -
- {this.props.label && !renderLabelInFormField ? ( -
- -
- ) : ( - '' - )} - { - 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 ? ( -
{this.props.helper}
- ) : ( - '' - )} - {this.state.isError ? ( -
{this.state.errorMessage}
- ) : ( - '' - )} -
- ); - } -} - -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 = ( - - {'icon' in props ? : null} - {label ? {label} : null} - - ); - - return ( - - ); -}; diff --git a/src/renderer/component/formField/view.jsx b/src/renderer/component/formField/view.jsx index 960b08c17..0ce16256f 100644 --- a/src/renderer/component/formField/view.jsx +++ b/src/renderer/component/formField/view.jsx @@ -1,8 +1,10 @@ +// This file is going to die +/* eslint-disable */ import React from 'react'; import PropTypes from 'prop-types'; import FileSelector from 'component/file-selector.js'; 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'; const formFieldFileSelectorTypes = ['file', 'directory']; @@ -195,3 +197,4 @@ class FormField extends React.PureComponent { } export default FormField; +/* eslint-enable */ diff --git a/src/renderer/component/header/index.js b/src/renderer/component/header/index.js index f25257214..c66076ce6 100644 --- a/src/renderer/component/header/index.js +++ b/src/renderer/component/header/index.js @@ -1,25 +1,17 @@ -import React from 'react'; -import { formatCredits } from 'util/formatCredits'; import { connect } from 'react-redux'; -import { selectIsBackDisabled, selectIsForwardDisabled } from 'redux/selectors/navigation'; -import { selectBalance } from 'redux/selectors/wallet'; -import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; -import Header from './view'; +import { doNavigate } from 'redux/actions/navigation'; 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 => ({ - isBackDisabled: selectIsBackDisabled(state), - isForwardDisabled: selectIsForwardDisabled(state), isUpgradeAvailable: selectIsUpgradeAvailable(state), balance: formatCredits(selectBalance(state) || 0, 2), }); const perform = dispatch => ({ navigate: path => dispatch(doNavigate(path)), - back: () => dispatch(doHistoryBack()), - forward: () => dispatch(doHistoryForward()), - downloadUpgrade: () => dispatch(doDownloadUpgrade()), }); export default connect(select, perform)(Header); diff --git a/src/renderer/component/header/view.jsx b/src/renderer/component/header/view.jsx index f8fc83890..0926cfbd5 100644 --- a/src/renderer/component/header/view.jsx +++ b/src/renderer/component/header/view.jsx @@ -5,78 +5,34 @@ import WunderBar from 'component/wunderbar'; type Props = { balance: string, - back: any => void, - forward: any => void, - isBackDisabled: boolean, - isForwardDisabled: boolean, - isUpgradeAvailable: boolean, navigate: any => void, downloadUpgrade: any => void, + isUpgradeAvailable: boolean, }; -export const Header = (props: Props) => { - const { - balance, - back, - forward, - isBackDisabled, - isForwardDisabled, - isUpgradeAvailable, - navigate, - downloadUpgrade, - } = props; +const Header = (props: Props) => { + const { balance, isUpgradeAvailable, navigate, downloadUpgrade } = props; return ( -
-
+

{__('4) Proof via Chat')}

@@ -142,7 +144,7 @@ class UserVerify extends React.PureComponent { />
-
+
{__('Or, Skip It Entirely')}
@@ -157,9 +159,10 @@ class UserVerify extends React.PureComponent { navigate('/discover')} button="alt" label={__('Skip Rewards')} />
- + ); } } export default UserVerify; +/* eslint-enable */ diff --git a/src/renderer/component/walletAddress/view.jsx b/src/renderer/component/walletAddress/view.jsx index a062f0bb5..c666e13f4 100644 --- a/src/renderer/component/walletAddress/view.jsx +++ b/src/renderer/component/walletAddress/view.jsx @@ -1,8 +1,16 @@ +// @flow import React from 'react'; import Link from 'component/link'; 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 { componentWillMount() { this.props.checkAddressIsMine(this.props.receiveAddress); } @@ -11,21 +19,22 @@ class WalletAddress extends React.PureComponent { const { receiveAddress, getNewAddress, gettingNewAddress } = this.props; return ( -
+
-

{__('Receive Credits')}

+

{__('Receive Credits')}

+

+ {__('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).')} -

+
diff --git a/src/renderer/component/walletBalance/view.jsx b/src/renderer/component/walletBalance/view.jsx index 9c1b1f6cc..d3cc40c49 100644 --- a/src/renderer/component/walletBalance/view.jsx +++ b/src/renderer/component/walletBalance/view.jsx @@ -1,33 +1,19 @@ +// @flow import React from 'react'; -import Link from 'component/link'; -import { CreditAmount } from 'component/common'; +import CreditAmount from 'component/common/credit-amount'; -const WalletBalance = props => { - const { balance, navigate } = props; - /* -
- navigate("/backup")} - label={__("Backup Your Wallet")} - /> -
- */ +type Props = { + balance: number, +}; + +const WalletBalance = (props: Props) => { + const { balance } = props; return ( -
-
-

{__('Balance')}

-
+
+

{__('Balance')}

+ {__('You currently have')}
- {(balance || balance === 0) && } -
-
- - + {(balance || balance === 0) && }
); diff --git a/src/renderer/component/walletSend/index.js b/src/renderer/component/walletSend/index.js index fa005c0c4..2707dcc14 100644 --- a/src/renderer/component/walletSend/index.js +++ b/src/renderer/component/walletSend/index.js @@ -1,28 +1,9 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { - doSendDraftTransaction, - doSetDraftTransactionAmount, - doSetDraftTransactionAddress, -} from 'redux/actions/wallet'; -import { - selectDraftTransactionAmount, - selectDraftTransactionAddress, - selectDraftTransactionError, -} from 'redux/selectors/wallet'; - +import { doSendDraftTransaction } from 'redux/actions/wallet'; import WalletSend from './view'; -const select = state => ({ - address: selectDraftTransactionAddress(state), - amount: selectDraftTransactionAmount(state), - error: selectDraftTransactionError(state), -}); - const perform = dispatch => ({ - sendToAddress: () => dispatch(doSendDraftTransaction()), - setAmount: event => dispatch(doSetDraftTransactionAmount(event.target.value)), - setAddress: event => dispatch(doSetDraftTransactionAddress(event.target.value)), + sendToAddress: values => dispatch(doSendDraftTransaction(values)), }); -export default connect(select, perform)(WalletSend); +export default connect(null, perform)(WalletSend); diff --git a/src/renderer/component/walletSend/view.jsx b/src/renderer/component/walletSend/view.jsx index 7c51953b1..dce943b8a 100644 --- a/src/renderer/component/walletSend/view.jsx +++ b/src/renderer/component/walletSend/view.jsx @@ -1,55 +1,105 @@ +// @flow import React from 'react'; -import { Form, FormRow, Submit } from 'component/form'; -import { regexAddress } from 'lbryURI'; +import Button from 'component/link'; +import { Form, FormRow, FormField } from 'component/common/form'; +import { Formik } from 'formik'; +import { validateSendTx } from 'util/form-validation'; -class WalletSend extends React.PureComponent { - handleSubmit() { - const { amount, address, sendToAddress } = this.props; - const validSubmit = parseFloat(amount) > 0.0 && address; +type DraftTransaction = { + address: string, + amount: number | string, // So we can use a placeholder in the input +}; - if (validSubmit) { - sendToAddress(); - } +type Props = { + sendToAddress: DraftTransaction => void, +}; + +class WalletSend extends React.PureComponent { + constructor() { + super(); + + (this: any).handleSubmit = this.handleSubmit.bind(this); + } + + handleSubmit(values: DraftTransaction) { + const { sendToAddress } = this.props; + sendToAddress(values); } render() { - const { closeModal, modal, setAmount, setAddress, amount, address, error } = this.props; - return ( -
- -
-

{__('Send Credits')}

-
-
- -
-
- -
- 0.0) || !address} /> -
-
- +
+
+

{__('Send Credits')}

+
+
+ ( +
+ + ( + + )} + /> + + ( + + )} + /> + +
+
+
+ )} + /> +
); } diff --git a/src/renderer/component/walletSendTip/view.jsx b/src/renderer/component/walletSendTip/view.jsx index d3e106c19..29c47f33f 100644 --- a/src/renderer/component/walletSendTip/view.jsx +++ b/src/renderer/component/walletSendTip/view.jsx @@ -1,6 +1,8 @@ +// I'll come back to this +/* eslint-disable */ import React from 'react'; import Link from 'component/link'; -import { FormRow } from 'component/form'; +import { FormRow } from 'component/common/form'; import UriIndicator from 'component/uriIndicator'; class WalletSendTip extends React.PureComponent { @@ -67,3 +69,4 @@ class WalletSendTip extends React.PureComponent { } export default WalletSendTip; +/* eslint-enable */ diff --git a/src/renderer/component/wunderbar/internal/autocomplete.jsx b/src/renderer/component/wunderbar/internal/autocomplete.jsx index 5c70c8f06..f89114f06 100644 --- a/src/renderer/component/wunderbar/internal/autocomplete.jsx +++ b/src/renderer/component/wunderbar/internal/autocomplete.jsx @@ -466,6 +466,7 @@ export default class Autocomplete extends React.Component { const menu = this.props.renderMenu(items, this.props.value, style); return React.cloneElement(menu, { ref: e => (this.refs.menu = e), + className: 'wunderbar__menu', // Ignore blur to prevent menu from de-rendering before we can process click onMouseEnter: () => this.setIgnoreBlur(true), onMouseLeave: () => this.setIgnoreBlur(false), diff --git a/src/renderer/component/wunderbar/view.jsx b/src/renderer/component/wunderbar/view.jsx index 2c1bc4a6f..0abdd43dc 100644 --- a/src/renderer/component/wunderbar/view.jsx +++ b/src/renderer/component/wunderbar/view.jsx @@ -2,6 +2,8 @@ import React from 'react'; import { normalizeURI } from 'lbryURI'; import classnames from 'classnames'; +import throttle from 'util/throttle'; +import Icon from 'component/common/icon'; import Autocomplete from './internal/autocomplete'; type Props = { @@ -16,29 +18,22 @@ type Props = { }; class WunderBar extends React.PureComponent { - constructor() { - super(); + constructor(props: Props) { + super(props); + (this: any).handleSubmit = this.handleSubmit.bind(this); (this: any).handleChange = this.handleChange.bind(this); (this: any).focus = this.focus.bind(this); + (this: any).throttledGetSearchSuggestions = throttle(this.props.getSearchSuggestions, 1000); this.input = undefined; } - input: ?HTMLInputElement; - handleChange(e: SyntheticInputEvent<*>) { const { updateSearchQuery, getSearchSuggestions } = this.props; const { value } = e.target; updateSearchQuery(value); - getSearchSuggestions(value); - } - - focus() { - const { input } = this; - if (input) { - input.focus(); - } + this.throttledGetSearchSuggestions(value); } handleSubmit(value: string) { @@ -70,6 +65,16 @@ class WunderBar extends React.PureComponent { } } + focus() { + const { input } = this; + if (input) { + input.focus(); + } + } + + input: ?HTMLInputElement; + throttledGetSearchSuggestions: string => void; + render() { const { searchQuery, isActive, address, suggestions } = this.props; @@ -83,12 +88,13 @@ class WunderBar extends React.PureComponent { 'header__wunderbar--active': isActive, })} > + { this.input = ref; }} - wrapperStyle={{ flex: 1, minHeight: 0 }} + wrapperStyle={{ flex: 1 }} value={wunderbarValue} items={suggestions} getItemValue={item => item.value} @@ -108,7 +114,8 @@ class WunderBar extends React.PureComponent { 'wunderbar__active-suggestion': isHighlighted, })} > - {item.label} + + {item.label}
)} /> diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index 9599d61c9..66655e010 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -37,8 +37,6 @@ export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED'; export const UPDATE_BALANCE = 'UPDATE_BALANCE'; 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 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_COMPLETED = 'SEND_TRANSACTION_COMPLETED'; export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED'; diff --git a/src/renderer/constants/icons.js b/src/renderer/constants/icons.js index 728a8f196..8d91aa70c 100644 --- a/src/renderer/constants/icons.js +++ b/src/renderer/constants/icons.js @@ -1,5 +1,5 @@ -export const FEATURED = 'rocket'; -export const LOCAL = 'folder'; +export const FEATURED = 'Award'; +export const LOCAL = 'Folder'; export const FILE = 'file'; export const HISTORY = 'history'; export const HELP_CIRCLE = 'question-circle'; diff --git a/src/renderer/modal/modalCreditIntro/view.jsx b/src/renderer/modal/modalCreditIntro/view.jsx index 572e6b59d..7b2144060 100644 --- a/src/renderer/modal/modalCreditIntro/view.jsx +++ b/src/renderer/modal/modalCreditIntro/view.jsx @@ -1,6 +1,9 @@ +// I'll come back to this +/* esline-disable */ import React from 'react'; 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'; const ModalCreditIntro = props => { @@ -46,3 +49,4 @@ const ModalCreditIntro = props => { }; export default ModalCreditIntro; +/* esline-enable */ diff --git a/src/renderer/modal/modalFirstReward/view.jsx b/src/renderer/modal/modalFirstReward/view.jsx index b50625b58..5d86e3636 100644 --- a/src/renderer/modal/modalFirstReward/view.jsx +++ b/src/renderer/modal/modalFirstReward/view.jsx @@ -1,6 +1,8 @@ +// I"ll come back to This +/* esline-disable */ import React from 'react'; import { Modal } from 'modal/modal'; -import { CreditAmount } from 'component/common'; +import CreditAmount from 'component/common/credit-amount'; class ModalFirstReward extends React.PureComponent { render() { @@ -42,3 +44,4 @@ class ModalFirstReward extends React.PureComponent { } export default ModalFirstReward; +/* eslint-enable */ diff --git a/src/renderer/page/auth/view.jsx b/src/renderer/page/auth/view.jsx index 423ce8597..f0b6598e0 100644 --- a/src/renderer/page/auth/view.jsx +++ b/src/renderer/page/auth/view.jsx @@ -4,6 +4,7 @@ import Link from 'component/link'; import UserEmailNew from 'component/userEmailNew'; import UserEmailVerify from 'component/userEmailVerify'; import UserVerify from 'component/userVerify'; +import Page from 'component/page'; export class AuthPage extends React.PureComponent { componentWillMount() { @@ -58,25 +59,27 @@ export class AuthPage extends React.PureComponent { const { email, user, isPending, navigate } = this.props; const [innerContent, useTemplate] = this.renderMain(); - return useTemplate ? ( -
-
-
-

{this.getTitle()}

-
-
{innerContent}
-
-
- {`${__( - 'This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards.' - )} `} - navigate('/discover')} label={__('Return home')} />. + return ( + + {useTemplate ? ( +
+
+

{this.getTitle()}

-
-
-
- ) : ( - innerContent +
{innerContent}
+
+
+ {`${__( + 'This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards.' + )} `} + navigate('/discover')} label={__('Return home')} />. +
+
+
+ ) : ( + innerContent + )} + ); } } diff --git a/src/renderer/page/backup/view.jsx b/src/renderer/page/backup/view.jsx index bcb0a0667..a0581212b 100644 --- a/src/renderer/page/backup/view.jsx +++ b/src/renderer/page/backup/view.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import SubHeader from 'component/subHeader'; import Link from 'component/link'; +import Page from 'component/page'; class BackupPage extends React.PureComponent { render() { @@ -16,9 +16,8 @@ class BackupPage extends React.PureComponent { } return ( -
- -
+ +

{__('Backup Your LBRY Credits')}

@@ -57,7 +56,7 @@ class BackupPage extends React.PureComponent {

-
+ ); } } diff --git a/src/renderer/page/fileListDownloaded/view.jsx b/src/renderer/page/fileListDownloaded/view.jsx index f6be896ef..c187fa7c6 100644 --- a/src/renderer/page/fileListDownloaded/view.jsx +++ b/src/renderer/page/fileListDownloaded/view.jsx @@ -3,7 +3,6 @@ import Link from 'component/link'; import { FileTile } from 'component/fileTile'; import { BusyMessage, Thumbnail } from 'component/common.js'; import FileList from 'component/fileList'; -import SubHeader from 'component/subHeader'; class FileListDownloaded extends React.PureComponent { componentWillMount() { @@ -31,12 +30,7 @@ class FileListDownloaded extends React.PureComponent { ); } - return ( -
- - {content} -
- ); + return
{content}
; } } diff --git a/src/renderer/page/fileListPublished/view.jsx b/src/renderer/page/fileListPublished/view.jsx index de19dd1dd..cf0f7abbe 100644 --- a/src/renderer/page/fileListPublished/view.jsx +++ b/src/renderer/page/fileListPublished/view.jsx @@ -3,7 +3,6 @@ import Link from 'component/link'; import FileTile from 'component/fileTile'; import { BusyMessage, Thumbnail } from 'component/common.js'; import FileList from 'component/fileList'; -import SubHeader from 'component/subHeader'; class FileListPublished extends React.PureComponent { componentWillMount() { @@ -41,12 +40,7 @@ class FileListPublished extends React.PureComponent { ); } - return ( -
- - {content} -
- ); + return
{content}
; } } diff --git a/src/renderer/page/getCredits/view.jsx b/src/renderer/page/getCredits/view.jsx index b8e670443..ebc16acfe 100644 --- a/src/renderer/page/getCredits/view.jsx +++ b/src/renderer/page/getCredits/view.jsx @@ -1,25 +1,24 @@ import React from 'react'; -import SubHeader from 'component/subHeader'; import Link from 'component/link'; import RewardSummary from 'component/rewardSummary'; import ShapeShift from 'component/shapeShift'; +import Page from 'component/page'; const GetCreditsPage = props => ( -
- + -
+
-

{__('From External Wallet')}

+

{__('From External Wallet')}

- +
-
+
-

{__('More ways to get LBRY Credits')}

+

{__('More ways to get LBRY Credits')}

@@ -29,10 +28,10 @@ const GetCreditsPage = props => (

- +
-
+ ); export default GetCreditsPage; diff --git a/src/renderer/page/help/view.jsx b/src/renderer/page/help/view.jsx index c2590fd81..f0b0046f7 100644 --- a/src/renderer/page/help/view.jsx +++ b/src/renderer/page/help/view.jsx @@ -2,9 +2,9 @@ import React from 'react'; import lbry from 'lbry.js'; import Link from 'component/link'; -import SubHeader from 'component/subHeader'; import { BusyMessage } from 'component/common'; import Icon from 'component/common/icon'; +import Page from 'component/page'; class HelpPage extends React.PureComponent { constructor(props) { @@ -70,8 +70,7 @@ class HelpPage extends React.PureComponent { } return ( -
- +

{__('Read the FAQ')}

@@ -210,7 +209,7 @@ class HelpPage extends React.PureComponent { )}
-
+ ); } } diff --git a/src/renderer/page/invite/view.jsx b/src/renderer/page/invite/view.jsx index 4199066a5..946ca67c2 100644 --- a/src/renderer/page/invite/view.jsx +++ b/src/renderer/page/invite/view.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { BusyMessage } from 'component/common'; -import SubHeader from 'component/subHeader'; import InviteNew from 'component/inviteNew'; import InviteList from 'component/inviteList'; @@ -14,7 +13,6 @@ class InvitePage extends React.PureComponent { return (
- {isPending && } {!isPending && isFailed && {__('Failed to retrieve invite status.')}} diff --git a/src/renderer/page/report.js b/src/renderer/page/report.js index 617ca6d3d..48f433960 100644 --- a/src/renderer/page/report.js +++ b/src/renderer/page/report.js @@ -1,6 +1,6 @@ import React from 'react'; import Link from 'component/link'; -import { FormRow } from 'component/form'; +import { FormRow } from 'component/common/form'; import { doShowSnackBar } from 'redux/actions/app'; import lbry from '../lbry.js'; diff --git a/src/renderer/page/rewards/view.jsx b/src/renderer/page/rewards/view.jsx index 258d76052..8c5a92a10 100644 --- a/src/renderer/page/rewards/view.jsx +++ b/src/renderer/page/rewards/view.jsx @@ -2,8 +2,8 @@ import React from 'react'; import { BusyMessage } from 'component/common'; import RewardListClaimed from 'component/rewardListClaimed'; import RewardTile from 'component/rewardTile'; -import SubHeader from 'component/subHeader'; import Link from 'component/link'; +import Page from 'component/page'; class RewardsPage extends React.PureComponent { /* @@ -34,7 +34,7 @@ class RewardsPage extends React.PureComponent { if (user && !user.is_reward_approved) { if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) { return ( -
+

{__('Humans Only')}

@@ -102,6 +102,7 @@ class RewardsPage extends React.PureComponent { ); } return ( + // TODO: come back to me and actually implement a grid
{rewards.map(reward => )}
@@ -110,12 +111,11 @@ class RewardsPage extends React.PureComponent { render() { return ( -
- + {this.renderPageHeader()} {this.renderUnclaimedRewards()} {} -
+ ); } } diff --git a/src/renderer/page/sendCredits/view.jsx b/src/renderer/page/sendCredits/view.jsx index 07df1fd6f..82b038068 100644 --- a/src/renderer/page/sendCredits/view.jsx +++ b/src/renderer/page/sendCredits/view.jsx @@ -1,14 +1,13 @@ import React from 'react'; -import SubHeader from 'component/subHeader'; import WalletSend from 'component/walletSend'; import WalletAddress from 'component/walletAddress'; +import Page from 'component/page'; const SendReceivePage = props => ( -
- + -
+ ); export default SendReceivePage; diff --git a/src/renderer/page/settings/view.jsx b/src/renderer/page/settings/view.jsx index 0b061e87a..84c7a80bf 100644 --- a/src/renderer/page/settings/view.jsx +++ b/src/renderer/page/settings/view.jsx @@ -1,11 +1,11 @@ import React from 'react'; import FormField from 'component/formField'; -import { FormRow } from 'component/form.js'; -import SubHeader from 'component/subHeader'; +import { FormRow } from 'component/common/form'; import * as settings from 'constants/settings'; import lbry from 'lbry.js'; import Link from 'component/link'; import FormFieldPrice from 'component/formFieldPrice'; +import Page from 'component/page'; class SettingsPage extends React.PureComponent { constructor(props) { @@ -144,8 +144,7 @@ class SettingsPage extends React.PureComponent { ); } return ( -
- + {/*
@@ -348,7 +347,7 @@ class SettingsPage extends React.PureComponent {

-
+ ); } } diff --git a/src/renderer/page/subscriptions/view.jsx b/src/renderer/page/subscriptions/view.jsx index 3c4e6e61a..73fd45f83 100644 --- a/src/renderer/page/subscriptions/view.jsx +++ b/src/renderer/page/subscriptions/view.jsx @@ -1,6 +1,6 @@ // @flow import React from 'react'; -import SubHeader from 'component/subHeader'; +import Page from 'component/page'; import { BusyMessage } from 'component/common'; import CategoryList from 'component/common/category-list'; import type { Subscription } from 'redux/reducers/subscriptions'; @@ -61,16 +61,10 @@ export default class extends React.PureComponent { (subscriptions.length !== savedSubscriptions.length || someClaimsNotLoaded); return ( -
- + {!savedSubscriptions.length && ( {__("You haven't subscribed to any channels yet")} )} - {fetchingSubscriptions && ( -
- -
- )} {!!savedSubscriptions.length && (
{!!subscriptions.length && @@ -93,7 +87,7 @@ export default class extends React.PureComponent { })}
)} -
+ ); } } diff --git a/src/renderer/page/transactionHistory/view.jsx b/src/renderer/page/transactionHistory/view.jsx index 562da6aa5..06fc2ef8f 100644 --- a/src/renderer/page/transactionHistory/view.jsx +++ b/src/renderer/page/transactionHistory/view.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { BusyMessage } from 'component/common'; -import SubHeader from 'component/subHeader'; import TransactionList from 'component/transactionList'; +import Page from 'component/page'; class TransactionHistoryPage extends React.PureComponent { componentWillMount() { @@ -12,9 +12,8 @@ class TransactionHistoryPage extends React.PureComponent { const { fetchingTransactions, transactions } = this.props; return ( -
- -
+ +
-
+ ); } } diff --git a/src/renderer/page/wallet/view.jsx b/src/renderer/page/wallet/view.jsx index b98bb80f9..683ba03e7 100644 --- a/src/renderer/page/wallet/view.jsx +++ b/src/renderer/page/wallet/view.jsx @@ -1,18 +1,19 @@ import React from 'react'; -import SubHeader from 'component/subHeader'; import WalletBalance from 'component/walletBalance'; import RewardSummary from 'component/rewardSummary'; import TransactionListRecent from 'component/transactionListRecent'; +import WalletAddress from 'component/walletAddress'; +import Page from 'component/page'; -const WalletPage = props => ( -
- -
+const WalletPage = () => ( + +
+ -
+ ); export default WalletPage; diff --git a/src/renderer/redux/actions/search.js b/src/renderer/redux/actions/search.js index ca8c4426b..54eda46ee 100644 --- a/src/renderer/redux/actions/search.js +++ b/src/renderer/redux/actions/search.js @@ -1,5 +1,5 @@ import * as ACTIONS from 'constants/action_types'; -import { normalizeURI } from 'lbryURI'; +import { normalizeURI, buildURI } from 'lbryURI'; import { doResolveUri } from 'redux/actions/content'; import { doNavigate } from 'redux/actions/navigation'; import { selectCurrentPage } from 'redux/selectors/navigation'; @@ -89,10 +89,17 @@ export const getSearchSuggestions = value => dispatch => { fetch(`https://lighthouse.lbry.io/autocomplete?s=${searchValue}`) .then(handleSearchApiResponse) .then(suggestions => { - const formattedSuggestions = suggestions.slice(0, 5).map(suggestion => ({ - label: suggestion, - value: suggestion, - })); + const formattedSuggestions = suggestions.slice(0, 5).map(suggestion => { + // This will need to be more robust when the api starts returning lbry uris + const isChannel = suggestion.startsWith('@'); + const suggestionObj = { + value: suggestion, + label: isChannel ? suggestion.slice(1) : suggestion, + icon: isChannel ? 'AtSign' : 'Search', + }; + + return suggestionObj; + }); // Should we add lbry://{query} as the first 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 { const uri = normalizeURI(value); formattedSuggestions.unshift( - { label: uri, value: uri }, - { label: searchLabel, value: `${value}?search` } + { label: uri, value: uri, icon: 'Compass' }, + { label: searchLabel, value: `${value}?search`, icon: 'Search' } ); } catch (e) { if (value) { - formattedSuggestions.unshift({ label: searchLabel, value }); + formattedSuggestions.unshift({ label: searchLabel, value, icon: 'Search' }); } } diff --git a/src/renderer/redux/actions/wallet.js b/src/renderer/redux/actions/wallet.js index df2faeb8d..35c04d50e 100644 --- a/src/renderer/redux/actions/wallet.js +++ b/src/renderer/redux/actions/wallet.js @@ -5,8 +5,6 @@ import { doOpenModal, doShowSnackBar } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { selectBalance, - selectDraftTransaction, - selectDraftTransactionAmount, } from 'redux/selectors/wallet'; export function doUpdateBalance() { @@ -89,12 +87,10 @@ export function doCheckAddressIsMine(address) { }; } -export function doSendDraftTransaction() { +export function doSendDraftTransaction({ amount, address }) { return (dispatch, getState) => { const state = getState(); - const draftTx = selectDraftTransaction(state); const balance = selectBalance(state); - const amount = selectDraftTransactionAmount(state); if (balance - amount <= 0) { dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS)); @@ -135,26 +131,12 @@ export function doSendDraftTransaction() { }; Lbry.wallet_send({ - amount: draftTx.amount, - address: draftTx.address, + amount, + address, }).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) { return (dispatch, getState) => { const state = getState(); diff --git a/src/renderer/redux/reducers/wallet.js b/src/renderer/redux/reducers/wallet.js index bc5761c6c..864076d66 100644 --- a/src/renderer/redux/reducers/wallet.js +++ b/src/renderer/redux/reducers/wallet.js @@ -2,10 +2,6 @@ import * as ACTIONS from 'constants/action_types'; const reducers = {}; const receiveAddress = localStorage.getItem('receiveAddress'); -const buildDraftTransaction = () => ({ - amount: undefined, - address: undefined, -}); const defaultState = { balance: undefined, @@ -14,8 +10,8 @@ const defaultState = { fetchingTransactions: false, receiveAddress, gettingNewAddress: false, - draftTransaction: buildDraftTransaction(), sendingSupport: false, + sendingTx: false }; reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = state => @@ -68,51 +64,21 @@ reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED] = state => 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 => { - const newDraftTransaction = Object.assign({}, state.draftTransaction, { - sending: true, - }); - return Object.assign({}, state, { - draftTransaction: newDraftTransaction, + sendingTx: true, }); }; reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = state => Object.assign({}, state, { - draftTransaction: buildDraftTransaction(), + sendingTx: false, }); reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state, action) => { - const newDraftTransaction = Object.assign({}, state.draftTransaction, { - sending: false, - error: action.data.error, - }); - return Object.assign({}, state, { - draftTransaction: newDraftTransaction, + sendingTx: false, + error: action.data.error }); }; diff --git a/src/renderer/redux/selectors/navigation.js b/src/renderer/redux/selectors/navigation.js index 31cc7306d..d24430fc3 100644 --- a/src/renderer/redux/selectors/navigation.js +++ b/src/renderer/redux/selectors/navigation.js @@ -1,6 +1,5 @@ import { createSelector } from 'reselect'; -import { parseQueryParams, toQueryString } from 'util/query_params'; -import { normalizeURI } from 'lbryURI'; +import { parseQueryParams } from 'util/query_params'; export const selectState = state => state.navigation || {}; @@ -22,72 +21,6 @@ export const selectCurrentParams = createSelector(selectCurrentPath, path => { export const makeSelectCurrentParam = param => 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 selectIsBackDisabled = createSelector(selectState, state => state.index === 0); @@ -97,6 +30,8 @@ export const selectIsForwardDisabled = createSelector( 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 selectHistoryStack = createSelector(selectState, state => state.stack); @@ -106,3 +41,126 @@ export const selectActiveHistoryEntry = createSelector( selectState, 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; + } +); diff --git a/src/renderer/redux/selectors/wallet.js b/src/renderer/redux/selectors/wallet.js index bddedb8f4..d5fd9326d 100644 --- a/src/renderer/redux/selectors/wallet.js +++ b/src/renderer/redux/selectors/wallet.js @@ -96,26 +96,6 @@ export const selectGettingNewAddress = createSelector( 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 makeSelectBlockDate = block => diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss index db1eedf76..c438ffb35 100644 --- a/src/renderer/scss/_gui.scss +++ b/src/renderer/scss/_gui.scss @@ -1,18 +1,25 @@ // Generic html styles used accross the App // component specific styling should go in the component scss file -// The actual fonts used will change ex: medium vs regular @font-face { font-family: 'Metropolis'; font-weight: normal; font-style: normal; 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'); } @font-face { font-family: 'Metropolis'; - font-weight: 600; + font-weight: 700; font-style: normal; text-rendering: optimizeLegibility; src: url('../../../static/font/metropolis/Metropolis-SemiBold.woff2') format('woff2'); @@ -63,19 +70,6 @@ h5 { font-size: 1.1em; } -sup, -sub { - vertical-align: baseline; - position: relative; -} - -sup { - top: -0.4em; -} -sub { - top: 0.4em; -} - code { font: 0.8em Consolas, 'Lucida Console', 'Source Sans', monospace; background-color: var(--color-bg-alt); @@ -83,35 +77,61 @@ code { // Without this buttons don't have the Metropolis font button { + font-weight: inherit; font-family: inherit; } -#window { - height: 100%; - overflow: hidden; +ul { + list-style-type: none; } -#main-content { - height: 100%; - overflow-y: auto; - position: absolute; - left: 0px; - right: 0px; - // don't use {bottom/top} here - // they cause flashes of un-rendered content when scrolling - margin-top: var(--header-height); - // TODO: fix this scrollbar extends beyond screen at the bottom - padding-bottom: var(--header-height); +input { + width: 100%; + cursor: text; + border-bottom: var(--input-border-size) solid var(--input-border-color); + color: var(--input-color); + line-height: 1; + + &.input-copyable { + background: var(--input-bg); + color: var(--input-disabled-color); + 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); } +/* + Page content +*/ +.content { + grid-area: content; + overflow: auto; +} + .main { - padding: 0 $spacing-vertical * 2/3; + padding: 0 $spacing-vertical $spacing-vertical; + max-width: 900px; + margin: auto; } .main--no-padding { padding-left: 0; padding-right: 0; + margin: 0; + max-width: none; } .page__header { @@ -124,26 +144,66 @@ button { 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 */ *::selection { background: var(--text-selection-bg); color: var(--text-selection-color); } -.credit-amount--indicator { - font-weight: 500; - color: var(--color-money); -} - -.credit-amount--fee { - font-size: 0.9em; - color: var(--color-meta-light); -} - -.credit-amount--bold { +.credit-amount { + padding: 5px; + border-radius: 5px; 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 { display: none; } diff --git a/src/renderer/scss/_icons.scss b/src/renderer/scss/_icons.scss deleted file mode 100644 index 7797614a8..000000000 --- a/src/renderer/scss/_icons.scss +++ /dev/null @@ -1,1688 +0,0 @@ -@font-face { - font-family: 'FontAwesome'; - src: url('../../../static/font/fontawesome-webfont.eot?v=4.7.0'); - src: url('../../../static/font/fontawesome-webfont.eot?#iefix&v=4.7.0') - format('embedded-opentype'), - url('../../../static/font/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), - url('../../../static/font/fontawesome-webfont.woff?v=4.7.0') format('woff'), - url('../../../static/font/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), - url('../../../static/font/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class*='icon-'] { - display: inline-block; - text-align: center; - font-family: 'FontAwesome'; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - speak: none; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-size: inherit; - text-rendering: auto; - transform: translate(0, 0); -} - -.icon--fixed-width { - /* This borrowed is from a component of Font Awesome we're not using, maybe add it? */ - width: (18em / 14); - text-align: center; -} - -.icon--padded { - padding: 0 3px; -} - -/* Adjustments for icon size and alignment */ -.icon-rocket { - color: orangered; - font-size: 0.95em; - position: relative; - top: -0.04em; - margin-left: 0.025em; - margin-right: 0.025em; -} - -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen - readers do not read off random characters that represent icons */ -.icon-glass:before { - content: '\f000'; -} -.icon-music:before { - content: '\f001'; -} -.icon-search:before { - content: '\f002'; -} -.icon-envelope-o:before { - content: '\f003'; -} -.icon-heart:before { - content: '\f004'; -} -.icon-star:before { - content: '\f005'; -} -.icon-star-o:before { - content: '\f006'; -} -.icon-user:before { - content: '\f007'; -} -.icon-film:before { - content: '\f008'; -} -.icon-th-large:before { - content: '\f009'; -} -.icon-th:before { - content: '\f00a'; -} -.icon-th-list:before { - content: '\f00b'; -} -.icon-check:before { - content: '\f00c'; -} -.icon-remove:before, -.icon-close:before, -.icon-times:before { - content: '\f00d'; -} -.icon-search-plus:before { - content: '\f00e'; -} -.icon-search-minus:before { - content: '\f010'; -} -.icon-power-off:before { - content: '\f011'; -} -.icon-signal:before { - content: '\f012'; -} -.icon-gear:before, -.icon-cog:before { - content: '\f013'; -} -.icon-trash-o:before { - content: '\f014'; -} -.icon-home:before { - content: '\f015'; -} -.icon-file-o:before { - content: '\f016'; -} -.icon-clock-o:before { - content: '\f017'; -} -.icon-road:before { - content: '\f018'; -} -.icon-download:before { - content: '\f019'; -} -.icon-arrow-circle-o-down:before { - content: '\f01a'; -} -.icon-arrow-circle-o-up:before { - content: '\f01b'; -} -.icon-inbox:before { - content: '\f01c'; -} -.icon-play-circle-o:before { - content: '\f01d'; -} -.icon-rotate-right:before, -.icon-repeat:before { - content: '\f01e'; -} -.icon-refresh:before { - content: '\f021'; -} -.icon-list-alt:before { - content: '\f022'; -} -.icon-lock:before { - content: '\f023'; -} -.icon-flag:before { - content: '\f024'; -} -.icon-headphones:before { - content: '\f025'; -} -.icon-volume-off:before { - content: '\f026'; -} -.icon-volume-down:before { - content: '\f027'; -} -.icon-volume-up:before { - content: '\f028'; -} -.icon-qrcode:before { - content: '\f029'; -} -.icon-barcode:before { - content: '\f02a'; -} -.icon-tag:before { - content: '\f02b'; -} -.icon-tags:before { - content: '\f02c'; -} -.icon-book:before { - content: '\f02d'; -} -.icon-bookmark:before { - content: '\f02e'; -} -.icon-print:before { - content: '\f02f'; -} -.icon-camera:before { - content: '\f030'; -} -.icon-font:before { - content: '\f031'; -} -.icon-bold:before { - content: '\f032'; -} -.icon-italic:before { - content: '\f033'; -} -.icon-text-height:before { - content: '\f034'; -} -.icon-text-width:before { - content: '\f035'; -} -.icon-align-left:before { - content: '\f036'; -} -.icon-align-center:before { - content: '\f037'; -} -.icon-align-right:before { - content: '\f038'; -} -.icon-align-justify:before { - content: '\f039'; -} -.icon-list:before { - content: '\f03a'; -} -.icon-dedent:before, -.icon-outdent:before { - content: '\f03b'; -} -.icon-indent:before { - content: '\f03c'; -} -.icon-video-camera:before { - content: '\f03d'; -} -.icon-photo:before, -.icon-image:before, -.icon-picture-o:before { - content: '\f03e'; -} -.icon-pencil:before { - content: '\f040'; -} -.icon-map-marker:before { - content: '\f041'; -} -.icon-adjust:before { - content: '\f042'; -} -.icon-tint:before { - content: '\f043'; -} -.icon-edit:before, -.icon-pencil-square-o:before { - content: '\f044'; -} -.icon-share-square-o:before { - content: '\f045'; -} -.icon-check-square-o:before { - content: '\f046'; -} -.icon-arrows:before { - content: '\f047'; -} -.icon-step-backward:before { - content: '\f048'; -} -.icon-fast-backward:before { - content: '\f049'; -} -.icon-backward:before { - content: '\f04a'; -} -.icon-play:before { - content: '\f04b'; -} -.icon-pause:before { - content: '\f04c'; -} -.icon-stop:before { - content: '\f04d'; -} -.icon-forward:before { - content: '\f04e'; -} -.icon-fast-forward:before { - content: '\f050'; -} -.icon-step-forward:before { - content: '\f051'; -} -.icon-eject:before { - content: '\f052'; -} -.icon-chevron-left:before { - content: '\f053'; -} -.icon-chevron-right:before { - content: '\f054'; -} -.icon-plus-circle:before { - content: '\f055'; -} -.icon-minus-circle:before { - content: '\f056'; -} -.icon-times-circle:before { - content: '\f057'; -} -.icon-check-circle:before { - content: '\f058'; -} -.icon-question-circle:before { - content: '\f059'; -} -.icon-info-circle:before { - content: '\f05a'; -} -.icon-crosshairs:before { - content: '\f05b'; -} -.icon-times-circle-o:before { - content: '\f05c'; -} -.icon-check-circle-o:before { - content: '\f05d'; -} -.icon-ban:before { - content: '\f05e'; -} -.icon-arrow-left:before { - content: '\f060'; -} -.icon-arrow-right:before { - content: '\f061'; -} -.icon-arrow-up:before { - content: '\f062'; -} -.icon-arrow-down:before { - content: '\f063'; -} -.icon-mail-forward:before, -.icon-share:before { - content: '\f064'; -} -.icon-expand:before { - content: '\f065'; -} -.icon-compress:before { - content: '\f066'; -} -.icon-plus:before { - content: '\f067'; -} -.icon-minus:before { - content: '\f068'; -} -.icon-asterisk:before { - content: '\f069'; -} -.icon-exclamation-circle:before { - content: '\f06a'; -} -.icon-gift:before { - content: '\f06b'; -} -.icon-leaf:before { - content: '\f06c'; -} -.icon-fire:before { - content: '\f06d'; -} -.icon-eye:before { - content: '\f06e'; -} -.icon-eye-slash:before { - content: '\f070'; -} -.icon-warning:before, -.icon-exclamation-triangle:before { - content: '\f071'; -} -.icon-plane:before { - content: '\f072'; -} -.icon-calendar:before { - content: '\f073'; -} -.icon-random:before { - content: '\f074'; -} -.icon-comment:before { - content: '\f075'; -} -.icon-magnet:before { - content: '\f076'; -} -.icon-chevron-up:before { - content: '\f077'; -} -.icon-chevron-down:before { - content: '\f078'; -} -.icon-retweet:before { - content: '\f079'; -} -.icon-shopping-cart:before { - content: '\f07a'; -} -.icon-folder:before { - content: '\f07b'; -} -.icon-folder-open:before { - content: '\f07c'; -} -.icon-arrows-v:before { - content: '\f07d'; -} -.icon-arrows-h:before { - content: '\f07e'; -} -.icon-bar-chart-o:before, -.icon-bar-chart:before { - content: '\f080'; -} -.icon-twitter-square:before { - content: '\f081'; -} -.icon-facebook-square:before { - content: '\f082'; -} -.icon-camera-retro:before { - content: '\f083'; -} -.icon-key:before { - content: '\f084'; -} -.icon-gears:before, -.icon-cogs:before { - content: '\f085'; -} -.icon-comments:before { - content: '\f086'; -} -.icon-thumbs-o-up:before { - content: '\f087'; -} -.icon-thumbs-o-down:before { - content: '\f088'; -} -.icon-star-half:before { - content: '\f089'; -} -.icon-heart-o:before { - content: '\f08a'; -} -.icon-sign-out:before { - content: '\f08b'; -} -.icon-linkedin-square:before { - content: '\f08c'; -} -.icon-thumb-tack:before { - content: '\f08d'; -} -.icon-external-link:before { - content: '\f08e'; -} -.icon-sign-in:before { - content: '\f090'; -} -.icon-trophy:before { - content: '\f091'; -} -.icon-github-square:before { - content: '\f092'; -} -.icon-upload:before { - content: '\f093'; -} -.icon-lemon-o:before { - content: '\f094'; -} -.icon-phone:before { - content: '\f095'; -} -.icon-square-o:before { - content: '\f096'; -} -.icon-bookmark-o:before { - content: '\f097'; -} -.icon-phone-square:before { - content: '\f098'; -} -.icon-twitter:before { - content: '\f099'; -} -.icon-facebook-f:before, -.icon-facebook:before { - content: '\f09a'; -} -.icon-github:before { - content: '\f09b'; -} -.icon-unlock:before { - content: '\f09c'; -} -.icon-credit-card:before { - content: '\f09d'; -} -.icon-rss:before { - content: '\f09e'; -} -.icon-hdd-o:before { - content: '\f0a0'; -} -.icon-bullhorn:before { - content: '\f0a1'; -} -.icon-bell:before { - content: '\f0f3'; -} -.icon-certificate:before { - content: '\f0a3'; -} -.icon-hand-o-right:before { - content: '\f0a4'; -} -.icon-hand-o-left:before { - content: '\f0a5'; -} -.icon-hand-o-up:before { - content: '\f0a6'; -} -.icon-hand-o-down:before { - content: '\f0a7'; -} -.icon-arrow-circle-left:before { - content: '\f0a8'; -} -.icon-arrow-circle-right:before { - content: '\f0a9'; -} -.icon-arrow-circle-up:before { - content: '\f0aa'; -} -.icon-arrow-circle-down:before { - content: '\f0ab'; -} -.icon-globe:before { - content: '\f0ac'; -} -.icon-wrench:before { - content: '\f0ad'; -} -.icon-tasks:before { - content: '\f0ae'; -} -.icon-filter:before { - content: '\f0b0'; -} -.icon-briefcase:before { - content: '\f0b1'; -} -.icon-arrows-alt:before { - content: '\f0b2'; -} -.icon-group:before, -.icon-users:before { - content: '\f0c0'; -} -.icon-chain:before, -.icon-link:before { - content: '\f0c1'; -} -.icon-cloud:before { - content: '\f0c2'; -} -.icon-flask:before { - content: '\f0c3'; -} -.icon-cut:before, -.icon-scissors:before { - content: '\f0c4'; -} -.icon-copy:before, -.icon-files-o:before { - content: '\f0c5'; -} -.icon-paperclip:before { - content: '\f0c6'; -} -.icon-save:before, -.icon-floppy-o:before { - content: '\f0c7'; -} -.icon-square:before { - content: '\f0c8'; -} -.icon-navicon:before, -.icon-reorder:before, -.icon-bars:before { - content: '\f0c9'; -} -.icon-list-ul:before { - content: '\f0ca'; -} -.icon-list-ol:before { - content: '\f0cb'; -} -.icon-strikethrough:before { - content: '\f0cc'; -} -.icon-underline:before { - content: '\f0cd'; -} -.icon-table:before { - content: '\f0ce'; -} -.icon-magic:before { - content: '\f0d0'; -} -.icon-truck:before { - content: '\f0d1'; -} -.icon-pinterest:before { - content: '\f0d2'; -} -.icon-pinterest-square:before { - content: '\f0d3'; -} -.icon-google-plus-square:before { - content: '\f0d4'; -} -.icon-google-plus:before { - content: '\f0d5'; -} -.icon-money:before { - content: '\f0d6'; -} -.icon-caret-down:before { - content: '\f0d7'; -} -.icon-caret-up:before { - content: '\f0d8'; -} -.icon-caret-left:before { - content: '\f0d9'; -} -.icon-caret-right:before { - content: '\f0da'; -} -.icon-columns:before { - content: '\f0db'; -} -.icon-unsorted:before, -.icon-sort:before { - content: '\f0dc'; -} -.icon-sort-down:before, -.icon-sort-desc:before { - content: '\f0dd'; -} -.icon-sort-up:before, -.icon-sort-asc:before { - content: '\f0de'; -} -.icon-envelope:before { - content: '\f0e0'; -} -.icon-linkedin:before { - content: '\f0e1'; -} -.icon-rotate-left:before, -.icon-undo:before { - content: '\f0e2'; -} -.icon-legal:before, -.icon-gavel:before { - content: '\f0e3'; -} -.icon-dashboard:before, -.icon-tachometer:before { - content: '\f0e4'; -} -.icon-comment-o:before { - content: '\f0e5'; -} -.icon-comments-o:before { - content: '\f0e6'; -} -.icon-flash:before, -.icon-bolt:before { - content: '\f0e7'; -} -.icon-sitemap:before { - content: '\f0e8'; -} -.icon-umbrella:before { - content: '\f0e9'; -} -.icon-paste:before, -.icon-clipboard:before { - content: '\f0ea'; -} -.icon-lightbulb-o:before { - content: '\f0eb'; -} -.icon-exchange:before { - content: '\f0ec'; -} -.icon-cloud-download:before { - content: '\f0ed'; -} -.icon-cloud-upload:before { - content: '\f0ee'; -} -.icon-user-md:before { - content: '\f0f0'; -} -.icon-stethoscope:before { - content: '\f0f1'; -} -.icon-suitcase:before { - content: '\f0f2'; -} -.icon-bell-o:before { - content: '\f0a2'; -} -.icon-coffee:before { - content: '\f0f4'; -} -.icon-cutlery:before { - content: '\f0f5'; -} -.icon-file-text-o:before { - content: '\f0f6'; -} -.icon-building-o:before { - content: '\f0f7'; -} -.icon-hospital-o:before { - content: '\f0f8'; -} -.icon-ambulance:before { - content: '\f0f9'; -} -.icon-medkit:before { - content: '\f0fa'; -} -.icon-fighter-jet:before { - content: '\f0fb'; -} -.icon-beer:before { - content: '\f0fc'; -} -.icon-h-square:before { - content: '\f0fd'; -} -.icon-plus-square:before { - content: '\f0fe'; -} -.icon-angle-double-left:before { - content: '\f100'; -} -.icon-angle-double-right:before { - content: '\f101'; -} -.icon-angle-double-up:before { - content: '\f102'; -} -.icon-angle-double-down:before { - content: '\f103'; -} -.icon-angle-left:before { - content: '\f104'; -} -.icon-angle-right:before { - content: '\f105'; -} -.icon-angle-up:before { - content: '\f106'; -} -.icon-angle-down:before { - content: '\f107'; -} -.icon-desktop:before { - content: '\f108'; -} -.icon-laptop:before { - content: '\f109'; -} -.icon-tablet:before { - content: '\f10a'; -} -.icon-mobile-phone:before, -.icon-mobile:before { - content: '\f10b'; -} -.icon-circle-o:before { - content: '\f10c'; -} -.icon-quote-left:before { - content: '\f10d'; -} -.icon-quote-right:before { - content: '\f10e'; -} -.icon-spinner:before { - content: '\f110'; -} -.icon-circle:before { - content: '\f111'; -} -.icon-mail-reply:before, -.icon-reply:before { - content: '\f112'; -} -.icon-github-alt:before { - content: '\f113'; -} -.icon-folder-o:before { - content: '\f114'; -} -.icon-folder-open-o:before { - content: '\f115'; -} -.icon-smile-o:before { - content: '\f118'; -} -.icon-frown-o:before { - content: '\f119'; -} -.icon-meh-o:before { - content: '\f11a'; -} -.icon-gamepad:before { - content: '\f11b'; -} -.icon-keyboard-o:before { - content: '\f11c'; -} -.icon-flag-o:before { - content: '\f11d'; -} -.icon-flag-checkered:before { - content: '\f11e'; -} -.icon-terminal:before { - content: '\f120'; -} -.icon-code:before { - content: '\f121'; -} -.icon-mail-reply-all:before, -.icon-reply-all:before { - content: '\f122'; -} -.icon-star-half-empty:before, -.icon-star-half-full:before, -.icon-star-half-o:before { - content: '\f123'; -} -.icon-location-arrow:before { - content: '\f124'; -} -.icon-crop:before { - content: '\f125'; -} -.icon-code-fork:before { - content: '\f126'; -} -.icon-unlink:before, -.icon-chain-broken:before { - content: '\f127'; -} -.icon-question:before { - content: '\f128'; -} -.icon-info:before { - content: '\f129'; -} -.icon-exclamation:before { - content: '\f12a'; -} -.icon-superscript:before { - content: '\f12b'; -} -.icon-subscript:before { - content: '\f12c'; -} -.icon-eraser:before { - content: '\f12d'; -} -.icon-puzzle-piece:before { - content: '\f12e'; -} -.icon-microphone:before { - content: '\f130'; -} -.icon-microphone-slash:before { - content: '\f131'; -} -.icon-shield:before { - content: '\f132'; -} -.icon-calendar-o:before { - content: '\f133'; -} -.icon-fire-extinguisher:before { - content: '\f134'; -} -.icon-rocket:before { - content: '\f135'; -} -.icon-maxcdn:before { - content: '\f136'; -} -.icon-chevron-circle-left:before { - content: '\f137'; -} -.icon-chevron-circle-right:before { - content: '\f138'; -} -.icon-chevron-circle-up:before { - content: '\f139'; -} -.icon-chevron-circle-down:before { - content: '\f13a'; -} -.icon-html5:before { - content: '\f13b'; -} -.icon-css3:before { - content: '\f13c'; -} -.icon-anchor:before { - content: '\f13d'; -} -.icon-unlock-alt:before { - content: '\f13e'; -} -.icon-bullseye:before { - content: '\f140'; -} -.icon-ellipsis-h:before { - content: '\f141'; -} -.icon-ellipsis-v:before { - content: '\f142'; -} -.icon-rss-square:before { - content: '\f143'; -} -.icon-play-circle:before { - content: '\f144'; -} -.icon-ticket:before { - content: '\f145'; -} -.icon-minus-square:before { - content: '\f146'; -} -.icon-minus-square-o:before { - content: '\f147'; -} -.icon-level-up:before { - content: '\f148'; -} -.icon-level-down:before { - content: '\f149'; -} -.icon-check-square:before { - content: '\f14a'; -} -.icon-pencil-square:before { - content: '\f14b'; -} -.icon-external-link-square:before { - content: '\f14c'; -} -.icon-share-square:before { - content: '\f14d'; -} -.icon-compass:before { - content: '\f14e'; -} -.icon-toggle-down:before, -.icon-caret-square-o-down:before { - content: '\f150'; -} -.icon-toggle-up:before, -.icon-caret-square-o-up:before { - content: '\f151'; -} -.icon-toggle-right:before, -.icon-caret-square-o-right:before { - content: '\f152'; -} -.icon-euro:before, -.icon-eur:before { - content: '\f153'; -} -.icon-gbp:before { - content: '\f154'; -} -.icon-dollar:before, -.icon-usd:before { - content: '\f155'; -} -.icon-rupee:before, -.icon-inr:before { - content: '\f156'; -} -.icon-cny:before, -.icon-rmb:before, -.icon-yen:before, -.icon-jpy:before { - content: '\f157'; -} -.icon-ruble:before, -.icon-rouble:before, -.icon-rub:before { - content: '\f158'; -} -.icon-won:before, -.icon-krw:before { - content: '\f159'; -} -.icon-bitcoin:before, -.icon-btc:before { - content: '\f15a'; -} -.icon-file:before { - content: '\f15b'; -} -.icon-file-text:before { - content: '\f15c'; -} -.icon-sort-alpha-asc:before { - content: '\f15d'; -} -.icon-sort-alpha-desc:before { - content: '\f15e'; -} -.icon-sort-amount-asc:before { - content: '\f160'; -} -.icon-sort-amount-desc:before { - content: '\f161'; -} -.icon-sort-numeric-asc:before { - content: '\f162'; -} -.icon-sort-numeric-desc:before { - content: '\f163'; -} -.icon-thumbs-up:before { - content: '\f164'; -} -.icon-thumbs-down:before { - content: '\f165'; -} -.icon-youtube-square:before { - content: '\f166'; -} -.icon-youtube:before { - content: '\f167'; -} -.icon-xing:before { - content: '\f168'; -} -.icon-xing-square:before { - content: '\f169'; -} -.icon-youtube-play:before { - content: '\f16a'; -} -.icon-dropbox:before { - content: '\f16b'; -} -.icon-stack-overflow:before { - content: '\f16c'; -} -.icon-instagram:before { - content: '\f16d'; -} -.icon-flickr:before { - content: '\f16e'; -} -.icon-adn:before { - content: '\f170'; -} -.icon-bitbucket:before { - content: '\f171'; -} -.icon-bitbucket-square:before { - content: '\f172'; -} -.icon-tumblr:before { - content: '\f173'; -} -.icon-tumblr-square:before { - content: '\f174'; -} -.icon-long-arrow-down:before { - content: '\f175'; -} -.icon-long-arrow-up:before { - content: '\f176'; -} -.icon-long-arrow-left:before { - content: '\f177'; -} -.icon-long-arrow-right:before { - content: '\f178'; -} -.icon-apple:before { - content: '\f179'; -} -.icon-windows:before { - content: '\f17a'; -} -.icon-android:before { - content: '\f17b'; -} -.icon-linux:before { - content: '\f17c'; -} -.icon-dribbble:before { - content: '\f17d'; -} -.icon-skype:before { - content: '\f17e'; -} -.icon-foursquare:before { - content: '\f180'; -} -.icon-trello:before { - content: '\f181'; -} -.icon-female:before { - content: '\f182'; -} -.icon-male:before { - content: '\f183'; -} -.icon-gittip:before, -.icon-gratipay:before { - content: '\f184'; -} -.icon-sun-o:before { - content: '\f185'; -} -.icon-moon-o:before { - content: '\f186'; -} -.icon-archive:before { - content: '\f187'; -} -.icon-bug:before { - content: '\f188'; -} -.icon-vk:before { - content: '\f189'; -} -.icon-weibo:before { - content: '\f18a'; -} -.icon-renren:before { - content: '\f18b'; -} -.icon-pagelines:before { - content: '\f18c'; -} -.icon-stack-exchange:before { - content: '\f18d'; -} -.icon-arrow-circle-o-right:before { - content: '\f18e'; -} -.icon-arrow-circle-o-left:before { - content: '\f190'; -} -.icon-toggle-left:before, -.icon-caret-square-o-left:before { - content: '\f191'; -} -.icon-dot-circle-o:before { - content: '\f192'; -} -.icon-wheelchair:before { - content: '\f193'; -} -.icon-vimeo-square:before { - content: '\f194'; -} -.icon-turkish-lira:before, -.icon-try:before { - content: '\f195'; -} -.icon-plus-square-o:before { - content: '\f196'; -} -.icon-space-shuttle:before { - content: '\f197'; -} -.icon-slack:before { - content: '\f198'; -} -.icon-envelope-square:before { - content: '\f199'; -} -.icon-wordpress:before { - content: '\f19a'; -} -.icon-openid:before { - content: '\f19b'; -} -.icon-institution:before, -.icon-bank:before, -.icon-university:before { - content: '\f19c'; -} -.icon-mortar-board:before, -.icon-graduation-cap:before { - content: '\f19d'; -} -.icon-yahoo:before { - content: '\f19e'; -} -.icon-google:before { - content: '\f1a0'; -} -.icon-reddit:before { - content: '\f1a1'; -} -.icon-reddit-square:before { - content: '\f1a2'; -} -.icon-stumbleupon-circle:before { - content: '\f1a3'; -} -.icon-stumbleupon:before { - content: '\f1a4'; -} -.icon-delicious:before { - content: '\f1a5'; -} -.icon-digg:before { - content: '\f1a6'; -} -.icon-pied-piper:before { - content: '\f1a7'; -} -.icon-pied-piper-alt:before { - content: '\f1a8'; -} -.icon-drupal:before { - content: '\f1a9'; -} -.icon-joomla:before { - content: '\f1aa'; -} -.icon-language:before { - content: '\f1ab'; -} -.icon-fax:before { - content: '\f1ac'; -} -.icon-building:before { - content: '\f1ad'; -} -.icon-child:before { - content: '\f1ae'; -} -.icon-paw:before { - content: '\f1b0'; -} -.icon-spoon:before { - content: '\f1b1'; -} -.icon-cube:before { - content: '\f1b2'; -} -.icon-cubes:before { - content: '\f1b3'; -} -.icon-behance:before { - content: '\f1b4'; -} -.icon-behance-square:before { - content: '\f1b5'; -} -.icon-steam:before { - content: '\f1b6'; -} -.icon-steam-square:before { - content: '\f1b7'; -} -.icon-recycle:before { - content: '\f1b8'; -} -.icon-automobile:before, -.icon-car:before { - content: '\f1b9'; -} -.icon-cab:before, -.icon-taxi:before { - content: '\f1ba'; -} -.icon-tree:before { - content: '\f1bb'; -} -.icon-spotify:before { - content: '\f1bc'; -} -.icon-deviantart:before { - content: '\f1bd'; -} -.icon-soundcloud:before { - content: '\f1be'; -} -.icon-database:before { - content: '\f1c0'; -} -.icon-file-pdf-o:before { - content: '\f1c1'; -} -.icon-file-word-o:before { - content: '\f1c2'; -} -.icon-file-excel-o:before { - content: '\f1c3'; -} -.icon-file-powerpoint-o:before { - content: '\f1c4'; -} -.icon-file-photo-o:before, -.icon-file-picture-o:before, -.icon-file-image-o:before { - content: '\f1c5'; -} -.icon-file-zip-o:before, -.icon-file-archive-o:before { - content: '\f1c6'; -} -.icon-file-sound-o:before, -.icon-file-audio-o:before { - content: '\f1c7'; -} -.icon-file-movie-o:before, -.icon-file-video-o:before { - content: '\f1c8'; -} -.icon-file-code-o:before { - content: '\f1c9'; -} -.icon-vine:before { - content: '\f1ca'; -} -.icon-codepen:before { - content: '\f1cb'; -} -.icon-jsfiddle:before { - content: '\f1cc'; -} -.icon-life-bouy:before, -.icon-life-buoy:before, -.icon-life-saver:before, -.icon-support:before, -.icon-life-ring:before { - content: '\f1cd'; -} -.icon-circle-o-notch:before { - content: '\f1ce'; -} -.icon-ra:before, -.icon-rebel:before { - content: '\f1d0'; -} -.icon-ge:before, -.icon-empire:before { - content: '\f1d1'; -} -.icon-git-square:before { - content: '\f1d2'; -} -.icon-git:before { - content: '\f1d3'; -} -.icon-hacker-news:before { - content: '\f1d4'; -} -.icon-tencent-weibo:before { - content: '\f1d5'; -} -.icon-qq:before { - content: '\f1d6'; -} -.icon-wechat:before, -.icon-weixin:before { - content: '\f1d7'; -} -.icon-send:before, -.icon-paper-plane:before { - content: '\f1d8'; -} -.icon-send-o:before, -.icon-paper-plane-o:before { - content: '\f1d9'; -} -.icon-history:before { - content: '\f1da'; -} -.icon-genderless:before, -.icon-circle-thin:before { - content: '\f1db'; -} -.icon-header:before { - content: '\f1dc'; -} -.icon-paragraph:before { - content: '\f1dd'; -} -.icon-sliders:before { - content: '\f1de'; -} -.icon-share-alt:before { - content: '\f1e0'; -} -.icon-share-alt-square:before { - content: '\f1e1'; -} -.icon-bomb:before { - content: '\f1e2'; -} -.icon-soccer-ball-o:before, -.icon-futbol-o:before { - content: '\f1e3'; -} -.icon-tty:before { - content: '\f1e4'; -} -.icon-binoculars:before { - content: '\f1e5'; -} -.icon-plug:before { - content: '\f1e6'; -} -.icon-slideshare:before { - content: '\f1e7'; -} -.icon-twitch:before { - content: '\f1e8'; -} -.icon-yelp:before { - content: '\f1e9'; -} -.icon-newspaper-o:before { - content: '\f1ea'; -} -.icon-wifi:before { - content: '\f1eb'; -} -.icon-calculator:before { - content: '\f1ec'; -} -.icon-paypal:before { - content: '\f1ed'; -} -.icon-google-wallet:before { - content: '\f1ee'; -} -.icon-cc-visa:before { - content: '\f1f0'; -} -.icon-cc-mastercard:before { - content: '\f1f1'; -} -.icon-cc-discover:before { - content: '\f1f2'; -} -.icon-cc-amex:before { - content: '\f1f3'; -} -.icon-cc-paypal:before { - content: '\f1f4'; -} -.icon-cc-stripe:before { - content: '\f1f5'; -} -.icon-bell-slash:before { - content: '\f1f6'; -} -.icon-bell-slash-o:before { - content: '\f1f7'; -} -.icon-trash:before { - content: '\f1f8'; -} -.icon-copyright:before { - content: '\f1f9'; -} -.icon-at:before { - content: '\f1fa'; -} -.icon-eyedropper:before { - content: '\f1fb'; -} -.icon-paint-brush:before { - content: '\f1fc'; -} -.icon-birthday-cake:before { - content: '\f1fd'; -} -.icon-area-chart:before { - content: '\f1fe'; -} -.icon-pie-chart:before { - content: '\f200'; -} -.icon-line-chart:before { - content: '\f201'; -} -.icon-lastfm:before { - content: '\f202'; -} -.icon-lastfm-square:before { - content: '\f203'; -} -.icon-toggle-off:before { - content: '\f204'; -} -.icon-toggle-on:before { - content: '\f205'; -} -.icon-bicycle:before { - content: '\f206'; -} -.icon-bus:before { - content: '\f207'; -} -.icon-ioxhost:before { - content: '\f208'; -} -.icon-angellist:before { - content: '\f209'; -} -.icon-cc:before { - content: '\f20a'; -} -.icon-shekel:before, -.icon-sheqel:before, -.icon-ils:before { - content: '\f20b'; -} -.icon-meanpath:before { - content: '\f20c'; -} -.icon-buysellads:before { - content: '\f20d'; -} -.icon-connectdevelop:before { - content: '\f20e'; -} -.icon-dashcube:before { - content: '\f210'; -} -.icon-forumbee:before { - content: '\f211'; -} -.icon-leanpub:before { - content: '\f212'; -} -.icon-sellsy:before { - content: '\f213'; -} -.icon-shirtsinbulk:before { - content: '\f214'; -} -.icon-simplybuilt:before { - content: '\f215'; -} -.icon-skyatlas:before { - content: '\f216'; -} -.icon-cart-plus:before { - content: '\f217'; -} -.icon-cart-arrow-down:before { - content: '\f218'; -} -.icon-diamond:before { - content: '\f219'; -} -.icon-ship:before { - content: '\f21a'; -} -.icon-user-secret:before { - content: '\f21b'; -} -.icon-motorcycle:before { - content: '\f21c'; -} -.icon-street-view:before { - content: '\f21d'; -} -.icon-heartbeat:before { - content: '\f21e'; -} -.icon-venus:before { - content: '\f221'; -} -.icon-mars:before { - content: '\f222'; -} -.icon-mercury:before { - content: '\f223'; -} -.icon-transgender:before { - content: '\f224'; -} -.icon-transgender-alt:before { - content: '\f225'; -} -.icon-venus-double:before { - content: '\f226'; -} -.icon-mars-double:before { - content: '\f227'; -} -.icon-venus-mars:before { - content: '\f228'; -} -.icon-mars-stroke:before { - content: '\f229'; -} -.icon-mars-stroke-v:before { - content: '\f22a'; -} -.icon-mars-stroke-h:before { - content: '\f22b'; -} -.icon-neuter:before { - content: '\f22c'; -} -.icon-facebook-official:before { - content: '\f230'; -} -.icon-pinterest-p:before { - content: '\f231'; -} -.icon-whatsapp:before { - content: '\f232'; -} -.icon-server:before { - content: '\f233'; -} -.icon-user-plus:before { - content: '\f234'; -} -.icon-user-times:before { - content: '\f235'; -} -.icon-hotel:before, -.icon-bed:before { - content: '\f236'; -} -.icon-viacoin:before { - content: '\f237'; -} -.icon-train:before { - content: '\f238'; -} -.icon-subway:before { - content: '\f239'; -} -.icon-medium:before { - content: '\f23a'; -} -.icon-address-book:before { - content: '\f2b9'; -} -.icon-envelope-open:before { - content: '\f2b6'; -} diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss index f0b415e90..d7c120615 100644 --- a/src/renderer/scss/_vars.scss +++ b/src/renderer/scss/_vars.scss @@ -3,33 +3,39 @@ Both of these should probably die and become variables as well */ $spacing-vertical: 24px; $width-page-constrained: 800px; -$text-color: #000; :root { - --spacing-vertical: 24px; - /* 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-primary: #155b4a; - --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-dark-overlay: rgba(32, 32, 32, 0.9); --color-help: rgba(0, 0, 0, 0.54); - --color-notice: #8a6d3b; + // --color-notice: #8a6d3b; --color-error: #a94442; - --color-load-screen-text: #c3c3c3; - --color-meta-light: #505050; - --color-money: #216c2a; - --color-download: rgba(0, 0, 0, 0.75); - --color-canvas: #f5f5f5; - --color-bg: #ffffff; + // --color-load-screen-text: #c3c3c3; + // --color-meta-light: #505050; + // --color-money: #216c2a; + // --color-download: rgba(0, 0, 0, 0.75); + // --color-canvas: #f5f5f5; + --color-bg: #fafafa; --color-bg-alt: #f6f6f6; --color-placeholder: #ececec; + --color-nav-bg: #f6f6f6; /* Misc */ - --content-max-width: 1000px; - --nsfw-blur-intensity: 20px; - --height-video-embedded: $width-page-constrained * 9 / 16; + // --content-max-width: 1000px; + // --nsfw-blur-intensity: 20px; + // --height-video-embedded: $width-page-constrained * 9 / 16; /* Font */ --font-size: 16px; @@ -37,16 +43,10 @@ $text-color: #000; --font-size-subtext-multiple: 0.82; /* Shadows */ - --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), - 2px 3px 7px 0 rgba(0, 0, 0, 0.12); - - /* Transition */ - --transition-duration: 0.225s; - --transition-type: ease; + // --box-shadow-layer: 0px 1px 3px 0px rgba(0, 0, 0, 0.2); + --box-shadow-layer: 0 4px 9px -2px var(--color-grey); /* Text */ - --text-color: $text-color; --text-help-color: #eee; --text-max-width: 660px; --text-link-padding: 4px; @@ -58,10 +58,10 @@ $text-color: #000; /* Input */ --input-bg: transparent; - --input-width: 330px; + --input-label-color: var(--color-grey-dark); --input-color: var(--text-color); - --input-border-size: 2px; - --input-border-color: rgba(0, 0, 0, 0.54); + --input-border-size: 1px; + --input-border-color: var(--color-grey-dark); /* input:active */ --input-active-bg: transparent; @@ -81,39 +81,28 @@ $text-color: #000; --select-color: var(--text-color); --select-height: 30px; - //TODO: determine proper button variables; /* Button */ --btn-primary-color: #fff; --button-alt-color: var(--text-color); - --btn-primary-bg: var(--color-primary); - --btn-alt-bg: red; - --btn-radius: 10px; - // below needed? - --btn-padding: $spacing-vertical * 2/3; - --btn-height: $spacing-vertical * 1.5; - --btn-intra-margin: $spacing-vertical; + --btn-primary-bg: var(--color-primary-dark); + --btn-inverse-color: var(--color-primary-dark); + --btn-inverse-bg: var(--color-white); + --btn-radius: 20px; + --btn-height: 40px; /* Header */ - --header-bg: var(--color-bg); - --header-color: #666; + --header-bg: var(--color-white); + --header-color: var(--color-text); --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-hover-bg: rgba(100, 100, 100, 0.15); /* Header -> search */ - --search-bg: rgba(255, 255, 255, 0.7); - --search-border: 1px solid #ccc; --search-color: #666; + --search-bg-color: #fff; --search-active-color: var(--header-active-color); - --search-active-shadow: 0 0 3px 0px var(--text-selection-bg); - - /* 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); + --search-active-shadow: 0 6px 9px -2px var(--color-grey--dark); /* Table */ --table-border: 1px solid #e2e2e2; @@ -121,13 +110,10 @@ $text-color: #000; --table-item-odd: #f4f4f4; /* Card */ - --card-bg: var(--color-bg); --card-hover-translate: 10px; --card-margin: $spacing-vertical * 2/3; --card-max-width: $width-page-constrained; - --card-padding: $spacing-vertical * 2/3; --card-radius: 2px; - --card-link-scaling: 1.1; --card-small-width: $spacing-vertical * 10; /* Modal */ @@ -136,12 +122,7 @@ $text-color: #000; --modal-overlay-bg: rgba(#f5f5f5, 0.75); // --color-canvas: #F5F5F5 --modal-border: 1px solid rgb(204, 204, 204); - /* Menu */ - --menu-bg: var(--color-bg); - --menu-radius: 2px; - --menu-item-hover-bg: var(--color-bg-alt); - - /* Tooltip */ + // /* Tooltip */ --tooltip-width: 300px; --tooltip-bg: var(--color-bg); --tooltip-color: var(--text-color); @@ -153,10 +134,10 @@ $text-color: #000; --scrollbar-thumb-active-bg: var(--color-primary); --scrollbar-track-bg: transparent; - /* Divider */ - --divider: 1px solid rgba(0, 0, 0, 0.12); - - /* Animation :) */ - --animation-duration: 0.3s; - --animation-style: cubic-bezier(0.55, 0, 0.1, 1); + // /* Divider */ + // --divider: 1px solid rgba(0, 0, 0, 0.12); + // + // /* Animation :) */ + // --animation-duration: 0.3s; + // --animation-style: cubic-bezier(0.55, 0, 0.1, 1); } diff --git a/src/renderer/scss/all.scss b/src/renderer/scss/all.scss index 7d39cb43a..3293a57f4 100644 --- a/src/renderer/scss/all.scss +++ b/src/renderer/scss/all.scss @@ -1,7 +1,6 @@ @charset "UTF-8"; @import '_reset'; @import '_vars'; -@import '_icons'; @import '_gui'; @import 'component/_table'; @import 'component/_button.scss'; @@ -28,4 +27,5 @@ @import 'component/_radio.scss'; @import 'component/_shapeshift.scss'; @import 'component/_spinner.scss'; +@import 'component/_nav.scss'; @import 'page/_show.scss'; diff --git a/src/renderer/scss/component/_button.scss b/src/renderer/scss/component/_button.scss index dfb8e0513..78f8e181b 100644 --- a/src/renderer/scss/component/_button.scss +++ b/src/renderer/scss/component/_button.scss @@ -3,34 +3,35 @@ TODO: Determine [disabled] or .disabled Add support (probably just get rid of button prefix) */ - -button { +.btn { border: none; text-decoration: none; cursor: pointer; position: relative; -} - -button:disabled.btn--disabled { - cursor: default; - background-color: transparent; -} - -button.btn { + font-weight: 600; padding: 10px; - margin: 0 5px; + height: var(--btn-height); + min-width: var(--btn-height); border-radius: var(--btn-radius); color: var(--btn-primary-color); 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); } + + .icon + .btn__label { + padding-left: 5px; + } } -button.btn.btn--alt { +.btn.btn--alt { color: var(--btn-alt-color); - background-color: #efefef; + background-color: var(--color-white); &:hover { color: #111; @@ -46,30 +47,71 @@ button.btn.btn--alt { } } -button.btn.btn--circle { - border-radius: 50%; - transition: all 0.2s; +.btn.btn--inverse { + background-color: transparent; + color: var(--btn-inverse-color); - &:hover:not([disabled]) { - border-radius: var(--btn-radius); + &:hover { + background-color: var(--btn-inverse-bg); } } -button.btn.btn--inverse { - box-shadow: none; - background-color: transparent; - color: var(--btn-primary-bg); -} - -button.btn--link { +.btn.btn--link { padding: 0; margin: 0; background-color: inherit; - font-size: 0.9em; - color: var(--btn-primary-bg); // this should be a different color + font-size: 1em; + color: var(--btn-inverse-color); + border-radius: 0; + display: inline; &:hover { 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; } } diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss index 3315b8f31..431d18030 100644 --- a/src/renderer/scss/component/_card.scss +++ b/src/renderer/scss/component/_card.scss @@ -1,20 +1,23 @@ .card { margin-left: auto; margin-right: auto; - max-width: var(--card-max-width); border-radius: var(--card-radius); overflow: auto; user-select: text; display: flex; + position: relative; } -.card--placeholder { - background-color: black; +.card--section { + 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 { width: var(--card-small-width); - min-height: var(--card-small-width); overflow-x: hidden; white-space: normal; } @@ -48,7 +51,8 @@ margin-top: $spacing-vertical * 1/3; } -// TODO: regular .card__title for show page +// TODO: regular .card__title +// maybe not needed? .card__title--small { font-weight: 600; font-size: 0.9em; @@ -60,145 +64,24 @@ padding-top: $spacing-vertical * 1/3; } -// .card__title-primary .meta { -// white-space: nowrap; -// overflow: hidden; -// text-overflow: ellipsis; -// } -// +.card-media__internal-links { + position: absolute; + top: 5px; + right: 5px; +} -// -// .card__actions { -// margin-top: 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__content { + margin-top: var(--card-margin); + margin-bottom: var(--card-margin); +} -// -// .card-series-submit { -// margin-left: auto; -// margin-right: auto; -// max-width: var(--card-max-width); -// padding: $spacing-vertical / 2; -// } +.card__actions { + margin-top: var(--card-margin); + display: flex; +} /* - .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 There are left/right arrows to scroll the cards and view hidden content */ @@ -208,6 +91,14 @@ width: 100%; min-width: var(--card-small-width); 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 { @@ -225,6 +116,10 @@ align-items: center; } +.card-row__scroll-btns { + display: flex; +} + .card-row__scrollhouse { padding-top: $spacing-vertical * 2/3; overflow: hidden; @@ -233,26 +128,10 @@ display: inline-block; vertical-align: top; margin-left: $spacing-vertical * 2/3; + overflow: visible; } .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; -// } -// } diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss index a63352589..10cb942a2 100644 --- a/src/renderer/scss/component/_form-field.scss +++ b/src/renderer/scss/component/_form-field.scss @@ -1,195 +1,40 @@ -.form-row-submit { - margin-top: $spacing-vertical; -} -.form-row-submit--with-footer { - margin-bottom: $spacing-vertical; -} - -.form-row-phone { +.form-row { display: flex; + flex-direction: row; - .form-field__input-text { - margin-left: 5px; - width: calc(0.85 * var(--input-width)); + .form-field:not(:first-of-type) { + padding-left: $spacing-vertical; } } -.form-row__label-row { - margin-top: $spacing-vertical * 5/6; - margin-bottom: 0px; - 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__wrapper { + display: flex; + padding: $spacing-vertical / 3 0; } .form-field__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 { - height: auto; +.form-field__prefix { + 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; } diff --git a/src/renderer/scss/component/_header.scss b/src/renderer/scss/component/_header.scss index ca07bcc13..5140bc91d 100644 --- a/src/renderer/scss/component/_header.scss +++ b/src/renderer/scss/component/_header.scss @@ -1,60 +1,86 @@ -#header { +.header { + grid-area: header; + display: flex; display: flex; align-items: center; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: var(--header-height); - z-index: 3; - box-sizing: border-box; - color: var(--header-color); - background-color: var(--header-bg); -} - -.header__actions-left { - display: flex; - padding: 0 5px; + justify-content: space-between; + padding: 0 $spacing-vertical; + align-items: center; + justify-content: space-between; + height: 100%; + background-color: var(--color-bg); } .header__actions-right { margin-left: auto; + padding-left: $spacing-vertical / 2; + display: flex; } .header__wunderbar { + z-index: 1; flex: 1; - max-width: 325px; min-width: 175px; - overflow: hidden; + overflow: visible; white-space: nowrap; text-overflow: ellipsis; - height: 100%; display: flex; align-items: center; - padding: 10px 5px; cursor: text; -} + position: relative; -.wunderbar__input { - height: 50%; - width: 100%; - color: var(--search-color); - padding: 10px; - background-color: #f3f3f3; - border-radius: 10px; - font-size: 0.9em; - - &:focus { - // TODO: focus style + .icon { + position: absolute; + left: 10px; } } +.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 { - padding: 5px; + padding: 10px; background-color: var(--header-bg); 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 { - background-color: #a3ffb0; + background-color: var(--color-secondary); } diff --git a/src/renderer/scss/component/_nav.scss b/src/renderer/scss/component/_nav.scss new file mode 100644 index 000000000..4c793cea7 --- /dev/null +++ b/src/renderer/scss/component/_nav.scss @@ -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; +} diff --git a/src/renderer/scss/component/_shapeshift.scss b/src/renderer/scss/component/_shapeshift.scss index cbe040180..456db51e6 100644 --- a/src/renderer/scss/component/_shapeshift.scss +++ b/src/renderer/scss/component/_shapeshift.scss @@ -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 { min-height: 63px; } diff --git a/src/renderer/util/form-validation.js b/src/renderer/util/form-validation.js new file mode 100644 index 000000000..e9e85e4b5 --- /dev/null +++ b/src/renderer/util/form-validation.js @@ -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 */ diff --git a/static/font/FontAwesome.otf b/static/font/FontAwesome.otf deleted file mode 100644 index 401ec0f36..000000000 Binary files a/static/font/FontAwesome.otf and /dev/null differ diff --git a/static/font/fontawesome-webfont.eot b/static/font/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca95..000000000 Binary files a/static/font/fontawesome-webfont.eot and /dev/null differ diff --git a/static/font/fontawesome-webfont.svg b/static/font/fontawesome-webfont.svg deleted file mode 100644 index 855c845e5..000000000 --- a/static/font/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/font/fontawesome-webfont.ttf b/static/font/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa..000000000 Binary files a/static/font/fontawesome-webfont.ttf and /dev/null differ diff --git a/static/font/fontawesome-webfont.woff b/static/font/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b..000000000 Binary files a/static/font/fontawesome-webfont.woff and /dev/null differ diff --git a/static/font/fontawesome-webfont.woff2 b/static/font/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc604..000000000 Binary files a/static/font/fontawesome-webfont.woff2 and /dev/null differ diff --git a/yarn.lock b/yarn.lock index 218d4ccd5..7cd4da7f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7486,6 +7486,10 @@ react-dom@^16.2.0: object-assign "^4.1.1" 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: version "2.5.1" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-2.5.1.tgz#f7a6c26a3a5faf5d4c2098155d9775e826fd56ee"