diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..2a43b86b9 Binary files /dev/null and b/.DS_Store differ diff --git a/flow-typed/react-transition-group.js b/flow-typed/react-transition-group.js new file mode 100644 index 000000000..77bc87c09 --- /dev/null +++ b/flow-typed/react-transition-group.js @@ -0,0 +1,3 @@ +declare module 'react-transition-group' { + declare module.exports: any; +} diff --git a/package.json b/package.json index d662d2b60..f0d15f29d 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "react-paginate": "^5.0.0", "react-redux": "^5.0.3", "react-simplemde-editor": "^3.6.11", + "react-transition-group": "1.x", "redux": "^3.6.0", "redux-action-buffer": "^1.1.0", "redux-logger": "^3.0.1", diff --git a/src/main/createWindow.js b/src/main/createWindow.js index 6809761f3..8ad1107fb 100644 --- a/src/main/createWindow.js +++ b/src/main/createWindow.js @@ -4,7 +4,7 @@ import setupContextMenu from './menu/setupContextMenu'; export default deepLinkingURIArg => { let windowConfiguration = { - backgroundColor: '#155B4A', + backgroundColor: '#44b098', minWidth: 800, minHeight: 600, autoHideMenuBar: true, diff --git a/src/renderer/component/address/view.jsx b/src/renderer/component/address/view.jsx index 1ed47a92b..1c18d4be2 100644 --- a/src/renderer/component/address/view.jsx +++ b/src/renderer/component/address/view.jsx @@ -23,12 +23,13 @@ export default class Address extends React.PureComponent<Props> { return ( <FormField + stretch name="address" render={() => ( <React.Fragment> <input id="address" - className="input-copyable" + className="input-copyable form-field__input" readOnly value={address || ''} ref={input => { diff --git a/src/renderer/component/common/form-components/form-field.jsx b/src/renderer/component/common/form-components/form-field.jsx index ddea3f400..004980e49 100644 --- a/src/renderer/component/common/form-components/form-field.jsx +++ b/src/renderer/component/common/form-components/form-field.jsx @@ -1,5 +1,6 @@ // @flow import * as React from 'react'; +import classnames from 'classnames'; type Props = { name: string, @@ -13,22 +14,30 @@ type Props = { onChange?: any => any, defaultValue?: string | number, placeholder?: string | number, + children?: React.Node, + stretch?: boolean }; export class FormField extends React.PureComponent<Props> { render() { - const { render, label, prefix, postfix, error, helper, name, type, ...inputProps } = this.props; + const { render, label, prefix, postfix, error, helper, name, type, children, stretch, ...inputProps } = this.props; // Allow a type prop to determine the input or more customizability with a render prop let Input; if (type) { - Input = () => <input type={type} id={name} {...inputProps} />; + if (type === 'select') { + Input = () => ( + <select id={name} {...inputProps}>{children}</select> + ) + } else { + Input = () => <input type={type} id={name} {...inputProps} />; + } } else if (render) { Input = render; } return ( - <div className="form-field"> + <div className={classnames("form-field", { "form-field--stretch": stretch })}> {label && ( <label className="form-field__label" htmlFor={name}> {label} diff --git a/src/renderer/component/common/qr-code.jsx b/src/renderer/component/common/qr-code.jsx new file mode 100644 index 000000000..481492b4b --- /dev/null +++ b/src/renderer/component/common/qr-code.jsx @@ -0,0 +1,18 @@ +// @flow +import React from 'react'; +import QRCodeElement from 'qrcode.react'; + +type Props = { + value: string +} + +const QRCode = (props: Props) => { + const { value } = props; + return ( + <div className="qr-code"> + <QRCodeElement value={value} /> + </div> + ) +} + +export default QRCode; diff --git a/src/renderer/component/fileList/view.jsx b/src/renderer/component/fileList/view.jsx index 8dcccadc3..b4acb8801 100644 --- a/src/renderer/component/fileList/view.jsx +++ b/src/renderer/component/fileList/view.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { buildURI } from 'lbryURI'; -import FormField from 'component/formField'; +import { FormField } from 'component/common/form'; import FileTile from 'component/fileTile'; import { BusyMessage } from 'component/common.js'; diff --git a/src/renderer/component/publishForm/view.jsx b/src/renderer/component/publishForm/view.jsx index a7b8ad0c0..056f493ee 100644 --- a/src/renderer/component/publishForm/view.jsx +++ b/src/renderer/component/publishForm/view.jsx @@ -3,10 +3,8 @@ import React from 'react'; import lbry from 'lbry'; import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI'; -import FormField from 'component/formField'; import { Form, FormRow } from 'component/common/form'; import Link from 'component/link'; -import FormFieldPrice from 'component/formFieldPrice'; import Modal from 'modal/modal'; import { BusyMessage } from 'component/common'; import ChannelSection from './internal/channelSection'; @@ -516,367 +514,369 @@ class PublishForm extends React.PureComponent { submitLabel = !submitting ? __('Update') : __('Updating...'); } - return ( - <main className="main--single-column"> - <Form onSubmit={this.handleSubmit.bind(this)}> - <section className="card"> - <div className="card__title-primary"> - <h4>{__('Content')}</h4> - <div className="card__subtitle">{__('What are you publishing?')}</div> - </div> - <div className="card__content"> - <FormRow - name="file" - ref="file" - type="file" - onChange={event => { - this.onFileChange(event); - }} - helper={ - this.myClaimExists() - ? __( - "If you don't choose a file, the file from your existing claim will be used." - ) - : null - } - /> - </div> - {!this.state.hasFile && !this.myClaimExists() ? null : ( - <div> - <div className="card__content"> - <FormRow - ref="meta_title" - label={__('Title')} - type="text" - name="title" - value={this.state.meta_title} - placeholder="Titular Title" - onChange={event => { - this.handleMetadataChange(event); - }} - /> - </div> - <div className="card__content"> - <FormRow - type="text" - label={__('Thumbnail URL')} - name="thumbnail" - value={this.state.meta_thumbnail} - placeholder="http://spee.ch/mylogo" - onChange={event => { - this.handleMetadataChange(event); - }} - /> - </div> - <div className="card__content"> - <FormRow - type="SimpleMDE" - label={__('Description')} - ref="meta_description" - name="description" - value={this.state.meta_description} - placeholder={__('Description of your content')} - onChange={text => { - this.handleDescriptionChanged(text); - }} - /> - </div> - <div className="card__content"> - <FormRow - label={__('Language')} - type="select" - value={this.state.meta_language} - name="language" - onChange={event => { - this.handleMetadataChange(event); - }} - > - <option value="en">{__('English')}</option> - <option value="zh">{__('Chinese')}</option> - <option value="fr">{__('French')}</option> - <option value="de">{__('German')}</option> - <option value="jp">{__('Japanese')}</option> - <option value="ru">{__('Russian')}</option> - <option value="es">{__('Spanish')}</option> - </FormRow> - </div> - <div className="card__content"> - <FormRow - type="select" - label={__('Maturity')} - value={this.state.meta_nsfw} - name="nsfw" - onChange={event => { - this.handleMetadataChange(event); - }} - > - {/* <option value=""></option> */} - <option value="0">{__('All Ages')}</option> - <option value="1">{__('Adults Only')}</option> - </FormRow> - </div> - </div> - )} - </section> + return null; - <section className="card"> - <div className="card__title-primary"> - <h4>{__('Price')}</h4> - <div className="card__subtitle">{__('How much does this content cost?')}</div> - </div> - <div className="card__content"> - <FormRow - label={__('Free')} - type="radio" - name="isFree" - onChange={() => this.handleFeePrefChange(false)} - checked={!this.state.isFee} - /> - <FormField - type="radio" - name="isFree" - label={!this.state.isFee ? __('Choose price...') : __('Price ')} - onChange={() => { - this.handleFeePrefChange(true); - }} - checked={this.state.isFee} - /> - <span className={!this.state.isFee ? 'hidden' : ''}> - <FormFieldPrice - min="0" - defaultValue={{ - amount: this._defaultPaidPrice, - currency: 'LBC', - }} - onChange={val => this.handleFeeChange(val)} - /> - </span> - {this.state.isFee && this.state.feeCurrency.toUpperCase() != 'LBC' ? ( - <div className="form-field__helper"> - {__( - 'All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.' - )} - </div> - ) : null} - </div> - </section> - <section className="card"> - <div className="card__title-primary"> - <h4>{__('License')}</h4> - </div> - <div className="card__content"> - <FormRow - type="select" - value={this.state.licenseType} - ref={row => { - this._meta_license = row; - }} - onChange={event => { - this.handleLicenseTypeChange(event); - }} - > - <option>{__('None')}</option> - <option value="publicDomain">{__('Public Domain')}</option> - <option - value="cc-by" - data-url="https://creativecommons.org/licenses/by/4.0/legalcode" - > - {__('Creative Commons Attribution 4.0 International')} - </option> - <option - value="cc-by-sa" - data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode" - > - {__('Creative Commons Attribution-ShareAlike 4.0 International')} - </option> - <option - value="cc-by-nd" - data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode" - > - {__('Creative Commons Attribution-NoDerivatives 4.0 International')} - </option> - <option - value="cc-by-nc" - data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode" - > - {__('Creative Commons Attribution-NonCommercial 4.0 International')} - </option> - <option - value="cc-by-nc-sa" - data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode" - > - {__('Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International')} - </option> - <option - value="cc-by-nc-nd" - data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode" - > - {__('Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International')} - </option> - <option value="copyright">{__('Copyrighted...')}</option> - <option value="other">{__('Other...')}</option> - </FormRow> - - {this.state.licenseType == 'copyright' ? ( - <FormRow - label={__('Copyright notice')} - type="text" - name="copyright-notice" - value={this.state.copyrightNotice} - onChange={event => { - this.handleCopyrightNoticeChange(event); - }} - /> - ) : null} - - {this.state.licenseType == 'other' ? ( - <FormRow - label={__('License description')} - type="text" - name="other-license-description" - value={this.state.otherLicenseDescription} - onChange={event => { - this.handleOtherLicenseDescriptionChange(event); - }} - /> - ) : null} - - {this.state.licenseType == 'other' ? ( - <FormRow - label={__('License URL')} - type="text" - name="other-license-url" - value={this.state.otherLicenseUrl} - onChange={event => { - this.handleOtherLicenseUrlChange(event); - }} - /> - ) : null} - </div> - </section> - - <ChannelSection - {...this.props} - handleChannelChange={this.handleChannelChange.bind(this)} - channel={this.state.channel} - /> - - <section className="card"> - <div className="card__title-primary"> - <h4>{__('Content URL')}</h4> - <div className="card__subtitle"> - {__( - 'This is the exact address where people find your content (ex. lbry://myvideo).' - )}{' '} - <Link label={__('Learn more')} href="https://lbry.io/faq/naming" />. - </div> - </div> - <div className="card__content"> - <FormRow - prefix={`lbry://${ - this.state.channel === 'anonymous' ? '' : `${this.state.channel}/` - }`} - type="text" - ref="name" - placeholder="myname" - value={this.state.rawName} - onChange={event => { - this.handleNameChange(event); - }} - helper={this.getNameBidHelpText()} - /> - </div> - {this.state.rawName ? ( - <div className="card__content"> - <FormRow - ref="bid" - type="number" - step="any" - label={__('Deposit')} - postfix="LBC" - onChange={event => { - this.handleBidChange(event); - }} - value={this.state.bid} - placeholder={this.claim() ? this.topClaimValue() + 10 : 100} - helper={lbcInputHelp} - min="0" - /> - </div> - ) : ( - '' - )} - </section> - - <section className="card"> - <div className="card__title-primary"> - <h4>{__('Terms of Service')}</h4> - </div> - <div className="card__content"> - <FormRow - ref="tosAgree" - label={ - <span> - {__('I agree to the')}{' '} - <Link - href="https://www.lbry.io/termsofservice" - label={__('LBRY terms of service')} - /> - </span> - } - type="checkbox" - checked={this.state.tosAgree} - onChange={event => { - this.handleTOSChange(event); - }} - /> - </div> - </section> - - <div className="card-series-submit"> - <Link - type="submit" - label={!this.state.submitting ? __('Publish') : __('Publishing...')} - disabled={ - this.props.balance <= 0 || - this.state.submitting || - (this.state.uri && this.props.resolvingUris.indexOf(this.state.uri) !== -1) || - (this.claim() && !this.topClaimIsMine() && this.state.bid <= this.topClaimValue()) - } - /> - <Link button="cancel" onClick={this.props.back} label={__('Cancel')} /> - </div> - </Form> - - <Modal - isOpen={this.state.modal == 'publishStarted'} - contentLabel={__('File published')} - onConfirmed={event => { - this.handlePublishStartedConfirmed(event); - }} - > - <p> - {__('Your file has been published to LBRY at the address')}{' '} - <code>{this.state.uri}</code>! - </p> - <p> - {__( - 'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.' - )} - </p> - </Modal> - <Modal - isOpen={this.state.modal == 'error'} - contentLabel={__('Error publishing file')} - onConfirmed={event => { - this.closeModal(event); - }} - > - {__('The following error occurred when attempting to publish your file')}:{' '} - {this.state.errorMessage} - </Modal> - </main> - ); + // return ( + // <main className="main--single-column"> + // <Form onSubmit={this.handleSubmit.bind(this)}> + // <section className="card"> + // <div className="card__title-primary"> + // <h4>{__('Content')}</h4> + // <div className="card__subtitle">{__('What are you publishing?')}</div> + // </div> + // <div className="card__content"> + // <FormRow + // name="file" + // ref="file" + // type="file" + // onChange={event => { + // this.onFileChange(event); + // }} + // helper={ + // this.myClaimExists() + // ? __( + // "If you don't choose a file, the file from your existing claim will be used." + // ) + // : null + // } + // /> + // </div> + // {!this.state.hasFile && !this.myClaimExists() ? null : ( + // <div> + // <div className="card__content"> + // <FormRow + // ref="meta_title" + // label={__('Title')} + // type="text" + // name="title" + // value={this.state.meta_title} + // placeholder="Titular Title" + // onChange={event => { + // this.handleMetadataChange(event); + // }} + // /> + // </div> + // <div className="card__content"> + // <FormRow + // type="text" + // label={__('Thumbnail URL')} + // name="thumbnail" + // value={this.state.meta_thumbnail} + // placeholder="http://spee.ch/mylogo" + // onChange={event => { + // this.handleMetadataChange(event); + // }} + // /> + // </div> + // <div className="card__content"> + // <FormRow + // type="SimpleMDE" + // label={__('Description')} + // ref="meta_description" + // name="description" + // value={this.state.meta_description} + // placeholder={__('Description of your content')} + // onChange={text => { + // this.handleDescriptionChanged(text); + // }} + // /> + // </div> + // <div className="card__content"> + // <FormRow + // label={__('Language')} + // type="select" + // value={this.state.meta_language} + // name="language" + // onChange={event => { + // this.handleMetadataChange(event); + // }} + // > + // <option value="en">{__('English')}</option> + // <option value="zh">{__('Chinese')}</option> + // <option value="fr">{__('French')}</option> + // <option value="de">{__('German')}</option> + // <option value="jp">{__('Japanese')}</option> + // <option value="ru">{__('Russian')}</option> + // <option value="es">{__('Spanish')}</option> + // </FormRow> + // </div> + // <div className="card__content"> + // <FormRow + // type="select" + // label={__('Maturity')} + // value={this.state.meta_nsfw} + // name="nsfw" + // onChange={event => { + // this.handleMetadataChange(event); + // }} + // > + // {/* <option value=""></option> */} + // <option value="0">{__('All Ages')}</option> + // <option value="1">{__('Adults Only')}</option> + // </FormRow> + // </div> + // </div> + // )} + // </section> + // + // <section className="card"> + // <div className="card__title-primary"> + // <h4>{__('Price')}</h4> + // <div className="card__subtitle">{__('How much does this content cost?')}</div> + // </div> + // <div className="card__content"> + // <FormRow + // label={__('Free')} + // type="radio" + // name="isFree" + // onChange={() => this.handleFeePrefChange(false)} + // checked={!this.state.isFee} + // /> + // <FormField + // type="radio" + // name="isFree" + // label={!this.state.isFee ? __('Choose price...') : __('Price ')} + // onChange={() => { + // this.handleFeePrefChange(true); + // }} + // checked={this.state.isFee} + // /> + // <span className={!this.state.isFee ? 'hidden' : ''}> + // <FormFieldPrice + // min="0" + // defaultValue={{ + // amount: this._defaultPaidPrice, + // currency: 'LBC', + // }} + // onChange={val => this.handleFeeChange(val)} + // /> + // </span> + // {this.state.isFee && this.state.feeCurrency.toUpperCase() != 'LBC' ? ( + // <div className="form-field__helper"> + // {__( + // 'All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.' + // )} + // </div> + // ) : null} + // </div> + // </section> + // <section className="card"> + // <div className="card__title-primary"> + // <h4>{__('License')}</h4> + // </div> + // <div className="card__content"> + // <FormRow + // type="select" + // value={this.state.licenseType} + // ref={row => { + // this._meta_license = row; + // }} + // onChange={event => { + // this.handleLicenseTypeChange(event); + // }} + // > + // <option>{__('None')}</option> + // <option value="publicDomain">{__('Public Domain')}</option> + // <option + // value="cc-by" + // data-url="https://creativecommons.org/licenses/by/4.0/legalcode" + // > + // {__('Creative Commons Attribution 4.0 International')} + // </option> + // <option + // value="cc-by-sa" + // data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode" + // > + // {__('Creative Commons Attribution-ShareAlike 4.0 International')} + // </option> + // <option + // value="cc-by-nd" + // data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode" + // > + // {__('Creative Commons Attribution-NoDerivatives 4.0 International')} + // </option> + // <option + // value="cc-by-nc" + // data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode" + // > + // {__('Creative Commons Attribution-NonCommercial 4.0 International')} + // </option> + // <option + // value="cc-by-nc-sa" + // data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode" + // > + // {__('Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International')} + // </option> + // <option + // value="cc-by-nc-nd" + // data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode" + // > + // {__('Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International')} + // </option> + // <option value="copyright">{__('Copyrighted...')}</option> + // <option value="other">{__('Other...')}</option> + // </FormRow> + // + // {this.state.licenseType == 'copyright' ? ( + // <FormRow + // label={__('Copyright notice')} + // type="text" + // name="copyright-notice" + // value={this.state.copyrightNotice} + // onChange={event => { + // this.handleCopyrightNoticeChange(event); + // }} + // /> + // ) : null} + // + // {this.state.licenseType == 'other' ? ( + // <FormRow + // label={__('License description')} + // type="text" + // name="other-license-description" + // value={this.state.otherLicenseDescription} + // onChange={event => { + // this.handleOtherLicenseDescriptionChange(event); + // }} + // /> + // ) : null} + // + // {this.state.licenseType == 'other' ? ( + // <FormRow + // label={__('License URL')} + // type="text" + // name="other-license-url" + // value={this.state.otherLicenseUrl} + // onChange={event => { + // this.handleOtherLicenseUrlChange(event); + // }} + // /> + // ) : null} + // </div> + // </section> + // + // <ChannelSection + // {...this.props} + // handleChannelChange={this.handleChannelChange.bind(this)} + // channel={this.state.channel} + // /> + // + // <section className="card"> + // <div className="card__title-primary"> + // <h4>{__('Content URL')}</h4> + // <div className="card__subtitle"> + // {__( + // 'This is the exact address where people find your content (ex. lbry://myvideo).' + // )}{' '} + // <Link label={__('Learn more')} href="https://lbry.io/faq/naming" />. + // </div> + // </div> + // <div className="card__content"> + // <FormRow + // prefix={`lbry://${ + // this.state.channel === 'anonymous' ? '' : `${this.state.channel}/` + // }`} + // type="text" + // ref="name" + // placeholder="myname" + // value={this.state.rawName} + // onChange={event => { + // this.handleNameChange(event); + // }} + // helper={this.getNameBidHelpText()} + // /> + // </div> + // {this.state.rawName ? ( + // <div className="card__content"> + // <FormRow + // ref="bid" + // type="number" + // step="any" + // label={__('Deposit')} + // postfix="LBC" + // onChange={event => { + // this.handleBidChange(event); + // }} + // value={this.state.bid} + // placeholder={this.claim() ? this.topClaimValue() + 10 : 100} + // helper={lbcInputHelp} + // min="0" + // /> + // </div> + // ) : ( + // '' + // )} + // </section> + // + // <section className="card"> + // <div className="card__title-primary"> + // <h4>{__('Terms of Service')}</h4> + // </div> + // <div className="card__content"> + // <FormRow + // ref="tosAgree" + // label={ + // <span> + // {__('I agree to the')}{' '} + // <Link + // href="https://www.lbry.io/termsofservice" + // label={__('LBRY terms of service')} + // /> + // </span> + // } + // type="checkbox" + // checked={this.state.tosAgree} + // onChange={event => { + // this.handleTOSChange(event); + // }} + // /> + // </div> + // </section> + // + // <div className="card-series-submit"> + // <Link + // type="submit" + // label={!this.state.submitting ? __('Publish') : __('Publishing...')} + // disabled={ + // this.props.balance <= 0 || + // this.state.submitting || + // (this.state.uri && this.props.resolvingUris.indexOf(this.state.uri) !== -1) || + // (this.claim() && !this.topClaimIsMine() && this.state.bid <= this.topClaimValue()) + // } + // /> + // <Link button="cancel" onClick={this.props.back} label={__('Cancel')} /> + // </div> + // </Form> + // + // <Modal + // isOpen={this.state.modal == 'publishStarted'} + // contentLabel={__('File published')} + // onConfirmed={event => { + // this.handlePublishStartedConfirmed(event); + // }} + // > + // <p> + // {__('Your file has been published to LBRY at the address')}{' '} + // <code>{this.state.uri}</code>! + // </p> + // <p> + // {__( + // 'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.' + // )} + // </p> + // </Modal> + // <Modal + // isOpen={this.state.modal == 'error'} + // contentLabel={__('Error publishing file')} + // onConfirmed={event => { + // this.closeModal(event); + // }} + // > + // {__('The following error occurred when attempting to publish your file')}:{' '} + // {this.state.errorMessage} + // </Modal> + // </main> + // ); } } diff --git a/src/renderer/component/rewardSummary/view.jsx b/src/renderer/component/rewardSummary/view.jsx index 289a04a23..5854f4399 100644 --- a/src/renderer/component/rewardSummary/view.jsx +++ b/src/renderer/component/rewardSummary/view.jsx @@ -13,7 +13,7 @@ const RewardSummary = (props: Props) => { return ( <section className="card card--section"> - <h2>{__('Rewards')}</h2> + <div className="card__title">{__('Rewards')}</div> <p className="card__subtitle"> {hasRewards ? ( <React.Fragment> diff --git a/src/renderer/component/router/view.jsx b/src/renderer/component/router/view.jsx index b65e830fe..48ae6db9d 100644 --- a/src/renderer/component/router/view.jsx +++ b/src/renderer/component/router/view.jsx @@ -22,7 +22,7 @@ import SubscriptionsPage from 'page/subscriptions'; const route = (page, routesMap) => { const component = routesMap[page]; - return component; + return component || DiscoverPage; }; const Router = props => { diff --git a/src/renderer/component/shapeShift/internal/active-shift.jsx b/src/renderer/component/shapeShift/internal/active-shift.jsx index ae2e83348..70efd847e 100644 --- a/src/renderer/component/shapeShift/internal/active-shift.jsx +++ b/src/renderer/component/shapeShift/internal/active-shift.jsx @@ -1,6 +1,7 @@ // @flow import * as React from 'react'; -import QRCode from 'qrcode.react'; +import QRCode from 'component/common/qr-code'; +import { FormRow } from 'component/common/form'; import * as statuses from 'constants/shape_shift'; import Address from 'component/address'; import Link from 'component/link'; @@ -92,12 +93,12 @@ class ActiveShapeShift extends React.PureComponent<Props> { originCoinDepositMax={originCoinDepositMax} /> - <div className="shapeshift__deposit-address-wrapper"> - <Address address={shiftDepositAddress} showCopyButton /> - <div className="shapeshift__qrcode"> + {shiftDepositAddress && ( + <FormRow verticallyCentered padded> + <Address address={shiftDepositAddress} showCopyButton /> <QRCode value={shiftDepositAddress} /> - </div> - </div> + </FormRow> + )} </div> )} @@ -115,9 +116,9 @@ class ActiveShapeShift extends React.PureComponent<Props> { <p>{__('Transaction complete! You should see the new LBC in your wallet.')}</p> </div> )} - <div className="card__actions card__actions--only-vertical"> + <div className="card__actions"> <Link - button={shiftState === statuses.COMPLETE ? 'primary' : 'alt'} + primary onClick={clearShapeShift} label={ shiftState === statuses.COMPLETE || shiftState === statuses.RECEIVED @@ -126,13 +127,11 @@ class ActiveShapeShift extends React.PureComponent<Props> { } /> {shiftOrderId && ( - <span className="shapeshift__link"> <Link - button="text" + inverse label={__('View the status on Shapeshift.io')} href={`https://shapeshift.io/#/status/${shiftOrderId}`} /> - </span> )} {shiftState === statuses.NO_DEPOSITS && shiftReturnAddress && ( diff --git a/src/renderer/component/shapeShift/internal/form.jsx b/src/renderer/component/shapeShift/internal/form.jsx index 6a9cbcd4e..259a4cec3 100644 --- a/src/renderer/component/shapeShift/internal/form.jsx +++ b/src/renderer/component/shapeShift/internal/form.jsx @@ -1,7 +1,7 @@ // @flow import React from 'react'; import { getExampleAddress } from 'util/shape_shift'; -import { FormField, Submit } from 'component/common/form'; +import { FormField, FormRow, Submit } from 'component/common/form'; import type { ShapeShiftFormValues, Dispatch } from 'redux/actions/shape_shift'; import ShiftMarketInfo from './market_info'; @@ -50,59 +50,46 @@ export default (props: Props) => { <FormField prefix={__('Exchange')} postfix={__('for LBC')} - render={() => ( - <select - className="form-field__input form-field__input-select" - name="originCoin" - onChange={e => { - getCoinStats(e.target.value); - handleChange(e); - }} - > - {shiftSupportedCoins.map(coin => ( - <option key={coin} value={coin}> - {coin} - </option> - ))} - </select> - )} + type="select" + name="origin_coin" + onChange={e => { + getCoinStats(e.target.value); + handleChange(e); + }}> + {shiftSupportedCoins.map(coin => ( + <option key={coin} value={coin}> + {coin} + </option> + ))} + </FormField> + <ShiftMarketInfo + originCoin={originCoin} + shapeShiftRate={shapeShiftRate} + originCoinDepositFee={originCoinDepositFee} + originCoinDepositMin={originCoinDepositMin} + originCoinDepositMax={originCoinDepositMax} /> - <div> - <div className="shapeshift__tx-info"> - {!updating && - originCoinDepositMax && ( - <ShiftMarketInfo - originCoin={originCoin} - shapeShiftRate={shapeShiftRate} - originCoinDepositFee={originCoinDepositFee} - originCoinDepositMin={originCoinDepositMin} - originCoinDepositMax={originCoinDepositMax} - /> - )} - </div> - </div> + <FormRow padded> <FormField label={__('Return address')} error={touched.returnAddress && !!errors.returnAddress && errors.returnAddress} - render={() => ( - <input - type="text" - name="returnAddress" - placeholder={getExampleAddress(originCoin)} - onChange={handleChange} - onBlur={handleBlur} - value={values.returnAddress} - /> - )} + type="text" + name="return_address" + className="input--address" + placeholder={getExampleAddress(originCoin)} + onChange={handleChange} + onBlur={handleBlur} + value={values.returnAddress} /> + </FormRow> <span className="help"> <span> - ({__('optional but recommended')}) {__('We will return your')} {originCoin}{' '} + ({__('optional but recommended')})<br/>{__('We will return your')} {originCoin}{' '} {__("to this address if the transaction doesn't go through.")} </span> </span> - <div className="card__actions card__actions--only-vertical"> + <div className="card__actions"> <Submit label={__('Begin Conversion')} disabled={isSubmitting || !!Object.keys(errors).length} diff --git a/src/renderer/component/shapeShift/view.jsx b/src/renderer/component/shapeShift/view.jsx index 79fd3fadb..8107769c6 100644 --- a/src/renderer/component/shapeShift/view.jsx +++ b/src/renderer/component/shapeShift/view.jsx @@ -67,7 +67,7 @@ class ShapeShift extends React.PureComponent<Props> { return ( <section className="card card--section"> - <h2>{__('Convert Crypto to LBC')}</h2> + <div className="card__title">{__('Convert Crypto to LBC')}</div> <p className="card__subtitle"> {__('Powered by ShapeShift. Read our FAQ')}{' '} <Link fakeLink label={__('here')} href="https://lbry.io/faq/shapeshift" />. @@ -75,11 +75,9 @@ class ShapeShift extends React.PureComponent<Props> { shiftState !== 'complete' && <span>{__('This will update automatically.')}</span>} </p> - <div className="card__content shapeshift__content"> + <div className="card__content"> {error && <div className="form-field__error">{error}</div>} - {!loading && - !hasActiveShift && - !!shiftSupportedCoins.length && ( + {!hasActiveShift && ( <Formik onSubmit={createShapeShift} validate={validateShapeShiftForm} diff --git a/src/renderer/component/sideBar/view.jsx b/src/renderer/component/sideBar/view.jsx index 2844a6d7e..b92a06024 100644 --- a/src/renderer/component/sideBar/view.jsx +++ b/src/renderer/component/sideBar/view.jsx @@ -1,7 +1,9 @@ // @flow -import React from 'react'; +import * as React from 'react'; import Button from 'component/link'; import classnames from 'classnames'; +import Icon from 'component/common/icon'; +import { CSSTransitionGroup } from 'react-transition-group' type SideBarLink = { label: string, @@ -59,36 +61,44 @@ const SideBar = (props: Props) => { {navLinks.primary.map(({ label, path, active, icon }) => ( <li key={path} - className={classnames('nav__link nav__primary-link', { 'nav__link--active': active })} + className={classnames('nav__link nav__link--primary', { 'nav__link--active': active })} > <Button noStyle navigate={path} label={label} icon={icon} /> </li> ))} </ul> <hr /> - <ul className="nav__secondary"> + <ul> {navLinks.secondary.map(({ label, path, active, icon, subLinks = [] }) => ( <li - key={path} - className={classnames('nav__link nav__secondary-link', { - 'nav__link--active': active && !subLinks.length, + key={label} + className={classnames('nav__link', { + 'nav__link--active': active, })} > - <Button noStyle navigate={path} label={label} icon={icon} /> - {!!subLinks.length && - active && ( - <ul className="nav__sub"> - {subLinks.map(({ label: subLabel, path: subPath, active: subLinkActive }) => ( - <li - key={subPath} - className={classnames('nav__link nav__sub-link', { - 'nav__link--active': subLinkActive, - })} - > - <Button noStyle navigate={subPath} label={subLabel} /> - </li> - ))} + <Button noStyle navigate={path} label={label} icon={icon} /> + + {!!subLinks.length && active && ( + <CSSTransitionGroup + transitionAppear + transitionLeave + transitionAppearTimeout={300} + transitionEnterTimeout={300} + transitionLeaveTimeout={300} + transitionName="nav__sub"> + <ul key="0" className="nav__sub-links"> + {subLinks.map(({ label: subLabel, path: subPath, active: subLinkActive }) => ( + <li + key={subPath} + className={classnames('nav__link--sub', { + 'nav__link--active': subLinkActive, + })} + > + {subPath ? <Button noStyle navigate={subPath} label={subLabel} /> : <span>{subLabel}</span>} + </li> + ))} </ul> + </CSSTransitionGroup> )} </li> ))} @@ -98,4 +108,5 @@ const SideBar = (props: Props) => { ); }; + export default SideBar; diff --git a/src/renderer/component/transactionListRecent/view.jsx b/src/renderer/component/transactionListRecent/view.jsx index 564ba270f..5dd678583 100644 --- a/src/renderer/component/transactionListRecent/view.jsx +++ b/src/renderer/component/transactionListRecent/view.jsx @@ -22,7 +22,7 @@ class TransactionListRecent extends React.PureComponent<Props> { return ( <section className="card card--section"> - <h2>{__('Recent Transactions')}</h2> + <div className="card__title">{__('Recent Transactions')}</div> <div className="card__content"> {fetchingTransactions && <BusyMessage message={__('Loading transactions')} />} {!fetchingTransactions && ( diff --git a/src/renderer/component/walletAddress/view.jsx b/src/renderer/component/walletAddress/view.jsx index c666e13f4..eb1001b9a 100644 --- a/src/renderer/component/walletAddress/view.jsx +++ b/src/renderer/component/walletAddress/view.jsx @@ -20,9 +20,7 @@ class WalletAddress extends React.PureComponent<Props> { return ( <section className="card card--section"> - <div className="card__title-primary"> - <h2>{__('Receive Credits')}</h2> - </div> + <div className="card__title">{__('Receive Credits')}</div> <p className="card__subtitle"> {__('Use this wallet address to receive credits sent by another user (or yourself).')} </p> diff --git a/src/renderer/component/walletBalance/view.jsx b/src/renderer/component/walletBalance/view.jsx index d3cc40c49..a76abdb44 100644 --- a/src/renderer/component/walletBalance/view.jsx +++ b/src/renderer/component/walletBalance/view.jsx @@ -10,7 +10,7 @@ const WalletBalance = (props: Props) => { const { balance } = props; return ( <section className="card card--section"> - <h2>{__('Balance')}</h2> + <div className="card__title">{__('Balance')}</div> <span className="card__subtitle">{__('You currently have')}</span> <div className="card__content"> {(balance || balance === 0) && <CreditAmount large amount={balance} precision={8} />} diff --git a/src/renderer/component/walletSend/view.jsx b/src/renderer/component/walletSend/view.jsx index ec1114202..43a41870f 100644 --- a/src/renderer/component/walletSend/view.jsx +++ b/src/renderer/component/walletSend/view.jsx @@ -29,9 +29,7 @@ class WalletSend extends React.PureComponent<Props> { render() { return ( <section className="card card--section"> - <div className="card__title-primary"> - <h2>{__('Send Credits')}</h2> - </div> + <div className="card__title">{__('Send Credits')}</div> <div className="card__content"> <Formik initialValues={{ diff --git a/src/renderer/page/backup/view.jsx b/src/renderer/page/backup/view.jsx index a0581212b..991e1231b 100644 --- a/src/renderer/page/backup/view.jsx +++ b/src/renderer/page/backup/view.jsx @@ -1,45 +1,54 @@ -import React from 'react'; +// @flow +import * as React from 'react'; import Link from 'component/link'; import Page from 'component/page'; -class BackupPage extends React.PureComponent { +type Props = { + daemonSettings: { + lbryum_wallet_dir: ?string + } +} + +class BackupPage extends React.PureComponent<Props> { render() { const { daemonSettings } = this.props; + const { lbryum_wallet_dir } = daemonSettings; - if (!daemonSettings || Object.keys(daemonSettings).length === 0) { - return ( - <main className="main--single-column"> - <SubHeader /> - <span className="empty">{__('Failed to load settings.')}</span> - </main> - ); - } + const noDaemonSettings = Object.keys(daemonSettings).length === 0; return ( <Page> <section className="card card--section"> - <div className="card__title-primary"> - <h3>{__('Backup Your LBRY Credits')}</h3> + {noDaemonSettings ? ( + <div className="card__title">{__('Failed to load settings.')}</div> + ) : ( + <React.Fragment> + <div className="card__title"> + {__('Backup Your LBRY Credits')} </div> + <p className="card__subtitle"> + {__( + 'Your LBRY credits are controllable by you and only you, via wallet file(s) stored locally on your computer.' + )} + </p> <div className="card__content"> - <p> - {__( - 'Your LBRY credits are controllable by you and only you, via wallet file(s) stored locally on your computer.' - )} - </p> <p> {__( 'Currently, there is no automatic wallet backup. If you lose access to these files, you will lose your credits permanently.' )} </p> + </div> + <div className="card__content"> <p> {__( 'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:' )} </p> <p> - <code>{__(`${daemonSettings.lbryum_wallet_dir}`)}</code> + <code>{lbryum_wallet_dir}</code> </p> + </div> + <div className="card__content"> <p> <strong> {__( @@ -50,11 +59,14 @@ class BackupPage extends React.PureComponent { <p> For more details on backing up and best practices,{' '} <Link + fakeLink href="https://lbry.io/faq/how-to-backup-wallet" label={__('see this article')} />. </p> </div> + </React.Fragment> + )} </section> </Page> ); diff --git a/src/renderer/page/getCredits/view.jsx b/src/renderer/page/getCredits/view.jsx index ebc16acfe..82429c86f 100644 --- a/src/renderer/page/getCredits/view.jsx +++ b/src/renderer/page/getCredits/view.jsx @@ -9,16 +9,16 @@ const GetCreditsPage = props => ( <RewardSummary /> <ShapeShift /> <section className="card card--section"> - <div className="card__title-primary"> - <h2>{__('From External Wallet')}</h2> + <div className="card__title"> + {__('From External Wallet')} </div> <div className="card__actions"> <Link navigate="/send" label={__('Send / Receive')} /> </div> </section> <section className="card card--section"> - <div className="card__title-primary"> - <h2>{__('More ways to get LBRY Credits')}</h2> + <div className="card__title"> + {__('More ways to get LBRY Credits')} </div> <div className="card__content"> <p> diff --git a/src/renderer/page/help/view.jsx b/src/renderer/page/help/view.jsx index f0b0046f7..3351981cd 100644 --- a/src/renderer/page/help/view.jsx +++ b/src/renderer/page/help/view.jsx @@ -19,7 +19,7 @@ class HelpPage extends React.PureComponent { }; } - componentWillMount() { + componentDidMount() { lbry.getAppVersionInfo().then(({ remoteVersion, localVersion, upgradeAvailable }) => { this.setState({ uiVersion: localVersion, @@ -71,76 +71,71 @@ class HelpPage extends React.PureComponent { return ( <Page> - <section className="card"> - <div className="card__title-primary"> - <h3>{__('Read the FAQ')}</h3> + <section className="card card--section"> + <div className="card__title"> + {__('Read the FAQ')} </div> - <div className="card__content"> - <p>{__('Our FAQ answers many common questions.')}</p> - <p> - <Link - href="https://lbry.io/faq" - label={__('Read the FAQ')} - icon="icon-question" - button="alt" - /> - </p> - </div> - </section> - <section className="card"> - <div className="card__title-primary"> - <h3>{__('Get Live Help')}</h3> - </div> - <div className="card__content"> - <p> - {__('Live help is available most hours in the')} <strong>#help</strong>{' '} - {__('channel of our Discord chat room.')} - </p> - <p> - <Link - button="alt" - label={__('Join Our Chat')} - icon="icon-comments" - href="https://chat.lbry.io" - /> - </p> - </div> - </section> - <section className="card"> - <div className="card__title-primary"> - <h3>{__('Report a Bug')}</h3> - </div> - <div className="card__content"> - <p>{__('Did you find something wrong?')}</p> - <p> - <Link - navigate="/report" - label={__('Submit a Bug Report')} - icon="icon-bug" - button="alt" - /> - </p> - <div className="meta">{__('Thanks! LBRY is made by its users.')}</div> + <p className="card__subtitle">{__('Our FAQ answers many common questions.')}</p> + + <div className="card__actions"> + <Link + href="https://lbry.io/faq" + label={__('Read the FAQ')} + icon="HelpCircle" + button="alt" + /> </div> </section> - <section className="card"> - <div className="card__title-primary"> - <h3>{__('About')}</h3> + <section className="card card--section"> + <div className="card__title"> + {__('Get Live Help')} + </div> + <p className="card__subtitle"> + {__('Live help is available most hours in the')} <strong>#help</strong>{' '} + {__('channel of our Discord chat room.')} + </p> + <div className="card__actions"> + <Link + label={__('Join Our Chat')} + icon="MessageCircle" + href="https://chat.lbry.io" + /> + </div> + </section> + + <section className="card card--section"> + <div className="card__title"> + {__('Report a Bug')} + </div> + <p className="card__subtitle">{__('Did you find something wrong?')}</p> + + <div className="card__actions"> + <Link + navigate="/report" + label={__('Submit a Bug Report')} + icon="Flag" + button="alt" + /> + </div> + <div className="card__meta">{__('Thanks! LBRY is made by its users.')}</div> + </section> + + <section className="card card--section"> + <div className="card__title"> + {__('About')} </div> <div className="card__content"> - {this.state.upgradeAvailable === null ? ( - '' - ) : this.state.upgradeAvailable ? ( - <p> - {__('A newer version of LBRY is available.')}{' '} - <Link href={newVerLink} label={__('Download now!')} /> - </p> - ) : ( - <p>{__('Your copy of LBRY is up to date.')}</p> - )} + {this.state.upgradeAvailable !== null && this.state.upgradeAvailable ? ( + <p> + {__('A newer version of LBRY is available.')}{' '} + <Link href={newVerLink} label={__('Download now!')} /> + </p> + ) : ( + <p>{__('Your LBRY app is up to date.')}</p> + )} {this.state.uiVersion && ver ? ( - <table className="table-standard table-stretch table-standard--definition-list"> + <table className="card__content table-standard table-stretch table-standard--definition-list"> <tbody> <tr> <th>{__('App')}</th> @@ -171,9 +166,9 @@ class HelpPage extends React.PureComponent { <th>{__('Reward Eligible')}</th> <td> {user && user.is_reward_approved ? ( - <Icon icon="icon-check" /> + __("Yes") ) : ( - <Icon icon="icon-ban" /> + __("No") )} </td> </tr> @@ -189,7 +184,7 @@ class HelpPage extends React.PureComponent { <th>{__('Access Token')}</th> <td> {this.state.accessTokenHidden && ( - <Link label={__('show')} onClick={this.showAccessToken.bind(this)} /> + <Link fakeLink label={__('View')} onClick={this.showAccessToken.bind(this)} /> )} {!this.state.accessTokenHidden && accessToken && ( diff --git a/src/renderer/page/settings/view.jsx b/src/renderer/page/settings/view.jsx index 78960140c..23bc298b4 100644 --- a/src/renderer/page/settings/view.jsx +++ b/src/renderer/page/settings/view.jsx @@ -233,7 +233,6 @@ class SettingsPage extends React.PureComponent<Props, State> { <section className="card card--section"> <div className="card__title">{__('Content Settings')}</div> - <div className="card__content"> <FormField type="checkbox" name="show_unavailable" @@ -251,7 +250,6 @@ class SettingsPage extends React.PureComponent<Props, State> { 'NSFW content may include nudity, intense sexuality, profanity, or other adult content. By displaying NSFW content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ' )} /> - </div> </section> <section className="card card--section"> diff --git a/src/renderer/redux/reducers/settings.js b/src/renderer/redux/reducers/settings.js index 73cf69209..357236f23 100644 --- a/src/renderer/redux/reducers/settings.js +++ b/src/renderer/redux/reducers/settings.js @@ -27,6 +27,7 @@ const defaultState = { }, isNight: false, languages: {}, + daemonSettings: {} }; reducers[ACTIONS.DAEMON_SETTINGS_RECEIVED] = (state, action) => diff --git a/src/renderer/redux/selectors/navigation.js b/src/renderer/redux/selectors/navigation.js index aec05c82f..58dc75224 100644 --- a/src/renderer/redux/selectors/navigation.js +++ b/src/renderer/redux/selectors/navigation.js @@ -60,25 +60,42 @@ export const selectNavLinks = createSelector( 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(); + const isMyLbryPage = page => + page === 'downloaded' || + page === 'published' || + page === 'settings'; + + + const previousStack = historyStack.slice().reverse(); + + const getPreviousSubLinkPath = (checkIfValidPage) => { 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; + if (checkIfValidPage(pageInStack)) { + return currentStackItem.path; } } } + // Gets the last active sublink in a section + const getActiveSublink = (category) => { + if (category === 'wallet') { + const previousPath = getPreviousSubLinkPath(isWalletPage); + return previousPath ? previousPath : '/wallet'; + } else if (category === 'myLbry') { + const previousPath = getPreviousSubLinkPath(isMyLbryPage); + return previousPath ? previousPath : '/downloaded'; + } + + return undefined; + } + + const isCurrentlyWalletPage = isWalletPage(currentPage); + const isCurrentlyMyLbryPage = isMyLbryPage(currentPage); + const walletSubLinks = [ { label: 'Overview', @@ -101,12 +118,30 @@ export const selectNavLinks = createSelector( active: currentPage === 'rewards', }, { - label: 'My Transactions', + label: 'Transactions', path: '/history', active: currentPage === 'history', }, ]; + const myLbrySubLinks = [ + { + label: 'Downloads', + path: '/downloaded', + active: currentPage === 'downloaded', + }, + { + label: 'Publishes', + path: '/published', + active: currentPage === 'published', + }, + { + label: 'Settings', + path: '/settings', + active: currentPage === 'settings', + }, + ] + const navLinks = { primary: [ { @@ -125,27 +160,20 @@ export const selectNavLinks = createSelector( 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', + subLinks: walletSubLinks, + path: isCurrentlyWalletPage ? '/wallet' : getActiveSublink('wallet'), + active: isWalletPage(currentPage) }, { - label: 'Publish', - path: '/publish', - active: currentPage === 'publish', - icon: 'UploadCloud', - }, - { - label: 'Settings', - path: '/settings', - active: currentPage === 'settings', + label: 'My LBRY', icon: 'Settings', + subLinks: myLbrySubLinks, + path: isCurrentlyMyLbryPage ? '/downloaded' : getActiveSublink('myLbry'), + active: isMyLbryPage(currentPage) }, { - label: 'Backup Wallet', + label: 'Backup', path: '/backup', active: currentPage === 'backup', icon: 'Save', @@ -158,6 +186,7 @@ export const selectNavLinks = createSelector( }, ], }; + return navLinks; } ); diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss index 4a8d92c9e..c8e5c3724 100644 --- a/src/renderer/scss/_gui.scss +++ b/src/renderer/scss/_gui.scss @@ -54,6 +54,10 @@ body { overflow: hidden; } +* { + box-sizing: border-box; +} + h1, h2, h3, diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss index 32dac4f48..9044ab34e 100644 --- a/src/renderer/scss/_vars.scss +++ b/src/renderer/scss/_vars.scss @@ -88,7 +88,7 @@ $width-page-constrained: 800px; /* Button */ --btn-primary-color: #fff; --button-alt-color: var(--text-color); - --btn-primary-bg: var(--color-primary-dark); + --btn-primary-bg: var(--color-primary); --btn-inverse-color: var(--color-primary-dark); --btn-inverse-bg: var(--color-white); --btn-radius: 20px; diff --git a/src/renderer/scss/all.scss b/src/renderer/scss/all.scss index 89a8fc12e..a5741d061 100644 --- a/src/renderer/scss/all.scss +++ b/src/renderer/scss/all.scss @@ -21,8 +21,5 @@ @import 'component/_markdown-editor.scss'; @import 'component/_scrollbar.scss'; @import 'component/_divider.scss'; -@import 'component/_checkbox.scss'; -@import 'component/_radio.scss'; -@import 'component/_shapeshift.scss'; @import 'component/_spinner.scss'; @import 'component/_nav.scss'; diff --git a/src/renderer/scss/component/_button.scss b/src/renderer/scss/component/_button.scss index 7e0336834..04248fbbd 100644 --- a/src/renderer/scss/component/_button.scss +++ b/src/renderer/scss/component/_button.scss @@ -37,7 +37,11 @@ min-width: var(--btn-height); border-radius: var(--btn-radius); color: var(--btn-primary-color); - background-color: var(--btn-primary-bg); + + // TODO: Why does using --color-primary not work here? something is being overriden + // background-color: var(--color-primary); + background-color: #44b098; + display: flex; align-items: center; justify-content: center; @@ -111,7 +115,6 @@ &:hover { box-shadow: none; - color: var(--color-primary); } } diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss index 5bf0778d7..a4457283c 100644 --- a/src/renderer/scss/component/_card.scss +++ b/src/renderer/scss/component/_card.scss @@ -67,8 +67,8 @@ } .card__title { - font-size: 1.5em; - font-weight: 800; + font-size: 1.2em; + font-weight: 700; padding: 0; } @@ -88,6 +88,12 @@ padding-top: 0; } +.card__meta { + color: var(--color-help); + font-size: 0.85em; + padding-top: $spacing-vertical * 2/3; +} + // .card-media__internal__links should always be inside a card .card { .card-media__internal-links { @@ -109,10 +115,6 @@ display: flex; justify-content: space-between; align-items: center; - - .card__actions .btn:not(:first-of-type) { - margin-left: $spacing-vertical / 3; - } } .card__content { @@ -137,10 +139,14 @@ .card__actions { margin-top: var(--card-margin); display: flex; + + .btn:nth-child(n + 2) { + margin-left: $spacing-vertical / 3; + } } .card__actions--no-margin { - magin-top: 0; + margin-top: 0; } .card__actions--vertical { diff --git a/src/renderer/scss/component/_checkbox.scss b/src/renderer/scss/component/_checkbox.scss deleted file mode 100644 index b72f7c896..000000000 --- a/src/renderer/scss/component/_checkbox.scss +++ /dev/null @@ -1,69 +0,0 @@ -*, -*:before, -*:after { - box-sizing: border-box; -} - -$md-checkbox-checked-color: var(--color-primary); -$md-checkbox-border-color: var(--input-border-color); -$md-checkbox-size: 20px; -$md-checkbox-padding: 4px; -$md-checkmark-width: 2px; -$md-checkmark-color: #fff; - -.form-field--checkbox { - position: relative; - - label { - cursor: pointer; - &:before, - &:after { - content: ''; - position: absolute; - left: 0; - top: 0; - } - - &:before { - // box - width: $md-checkbox-size; - height: $md-checkbox-size; - background: transparent; - border: 2px solid $md-checkbox-border-color; - border-radius: 2px; - cursor: pointer; - transition: background 0.3s; - } - - &:after { - // checkmark - } - } - - input[type='checkbox'] { - outline: 0; - visibility: hidden; - margin-right: 16px; - - &:checked { - + label:before { - background: $md-checkbox-checked-color; - border: none; - } - + label:after { - $md-checkmark-size: $md-checkbox-size - 2*$md-checkbox-padding; - - transform: rotate(-45deg); - - top: ($md-checkbox-size / 2) - ($md-checkmark-size / 4) - $md-checkbox-size/10; - left: $md-checkbox-padding; - width: $md-checkmark-size; - height: $md-checkmark-size / 2; - - border: $md-checkmark-width solid $md-checkmark-color; - border-top-style: none; - border-right-style: none; - } - } - } -} diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss index ff2e743a1..1c1420878 100644 --- a/src/renderer/scss/component/_form-field.scss +++ b/src/renderer/scss/component/_form-field.scss @@ -14,6 +14,16 @@ &.form-row--centered { align-items: center; } + + .form-field--strech { + flex: 1; + } +} + +.form-field { + label { + cursor: pointer; + } } .form-field__input { @@ -26,18 +36,12 @@ } } -.form-field { - label { - cursor: pointer; - } -} - .form-field__error { color: var(--color-error); } .form-field__label { - color: var(--color-grey-dark); + color: var(--color-black); } .form-field__help { diff --git a/src/renderer/scss/component/_nav.scss b/src/renderer/scss/component/_nav.scss index 928d7a9f8..c347451ec 100644 --- a/src/renderer/scss/component/_nav.scss +++ b/src/renderer/scss/component/_nav.scss @@ -1,51 +1,84 @@ .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; + margin: $spacing-vertical $spacing-vertical * 2/3; } } .nav__actions-top { + height: var(--header-height); display: flex; justify-content: space-between; align-items: center; - padding: 0 5px; + padding: 0 $spacing-vertical * 1/3; } .nav__actions-history { display: flex; + + .btn { + margin-left: $spacing-vertical * 1/3; + } } +// Sidebar links .nav__primary { - padding-top: $spacing-vertical * 3; + padding-top: $spacing-vertical; } .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 { + .btn:hover { color: var(--color-black); } + + .btn__label { + margin-left: $spacing-vertical * 1/3; + } +} + +.nav__link--primary { + font-weight: bold; +} + +.nav__link--sub { + font-size: .9em; + font-weight: 400; + margin-left: 5px; + color: var(--color-grey-dark); + padding: 5px $spacing-vertical * 2/3; } .nav__link--active { color: var(--color-black); } +.nav__sub-links { + padding-top: $spacing-vertical * 1/3; +} + +// Sub links animations +// The -appear, -leave classes are added by 'react-transition-group' +.nav__sub-appear, +.nav__sub-leave { + max-height: 0; + opacity: 0; +} + +.nav__sub-appear.nav__sub-appear-active { + // using max-height is a hack to animate to height "auto" + // Needs to be some arbitrarily large height + max-height: 500px; + opacity: 1; + transition: max-height .5s ease-in-out, opacity .5s ease-in-out; +} + .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/_radio.scss b/src/renderer/scss/component/_radio.scss deleted file mode 100644 index 4d511816f..000000000 --- a/src/renderer/scss/component/_radio.scss +++ /dev/null @@ -1,54 +0,0 @@ -$md-radio-checked-color: var(--color-primary); -$md-radio-border-color: var(--input-border-color); -$md-radio-size: 20px; -$md-radio-checked-size: 10px; -$md-radio-ripple-size: 15px; - -.form-field--radio { - position: relative; - - label { - cursor: pointer; - - &:before, - &:after { - content: ''; - position: absolute; - left: 0; - top: 0; - border-radius: 50%; - transition: all 0.3s ease; - transition-property: transform, border-color; - } - - &:before { - width: $md-radio-size; - height: $md-radio-size; - background: transparent; - border: 2px solid $md-radio-border-color; - cursor: pointer; - } - - &:after { - top: $md-radio-size / 2 - $md-radio-checked-size / 2; - left: $md-radio-size / 2 - $md-radio-checked-size / 2; - width: $md-radio-checked-size; - height: $md-radio-checked-size; - transform: scale(0); - background: $md-radio-checked-color; - } - } - - input[type='radio'] { - visibility: hidden; - margin-right: 16px; - - &:checked + label:before { - border-color: $md-radio-checked-color; - } - - &:checked + label:after { - transform: scale(1); - } - } -} diff --git a/yarn.lock b/yarn.lock index a774567a4..a1f910fc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1819,6 +1819,10 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" +chain-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" + chainsaw@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" @@ -2756,6 +2760,10 @@ dom-converter@~0.1: dependencies: utila "~0.3" +dom-helpers@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" + dom-scroll-into-view@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e" @@ -7342,7 +7350,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.5.1, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0: +prop-types@^15.5.1, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" dependencies: @@ -7613,6 +7621,16 @@ react-simplemde-editor@^3.6.11: react "^0.14.2" simplemde "^1.11.2" +react-transition-group@1.x: + version "1.2.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6" + dependencies: + chain-function "^1.0.0" + dom-helpers "^3.2.0" + loose-envify "^1.3.1" + prop-types "^15.5.6" + warning "^3.0.0" + react@^0.14.2: version "0.14.9" resolved "https://registry.yarnpkg.com/react/-/react-0.14.9.tgz#9110a6497c49d44ba1c0edd317aec29c2e0d91d1"