implement settings redesign #998
24 changed files with 642 additions and 608 deletions
72
src/renderer/component/common/file-selector.jsx
Normal file
72
src/renderer/component/common/file-selector.jsx
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import { remote } from 'electron';
|
||||||
|
import Button from 'component/link';
|
||||||
|
import { FormRow } from 'component/common/form';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
type: string,
|
||||||
|
currentPath: string,
|
||||||
|
onFileChosen: string => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileSelector extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
type: 'file',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.input = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleButtonClick() {
|
||||||
|
remote.dialog.showOpenDialog(
|
||||||
|
{
|
||||||
|
properties:
|
||||||
|
this.props.type === 'file' ? ['openFile'] : ['openDirectory', 'createDirectory'],
|
||||||
|
},
|
||||||
|
paths => {
|
||||||
|
if (!paths) {
|
||||||
|
// User hit cancel, so do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = paths[0];
|
||||||
|
if (this.props.onFileChosen) {
|
||||||
|
this.props.onFileChosen(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { type, currentPath } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormRow verticallyCentered padded>
|
||||||
|
<Button
|
||||||
|
onClick={() => this.handleButtonClick()}
|
||||||
|
label={type === 'file' ? __('Choose File') : __('Choose Directory')}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
webkitdirectory="true"
|
||||||
|
className="input-copyable"
|
||||||
|
type="text"
|
||||||
|
ref={input => {
|
||||||
|
if (this.input) this.input = input;
|
||||||
|
}}
|
||||||
|
onFocus={() => {
|
||||||
|
if (this.input) this.input.select();
|
||||||
|
}}
|
||||||
|
readOnly="readonly"
|
||||||
|
value={currentPath || __('No File Chosen')}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FileSelector;
|
|
@ -0,0 +1,78 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import type { Price } from 'page/settings';
|
||||||
|
import { FormField } from './form-field';
|
||||||
|
import { FormRow } from './form-row';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
price: Price,
|
||||||
|
onChange: Price => void,
|
||||||
|
placeholder: number,
|
||||||
|
min: number,
|
||||||
|
disabled: boolean,
|
||||||
|
name: string,
|
||||||
|
label: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class FormFieldPrice extends React.PureComponent<Props> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
(this: any).handleAmountChange = this.handleAmountChange.bind(this);
|
||||||
|
(this: any).handleCurrencyChange = this.handleCurrencyChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAmountChange(event: SyntheticInputEvent<*>) {
|
||||||
|
const { price, onChange } = this.props;
|
||||||
|
onChange({
|
||||||
|
currency: price.currency,
|
||||||
|
amount: parseInt(event.target.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCurrencyChange(event: SyntheticInputEvent<*>) {
|
||||||
|
const { price, onChange } = this.props;
|
||||||
|
onChange({
|
||||||
|
currency: event.target.value,
|
||||||
|
amount: price.amount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { price, placeholder, min, disabled, name, label } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormRow padded>
|
||||||
|
<FormField
|
||||||
|
name={`${name}_amount`}
|
||||||
|
label={label}
|
||||||
|
type="number"
|
||||||
|
className="form-field input--price-amount"
|
||||||
|
min={min}
|
||||||
|
value={price.amount || ''}
|
||||||
|
onChange={this.handleAmountChange}
|
||||||
|
placeholder={placeholder || 5}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
name={`${name}_currency`}
|
||||||
|
render={() => (
|
||||||
|
<select
|
||||||
|
id={`${name}_currency`}
|
||||||
|
className="form-field"
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={this.handleCurrencyChange}
|
||||||
|
defaultValue={price.currency}
|
||||||
|
>
|
||||||
|
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
|
||||||
|
<option value="USD">{__('US Dollars')}</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormFieldPrice;
|
61
src/renderer/component/common/form-components/form-field.jsx
Normal file
61
src/renderer/component/common/form-components/form-field.jsx
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
name: string,
|
||||||
|
label?: string,
|
||||||
|
render?: () => React.Node,
|
||||||
|
prefix?: string,
|
||||||
|
postfix?: string,
|
||||||
|
error?: string | boolean,
|
||||||
|
helper?: string | React.Node,
|
||||||
|
type?: string,
|
||||||
|
onChange?: any => any,
|
||||||
|
defaultValue?: string | number,
|
||||||
|
placeholder?: string | number,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class FormField extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { render, label, prefix, postfix, error, helper, name, type, ...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} />;
|
||||||
|
} else if (render) {
|
||||||
|
Input = render;
|
||||||
|
}
|
||||||
|
|||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form-field">
|
||||||
|
{label && (
|
||||||
|
<label className="form-field__label" htmlFor={name}>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
<div className="form-field__input">
|
||||||
|
{prefix && (
|
||||||
|
<label htmlFor={name} className="form-field__prefix">
|
||||||
|
{prefix}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
{Input && <Input />}
|
||||||
|
{postfix && (
|
||||||
|
<label htmlFor={name} className="form-field__postfix">
|
||||||
|
{postfix}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{error && (
|
||||||
|
<div className="form-field__error">
|
||||||
|
{typeof error === 'string' ? error : __('There was an error')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{helper && <div className="form-field__help">{helper}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormField;
|
32
src/renderer/component/common/form-components/form-row.jsx
Normal file
32
src/renderer/component/common/form-components/form-row.jsx
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// @flow
|
||||||
|
// Used as a wrapper for FormField to produce inline form elements
|
||||||
|
import * as React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.Node,
|
||||||
|
padded?: boolean,
|
||||||
|
verticallyCentered?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class FormRow extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
padded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, padded, verticallyCentered } = this.props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames('form-row', {
|
||||||
|
'form-row--padded': padded,
|
||||||
|
'form-row--centered': verticallyCentered,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormRow;
|
26
src/renderer/component/common/form-components/form.jsx
Normal file
26
src/renderer/component/common/form-components/form.jsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.Node,
|
||||||
|
onSubmit: any => any,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Form extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { children, onSubmit } = this.props;
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="form"
|
||||||
|
onSubmit={event => {
|
||||||
|
event.preventDefault();
|
||||||
|
onSubmit(event);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Form;
|
21
src/renderer/component/common/form-components/submit.jsx
Normal file
21
src/renderer/component/common/form-components/submit.jsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import Button from 'component/link';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label: string,
|
||||||
|
disabled: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Submit extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
label: 'Submit',
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { label, disabled } = this.props;
|
||||||
|
return <Button type="submit" label={label} disabled={disabled} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Submit;
|
|
@ -1,95 +1,5 @@
|
||||||
// @flow
|
export { Form } from './form-components/form';
|
||||||
/* eslint-disable react/no-multi-comp */
|
export { FormRow } from './form-components/form-row';
|
||||||
import * as React from 'react';
|
export { FormField } from './form-components/form-field';
|
||||||
import Button from 'component/link';
|
export { FormFieldPrice } from './form-components/form-field-price';
|
||||||
import classnames from 'classnames';
|
export { Submit } from './form-components/submit';
|
||||||
|
|
||||||
type FormRowProps = {
|
|
||||||
children: React.Node,
|
|
||||||
padded?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class FormRow extends React.PureComponent<FormRowProps> {
|
|
||||||
static defaultProps = {
|
|
||||||
padded: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { children, padded } = this.props;
|
|
||||||
return <div className={classnames('form-row', { 'form-row--padded': padded })}>{children}</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FormFieldProps = {
|
|
||||||
render: () => React.Node,
|
|
||||||
label?: string,
|
|
||||||
prefix?: string,
|
|
||||||
postfix?: string,
|
|
||||||
error?: string | boolean,
|
|
||||||
helper?: string | React.Node,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class FormField extends React.PureComponent<FormFieldProps> {
|
|
||||||
render() {
|
|
||||||
const { render, label, prefix, postfix, error, helper } = this.props;
|
|
||||||
/* eslint-disable jsx-a11y/label-has-for */
|
|
||||||
// Will come back to this on the settings page
|
|
||||||
// Need htmlFor on the label
|
|
||||||
return (
|
|
||||||
<div className="form-field">
|
|
||||||
{label && <label className="form-field__label">{label}</label>}
|
|
||||||
<div className="form-field__wrapper">
|
|
||||||
{prefix && <span className="form-field__prefix">{prefix}</span>}
|
|
||||||
{render()}
|
|
||||||
{postfix && <span className="form-field__postfix">{postfix}</span>}
|
|
||||||
</div>
|
|
||||||
{error && (
|
|
||||||
<div className="form-field__error">
|
|
||||||
{typeof error === 'string' ? error : __('There was an error')}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{helper && <div className="form-field__help">{helper}</div>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
/* eslint-enable jsx-a11y/label-has-for */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubmitProps = {
|
|
||||||
label: string,
|
|
||||||
disabled: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Submit extends React.PureComponent<SubmitProps> {
|
|
||||||
static defaultProps = {
|
|
||||||
label: 'Submit',
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { label, disabled } = this.props;
|
|
||||||
return <Button type="submit" label={label} disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FormProps = {
|
|
||||||
children: React.Node,
|
|
||||||
onSubmit: any => any,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Form extends React.PureComponent<FormProps> {
|
|
||||||
render() {
|
|
||||||
const { children, onSubmit } = this.props;
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
className="form"
|
|
||||||
onSubmit={event => {
|
|
||||||
event.preventDefault();
|
|
||||||
onSubmit(event);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* eslint-enable react/no-multi-comp */
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const { remote } = require('electron');
|
|
||||||
|
|
||||||
class FileSelector extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
type: PropTypes.oneOf(['file', 'directory']),
|
|
||||||
initPath: PropTypes.string,
|
|
||||||
onFileChosen: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
type: 'file',
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this._inputElem = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.setState({
|
|
||||||
path: this.props.initPath || null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleButtonClick() {
|
|
||||||
remote.dialog.showOpenDialog(
|
|
||||||
{
|
|
||||||
properties: this.props.type == 'file' ? ['openFile'] : ['openDirectory', 'createDirectory'],
|
|
||||||
},
|
|
||||||
paths => {
|
|
||||||
if (!paths) {
|
|
||||||
// User hit cancel, so do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const path = paths[0];
|
|
||||||
this.setState({
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
if (this.props.onFileChosen) {
|
|
||||||
this.props.onFileChosen(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="file-selector">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="button-block button-alt file-selector__choose-button"
|
|
||||||
onClick={() => this.handleButtonClick()}
|
|
||||||
>
|
|
||||||
<span className="button__content">
|
|
||||||
<span className="button-label">
|
|
||||||
{this.props.type == 'file' ? __('Choose File') : __('Choose Directory')}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</button>{' '}
|
|
||||||
<span className="file-selector__path">
|
|
||||||
<input
|
|
||||||
className="input-copyable"
|
|
||||||
type="text"
|
|
||||||
ref={input => {
|
|
||||||
this._inputElem = input;
|
|
||||||
}}
|
|
||||||
onFocus={() => {
|
|
||||||
this._inputElem.select();
|
|
||||||
}}
|
|
||||||
readOnly="readonly"
|
|
||||||
value={this.state.path || __('No File Chosen')}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FileSelector;
|
|
|
@ -22,9 +22,8 @@ class FileActions extends React.PureComponent<Props> {
|
||||||
const { fileInfo, uri, openModal, claimIsMine, vertical } = this.props;
|
const { fileInfo, uri, openModal, claimIsMine, vertical } = this.props;
|
||||||
|
|
||||||
const claimId = fileInfo ? fileInfo.claim_id : '';
|
const claimId = fileInfo ? fileInfo.claim_id : '';
|
||||||
// showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
const showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
||||||
|
|
||||||
const showDelete = true;
|
|
||||||
return (
|
return (
|
||||||
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
||||||
<FileDownloadLink uri={uri} />
|
<FileDownloadLink uri={uri} />
|
||||||
|
|
|
@ -95,7 +95,7 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{obscureNsfw && <NsfwOverlay />}
|
{shouldObscureNsfw && <NsfwOverlay />}
|
||||||
</section>
|
</section>
|
||||||
Accidentally left this on the last PR. Accidentally left this on the last PR.
|
|||||||
);
|
);
|
||||||
/* eslint-enable jsx-a11y/click-events-have-key-events */
|
/* eslint-enable jsx-a11y/click-events-have-key-events */
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import FileSelector from 'component/file-selector.js';
|
import FileSelector from 'component/common/file-selector';
|
||||||
import SimpleMDE from 'react-simplemde-editor';
|
import SimpleMDE from 'react-simplemde-editor';
|
||||||
Just updating it here so the app successfully builds. Just updating it here so the app successfully builds.
|
|||||||
import { formFieldNestedLabelTypes, formFieldId } from 'component/common/form';
|
import { formFieldNestedLabelTypes, formFieldId } from 'component/common/form';
|
||||||
import style from 'react-simplemde-editor/dist/simplemde.min.css';
|
import style from 'react-simplemde-editor/dist/simplemde.min.css';
|
||||||
|
|
|
@ -1,63 +1,5 @@
|
||||||
import React from 'react';
|
// This just exists so the app builds. It will be removed
|
||||||
import FormField from 'component/formField';
|
|
||||||
|
|
||||||
class FormFieldPrice extends React.PureComponent {
|
const FormFieldPrice = () => null;
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
amount: props.defaultValue && props.defaultValue.amount ? props.defaultValue.amount : '',
|
|
||||||
currency:
|
|
||||||
props.defaultValue && props.defaultValue.currency ? props.defaultValue.currency : 'LBC',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange(newValues) {
|
|
||||||
const newState = Object.assign({}, this.state, newValues);
|
|
||||||
this.setState(newState);
|
|
||||||
this.props.onChange({
|
|
||||||
amount: newState.amount,
|
|
||||||
currency: newState.currency,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFeeAmountChange(event) {
|
|
||||||
this.handleChange({
|
|
||||||
amount: event.target.value ? Number(event.target.value) : null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFeeCurrencyChange(event) {
|
|
||||||
this.handleChange({ currency: event.target.value });
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { defaultValue, placeholder, min } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className="form-field">
|
|
||||||
<FormField
|
|
||||||
type="number"
|
|
||||||
name="amount"
|
|
||||||
min={min}
|
|
||||||
placeholder={placeholder || null}
|
|
||||||
step="any" // Unfortunately, you cannot set a step without triggering validation that enforces a multiple of the step
|
|
||||||
onChange={event => this.handleFeeAmountChange(event)}
|
|
||||||
defaultValue={defaultValue && defaultValue.amount ? defaultValue.amount : ''}
|
|
||||||
className="form-field__input--inline"
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
type="select"
|
|
||||||
name="currency"
|
|
||||||
onChange={event => this.handleFeeCurrencyChange(event)}
|
|
||||||
defaultValue={defaultValue && defaultValue.currency ? defaultValue.currency : ''}
|
|
||||||
className="form-field__input--inline"
|
|
||||||
>
|
|
||||||
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
|
|
||||||
<option value="USD">{__('US Dollars')}</option>
|
|
||||||
</FormField>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FormFieldPrice;
|
export default FormFieldPrice;
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'component/link';
|
import Button from 'component/link';
|
||||||
|
|
||||||
const NsfwOverlay = props => (
|
const NsfwOverlay = () => (
|
||||||
<div className="card-overlay">
|
<div className="card-overlay">
|
||||||
<p>
|
<p>
|
||||||
{__('This content is Not Safe For Work. To view adult content, please change your')}{' '}
|
{__('This content is Not Safe For Work. To view adult content, please change your')}{' '}
|
||||||
<Link
|
<Button fakeLink navigate="/settings" label={__('settings')} />.
|
||||||
className="button-text"
|
|
||||||
onClick={() => props.navigateSettings()}
|
|
||||||
label={__('Settings')}
|
|
||||||
/>.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -40,15 +40,7 @@ class WalletSend extends React.PureComponent<Props> {
|
||||||
}}
|
}}
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
validate={validateSendTx}
|
validate={validateSendTx}
|
||||||
render={({
|
render={({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
|
||||||
values,
|
|
||||||
errors,
|
|
||||||
touched,
|
|
||||||
handleChange,
|
|
||||||
handleBlur,
|
|
||||||
handleSubmit,
|
|
||||||
isSubmitting,
|
|
||||||
}) => (
|
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<FormField
|
<FormField
|
||||||
|
@ -57,7 +49,7 @@ class WalletSend extends React.PureComponent<Props> {
|
||||||
error={!!values.amount && touched.amount && errors.amount}
|
error={!!values.amount && touched.amount && errors.amount}
|
||||||
render={() => (
|
render={() => (
|
||||||
<input
|
<input
|
||||||
className="input--lbc-amount"
|
className="input--price-amount"
|
||||||
type="number"
|
type="number"
|
||||||
name="amount"
|
name="amount"
|
||||||
min="0"
|
min="0"
|
||||||
|
|
|
@ -74,6 +74,7 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
|
|
||||||
input: ?HTMLInputElement;
|
input: ?HTMLInputElement;
|
||||||
throttledGetSearchSuggestions: string => void;
|
throttledGetSearchSuggestions: string => void;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { searchQuery, isActive, address, suggestions } = this.props;
|
const { searchQuery, isActive, address, suggestions } = this.props;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import { doClearCache } from 'redux/actions/app';
|
import { doClearCache } from 'redux/actions/app';
|
||||||
|
@ -6,7 +5,6 @@ import {
|
||||||
doSetDaemonSetting,
|
doSetDaemonSetting,
|
||||||
doSetClientSetting,
|
doSetClientSetting,
|
||||||
doGetThemes,
|
doGetThemes,
|
||||||
doSetTheme,
|
|
||||||
doChangeLanguage,
|
doChangeLanguage,
|
||||||
} from 'redux/actions/settings';
|
} from 'redux/actions/settings';
|
||||||
import {
|
import {
|
||||||
|
@ -23,8 +21,7 @@ const select = state => ({
|
||||||
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
|
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
|
||||||
instantPurchaseEnabled: makeSelectClientSetting(settings.INSTANT_PURCHASE_ENABLED)(state),
|
instantPurchaseEnabled: makeSelectClientSetting(settings.INSTANT_PURCHASE_ENABLED)(state),
|
||||||
instantPurchaseMax: makeSelectClientSetting(settings.INSTANT_PURCHASE_MAX)(state),
|
instantPurchaseMax: makeSelectClientSetting(settings.INSTANT_PURCHASE_MAX)(state),
|
||||||
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
|
currentTheme: makeSelectClientSetting(settings.THEME)(state),
|
||||||
theme: makeSelectClientSetting(settings.THEME)(state),
|
|
||||||
themes: makeSelectClientSetting(settings.THEMES)(state),
|
themes: makeSelectClientSetting(settings.THEMES)(state),
|
||||||
language: selectCurrentLanguage(state),
|
language: selectCurrentLanguage(state),
|
||||||
languages: selectLanguages(state),
|
languages: selectLanguages(state),
|
||||||
|
|
|
@ -1,19 +1,112 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
import FormField from 'component/formField';
|
import * as React from 'react';
|
||||||
import { FormRow } from 'component/common/form';
|
import { FormField, FormFieldPrice } from 'component/common/form';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import lbry from 'lbry.js';
|
import Button from 'component/link';
|
||||||
import Link from 'component/link';
|
|
||||||
import FormFieldPrice from 'component/formFieldPrice';
|
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
import FileSelector from 'component/common/file-selector';
|
||||||
|
|
||||||
class SettingsPage extends React.PureComponent {
|
export type Price = {
|
||||||
constructor(props) {
|
currency: string,
|
||||||
|
amount: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type DaemonSettings = {
|
||||||
|
download_directory: string,
|
||||||
|
disable_max_key_fee: boolean,
|
||||||
|
share_usage_data: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setDaemonSetting: (string, boolean | string | Price) => void,
|
||||||
|
setClientSetting: (string, boolean | string | Price) => void,
|
||||||
|
clearCache: () => Promise<any>,
|
||||||
|
getThemes: () => void,
|
||||||
|
daemonSettings: DaemonSettings,
|
||||||
|
showNsfw: boolean,
|
||||||
|
instantPurchaseEnabled: boolean,
|
||||||
|
instantPurchaseMax: Price,
|
||||||
|
showUnavailable: boolean,
|
||||||
|
currentTheme: string,
|
||||||
|
themes: Array<string>,
|
||||||
|
automaticDarkModeEnabled: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
clearingCache: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
clearingCache: false,
|
clearingCache: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(this: any).onDownloadDirChange = this.onDownloadDirChange.bind(this);
|
||||||
|
(this: any).onKeyFeeChange = this.onKeyFeeChange.bind(this);
|
||||||
|
(this: any).onInstantPurchaseMaxChange = this.onInstantPurchaseMaxChange.bind(this);
|
||||||
|
(this: any).onShowNsfwChange = this.onShowNsfwChange.bind(this);
|
||||||
|
(this: any).onShowUnavailableChange = this.onShowUnavailableChange.bind(this);
|
||||||
|
(this: any).onShareDataChange = this.onShareDataChange.bind(this);
|
||||||
|
(this: any).onThemeChange = this.onThemeChange.bind(this);
|
||||||
|
(this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
|
||||||
|
(this: any).clearCache = this.clearCache.bind(this);
|
||||||
|
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.getThemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onRunOnStartChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.setDaemonSetting('run_on_startup', event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
onShareDataChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.setDaemonSetting('share_usage_data', event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDownloadDirChange(newDirectory: string) {
|
||||||
|
this.setDaemonSetting('download_directory', newDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyFeeChange(newValue: Price) {
|
||||||
|
this.setDaemonSetting('max_key_fee', newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyFeeDisableChange(isDisabled: boolean) {
|
||||||
|
this.setDaemonSetting('disable_max_key_fee', isDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
onThemeChange(event: SyntheticInputEvent<*>) {
|
||||||
|
const { value } = event.target;
|
||||||
|
this.props.setClientSetting(settings.THEME, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAutomaticDarkModeChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
onInstantPurchaseEnabledChange(enabled: boolean) {
|
||||||
|
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
onInstantPurchaseMaxChange(newValue: Price) {
|
||||||
|
this.props.setClientSetting(settings.INSTANT_PURCHASE_MAX, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowNsfwChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowUnavailableChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.SHOW_UNAVAILABLE, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDaemonSetting(name: string, value: boolean | string | Price) {
|
||||||
|
this.props.setDaemonSetting(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
|
@ -24,265 +117,136 @@ class SettingsPage extends React.PureComponent {
|
||||||
this.setState({ clearingCache: false });
|
this.setState({ clearingCache: false });
|
||||||
window.location.href = 'index.html';
|
window.location.href = 'index.html';
|
||||||
};
|
};
|
||||||
const clear = () => this.props.clearCache().then(success.bind(this));
|
const clear = () => this.props.clearCache().then(success);
|
||||||
|
|
||||||
setTimeout(clear, 1000, { once: true });
|
setTimeout(clear, 1000, { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
setDaemonSetting(name, value) {
|
|
||||||
this.props.setDaemonSetting(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRunOnStartChange(event) {
|
|
||||||
this.setDaemonSetting('run_on_startup', event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
onShareDataChange(event) {
|
|
||||||
this.setDaemonSetting('share_usage_data', event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDownloadDirChange(event) {
|
|
||||||
this.setDaemonSetting('download_directory', event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyFeeChange(newValue) {
|
|
||||||
const setting = newValue;
|
|
||||||
|
|
||||||
// this is stupid and should be fixed... somewhere
|
|
||||||
if (setting && (setting.amount === undefined || setting.amount === null)) {
|
|
||||||
setting.amount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setDaemonSetting('max_key_fee', setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyFeeDisableChange(isDisabled) {
|
|
||||||
this.setDaemonSetting('disable_max_key_fee', isDisabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
onThemeChange(event) {
|
|
||||||
const { value } = event.target;
|
|
||||||
this.props.setClientSetting(settings.THEME, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onAutomaticDarkModeChange(event) {
|
|
||||||
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
onInstantPurchaseEnabledChange(enabled) {
|
|
||||||
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
onInstantPurchaseMaxChange(newValue) {
|
|
||||||
this.props.setClientSetting(settings.INSTANT_PURCHASE_MAX, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// onMaxUploadPrefChange(isLimited) {
|
|
||||||
// if (!isLimited) {
|
|
||||||
// this.setDaemonSetting("max_upload", 0.0);
|
|
||||||
// }
|
|
||||||
// this.setState({
|
|
||||||
// isMaxUpload: isLimited,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// onMaxUploadFieldChange(event) {
|
|
||||||
// this.setDaemonSetting("max_upload", Number(event.target.value));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// onMaxDownloadPrefChange(isLimited) {
|
|
||||||
// if (!isLimited) {
|
|
||||||
// this.setDaemonSetting("max_download", 0.0);
|
|
||||||
// }
|
|
||||||
// this.setState({
|
|
||||||
// isMaxDownload: isLimited,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// onMaxDownloadFieldChange(event) {
|
|
||||||
// this.setDaemonSetting("max_download", Number(event.target.value));
|
|
||||||
// }
|
|
||||||
|
|
||||||
onShowNsfwChange(event) {
|
|
||||||
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
onLanguageChange(e) {
|
|
||||||
this.props.changeLanguage(e.target.value);
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowUnavailableChange(event) {
|
|
||||||
this.props.setClientSetting(settings.SHOW_UNAVAILABLE, event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.props.getThemes();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
daemonSettings,
|
daemonSettings,
|
||||||
language,
|
|
||||||
languages,
|
|
||||||
showNsfw,
|
showNsfw,
|
||||||
instantPurchaseEnabled,
|
instantPurchaseEnabled,
|
||||||
instantPurchaseMax,
|
instantPurchaseMax,
|
||||||
showUnavailable,
|
showUnavailable,
|
||||||
theme,
|
currentTheme,
|
||||||
themes,
|
themes,
|
||||||
automaticDarkModeEnabled,
|
automaticDarkModeEnabled,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!daemonSettings || Object.keys(daemonSettings).length === 0) {
|
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||||
return (
|
|
||||||
<main className="main--single-column">
|
|
||||||
<span className="empty">{__('Failed to load settings.')}</span>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
Figured we can remove these. They aren't to complex so adding them back should be easy (when we can). Figured we can remove these. They aren't to complex so adding them back should be easy (when we can).
|
|||||||
{/*
|
{noDaemonSettings ? (
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__content">
|
<div className="card__title">{__('Failed to load settings.')}</div>
|
||||||
<h4>{__("Language")}</h4>
|
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<div className="form-row">
|
|
||||||
<FormField
|
|
||||||
type="select"
|
|
||||||
name="language"
|
|
||||||
defaultValue={language}
|
|
||||||
onChange={this.onLanguageChange.bind(this)}
|
|
||||||
>
|
|
||||||
<option value="en">{__("English")}</option>
|
|
||||||
{Object.keys(languages).map(dLang =>
|
|
||||||
<option key={dLang} value={dLang}>
|
|
||||||
{languages[dLang]}
|
|
||||||
</option>
|
|
||||||
)}
|
|
||||||
</FormField>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section> */}
|
|
||||||
<section className="card">
|
|
||||||
<div className="card__content">
|
|
||||||
<h4>{__('Download Directory')}</h4>
|
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<FormRow
|
|
||||||
type="directory"
|
|
||||||
name="download_directory"
|
|
||||||
defaultValue={daemonSettings.download_directory}
|
|
||||||
helper={__('LBRY downloads will be saved here.')}
|
|
||||||
onChange={this.onDownloadDirChange.bind(this)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
<section className="card">
|
) : (
|
||||||
|
<React.Fragment>
|
||||||
|
<section className="card card--section">
|
||||||
|
<div className="card__title">{__('Download Directory')}</div>
|
||||||
|
<span className="card__subtitle">{__('LBRY downloads will be saved here.')}</span>
|
||||||
|
<FileSelector
|
||||||
|
type="openDirectory"
|
||||||
|
currentPath={daemonSettings.download_directory}
|
||||||
|
onFileChosen={this.onDownloadDirChange}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<section className="card card--section">
|
||||||
|
<div className="card__title">{__('Max Purchase Price')}</div>
|
||||||
|
<span className="card__subtitle">
|
||||||
|
{__(
|
||||||
|
'This will prevent you from purchasing any content over a certain cost, as a safety measure.'
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h4>{__('Max Purchase Price')}</h4>
|
<FormField
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<FormRow
|
|
||||||
type="radio"
|
type="radio"
|
||||||
name="max_key_fee"
|
name="no_max_purchase_limit"
|
||||||
onClick={() => {
|
checked={daemonSettings.disable_max_key_fee}
|
||||||
|
postfix={__('No Limit')}
|
||||||
|
onChange={() => {
|
||||||
this.onKeyFeeDisableChange(true);
|
this.onKeyFeeDisableChange(true);
|
||||||
}}
|
}}
|
||||||
defaultChecked={daemonSettings.disable_max_key_fee}
|
|
||||||
label={__('No Limit')}
|
|
||||||
/>
|
/>
|
||||||
<div className="form-row">
|
|
||||||
<FormField
|
<FormField
|
||||||
type="radio"
|
type="radio"
|
||||||
name="max_key_fee"
|
name="max_purchase_limit"
|
||||||
onClick={() => {
|
onChange={() => {
|
||||||
this.onKeyFeeDisableChange(false);
|
this.onKeyFeeDisableChange(false);
|
||||||
}}
|
}}
|
||||||
defaultChecked={!daemonSettings.disable_max_key_fee}
|
checked={!daemonSettings.disable_max_key_fee}
|
||||||
label={daemonSettings.disable_max_key_fee ? __('Choose limit') : __('Limit to')}
|
postfix={__('Choose limit')}
|
||||||
/>
|
/>
|
||||||
{!daemonSettings.disable_max_key_fee && (
|
|
||||||
<FormFieldPrice
|
<FormFieldPrice
|
||||||
min="0"
|
name="max_key_fee"
|
||||||
onChange={this.onKeyFeeChange.bind(this)}
|
label="Max purchase price"
|
||||||
defaultValue={
|
min={0}
|
||||||
|
onChange={this.onKeyFeeChange}
|
||||||
|
disabled={daemonSettings.disable_max_key_fee}
|
||||||
|
price={
|
||||||
daemonSettings.max_key_fee
|
daemonSettings.max_key_fee
|
||||||
? daemonSettings.max_key_fee
|
? daemonSettings.max_key_fee
|
||||||
: { currency: 'USD', amount: 50 }
|
: { currency: 'USD', amount: 50 }
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="form-field__helper">
|
|
||||||
{__(
|
|
||||||
'This will prevent you from purchasing any content over this cost, as a safety measure.'
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__content">
|
<div className="card__title">{__('Purchase Confirmations')}</div>
|
||||||
<h4>{__('Purchase Confirmations')}</h4>
|
<div className="card__subtitle">
|
||||||
|
{__(
|
||||||
|
"When this option is chosen, LBRY won't ask you to confirm downloads below your chosen price."
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<FormRow
|
<FormField
|
||||||
type="radio"
|
type="radio"
|
||||||
name="instant_purchase_max"
|
name="confirm_all_purchases"
|
||||||
defaultChecked={!instantPurchaseEnabled}
|
checked={!instantPurchaseEnabled}
|
||||||
label={__('Ask for confirmation of all purchases')}
|
postfix={__('Always confirm before purchasing content')}
|
||||||
onClick={e => {
|
onChange={() => {
|
||||||
this.onInstantPurchaseEnabledChange(false);
|
this.onInstantPurchaseEnabledChange(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="form-row">
|
|
||||||
<FormField
|
<FormField
|
||||||
type="radio"
|
type="radio"
|
||||||
name="instant_purchase_max"
|
name="instant_purchases"
|
||||||
defaultChecked={instantPurchaseEnabled}
|
checked={instantPurchaseEnabled}
|
||||||
label={`Single-click purchasing of content less than${
|
postfix={__('Only confirm purchases over a certain price')}
|
||||||
instantPurchaseEnabled ? '' : '...'
|
onChange={() => {
|
||||||
}`}
|
|
||||||
onClick={e => {
|
|
||||||
this.onInstantPurchaseEnabledChange(true);
|
this.onInstantPurchaseEnabledChange(true);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{instantPurchaseEnabled && (
|
|
||||||
<FormFieldPrice
|
<FormFieldPrice
|
||||||
min="0.1"
|
label={__('Confirmation price')}
|
||||||
onChange={val => this.onInstantPurchaseMaxChange(val)}
|
disabled={!instantPurchaseEnabled}
|
||||||
defaultValue={instantPurchaseMax}
|
min={0.1}
|
||||||
|
onChange={this.onInstantPurchaseMaxChange}
|
||||||
|
price={instantPurchaseMax}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="form-field__helper">
|
|
||||||
When this option is chosen, LBRY won't ask you to confirm downloads below the given
|
|
||||||
price.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
|
<div className="card__title">{__('Content Settings')}</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h4>{__('Content')}</h4>
|
<FormField
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<FormRow
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.onShowUnavailableChange.bind(this)}
|
name="show_unavailable"
|
||||||
defaultChecked={showUnavailable}
|
onChange={this.onShowUnavailableChange}
|
||||||
label={__('Show unavailable content in search results')}
|
checked={showUnavailable}
|
||||||
|
postfix={__('Show unavailable content in search results')}
|
||||||
/>
|
/>
|
||||||
<FormRow
|
<FormField
|
||||||
label={__('Show NSFW content')}
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.onShowNsfwChange.bind(this)}
|
name="show_nsfw"
|
||||||
defaultChecked={showNsfw}
|
onChange={this.onShowNsfwChange}
|
||||||
|
checked={showNsfw}
|
||||||
|
postfix={__('Show NSFW content')}
|
||||||
helper={__(
|
helper={__(
|
||||||
'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. '
|
'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. '
|
||||||
)}
|
)}
|
||||||
|
@ -290,63 +254,69 @@ class SettingsPage extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
|
<div className="card__title">{__('Share Diagnostic Data')}</div>
|
||||||
|
<div className="card__subtitle">{__('List what we are doing with the data here')}</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h4>{__('Share Diagnostic Data')}</h4>
|
<FormField
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<FormRow
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.onShareDataChange.bind(this)}
|
name="share_usage_data"
|
||||||
defaultChecked={daemonSettings.share_usage_data}
|
onChange={this.onShareDataChange}
|
||||||
label={__('Help make LBRY better by contributing diagnostic data about my usage')}
|
checked={daemonSettings.share_usage_data}
|
||||||
|
postfix={__(
|
||||||
|
'Help make LBRY better by contributing diagnostic data about my usage'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
<div className="card__content">
|
<div className="card__title">{__('Theme')}</div>
|
||||||
<h4>{__('Theme')}</h4>
|
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<FormField
|
<FormField
|
||||||
type="select"
|
name="theme_select"
|
||||||
onChange={this.onThemeChange.bind(this)}
|
render={() => (
|
||||||
defaultValue={theme}
|
<select
|
||||||
className="form-field__input--inline"
|
name="theme_select"
|
||||||
|
id="theme_select"
|
||||||
|
onChange={this.onThemeChange}
|
||||||
|
value={currentTheme}
|
||||||
|
disabled={automaticDarkModeEnabled}
|
||||||
>
|
>
|
||||||
{themes.map((theme, index) => (
|
{themes.map(theme => (
|
||||||
<option key={theme} value={theme}>
|
<option key={theme} value={theme}>
|
||||||
{theme}
|
{theme}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</FormField>
|
</select>
|
||||||
|
)}
|
||||||
<FormRow
|
/>
|
||||||
type="checkbox"
|
|
||||||
onChange={this.onAutomaticDarkModeChange.bind(this)}
|
<FormField
|
||||||
defaultChecked={automaticDarkModeEnabled}
|
type="checkbox"
|
||||||
label={__('Automatic dark mode (9pm to 8am)')}
|
name="automatic_dark_mode"
|
||||||
|
onChange={this.onAutomaticDarkModeChange}
|
||||||
|
checked={automaticDarkModeEnabled}
|
||||||
|
postfix={__('Automatic dark mode (9pm to 8am)')}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card card--section">
|
||||||
|
<div className="card__title">{__('Application Cache')}</div>
|
||||||
|
<span className="card__subtitle">
|
||||||
|
{__('This will delete your subscriptions, ... other stuff')}
|
||||||
|
</span>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h4>{__('Application Cache')}</h4>
|
<Button
|
||||||
</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<p>
|
|
||||||
<Link
|
|
||||||
label={this.state.clearingCache ? __('Clearing') : __('Clear the cache')}
|
label={this.state.clearingCache ? __('Clearing') : __('Clear the cache')}
|
||||||
icon="icon-trash"
|
icon="AlertCircle"
|
||||||
button="alt"
|
onClick={this.clearCache}
|
||||||
onClick={this.clearCache.bind(this)}
|
|
||||||
disabled={this.state.clearingCache}
|
disabled={this.state.clearingCache}
|
||||||
/>
|
/>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,22 +94,39 @@ ul {
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
cursor: pointer;
|
|
||||||
border-bottom: var(--input-border-size) solid var(--input-border-color);
|
border-bottom: var(--input-border-size) solid var(--input-border-color);
|
||||||
color: var(--input-color);
|
color: var(--input-color);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|
||||||
&[type='text'] {
|
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
|
||||||
|
&[type='radio'],
|
||||||
|
&[type='checkbox'],
|
||||||
|
&[type='file'],
|
||||||
|
&[type='select'] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[type='file'] {
|
||||||
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.input-copyable {
|
&.input-copyable {
|
||||||
background: var(--input-bg);
|
background: var(--input-bg);
|
||||||
color: var(--input-disabled-color);
|
color: var(--input-disabled-color);
|
||||||
width: 100%;
|
|
||||||
font-family: 'Consolas', 'Lucida Console', 'Adobe Source Code Pro', monospace;
|
font-family: 'Consolas', 'Lucida Console', 'Adobe Source Code Pro', monospace;
|
||||||
border-bottom: 1px dotted var(--color-divider);
|
border-bottom: 1px dotted var(--color-divider);
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: var(--input-disabled-color);
|
||||||
|
border-bottom: var(--input-border-size) solid var(--input-disabled-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button + input {
|
||||||
|
margin-left: $spacing-vertical * 2/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
dl {
|
dl {
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
@import 'component/_button.scss';
|
@import 'component/_button.scss';
|
||||||
@import 'component/_card.scss';
|
@import 'component/_card.scss';
|
||||||
@import 'component/_file-download.scss';
|
@import 'component/_file-download.scss';
|
||||||
@import 'component/_file-selector.scss';
|
|
||||||
@import 'component/_file-tile.scss';
|
@import 'component/_file-tile.scss';
|
||||||
@import 'component/_form-field.scss';
|
@import 'component/_form-field.scss';
|
||||||
@import 'component/_header.scss';
|
@import 'component/_header.scss';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// This will go away
|
// This will be moved and updated once we figure out how it should look
|
||||||
// It's for the download progress "button"
|
// It's for the download progress "button"
|
||||||
.faux-button-block {
|
.faux-button-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -9,6 +9,8 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: var(--button-radius);
|
border-radius: var(--button-radius);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
color: var(--color-white);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
top: 0em;
|
top: 0em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
.card__title {
|
.card__title {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
padding: $spacing-vertical / 3 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__title--small {
|
.card__title--small {
|
||||||
|
@ -88,11 +88,21 @@
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .card-media__internal__links should always be inside a card
|
||||||
|
.card {
|
||||||
.card-media__internal-links {
|
.card-media__internal-links {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $spacing-vertical * 2/3;
|
top: $spacing-vertical * 2/3;
|
||||||
right: $spacing-vertical * 2/3;
|
right: $spacing-vertical * 2/3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card--small {
|
||||||
|
.card-media__internal-links {
|
||||||
|
top: $spacing-vertical * 1/3;
|
||||||
|
right: $spacing-vertical * 1/3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Channel info with buttons on the right side
|
// Channel info with buttons on the right side
|
||||||
.card__channel-info {
|
.card__channel-info {
|
||||||
|
@ -107,7 +117,6 @@
|
||||||
|
|
||||||
.card__content {
|
.card__content {
|
||||||
margin-top: var(--card-margin);
|
margin-top: var(--card-margin);
|
||||||
margin-bottom: var(--card-margin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtext-title {
|
.card__subtext-title {
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
.form-field--file,
|
|
||||||
.form-field--directory {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-selector {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-selector__choose-button {
|
|
||||||
font-family: inherit;
|
|
||||||
line-height: 0;
|
|
||||||
color: inherit;
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-selector__path {
|
|
||||||
font-size: 14px;
|
|
||||||
flex-grow: 2;
|
|
||||||
.input-copyable {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,37 @@
|
||||||
.form-row {
|
.form-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
.form-field:not(:first-of-type) {
|
.form-field:not(:first-of-type) {
|
||||||
padding-left: $spacing-vertical;
|
padding-left: $spacing-vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.form-row--padded {
|
&.form-row--padded {
|
||||||
padding: $spacing-vertical * 2/3 0;
|
padding-top: $spacing-vertical * 2/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.form-row--centered {
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field__wrapper {
|
.form-field__input {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: $spacing-vertical / 3 0;
|
padding-top: $spacing-vertical / 3;
|
||||||
|
|
||||||
// Hmm, not sure about this
|
input[type='checkbox'],
|
||||||
// without this the checkbox isn't on the same line as other form-field text
|
input[type='radio'] {
|
||||||
input[type='checkbox'] {
|
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.form-field__error {
|
.form-field__error {
|
||||||
color: var(--color-error);
|
color: var(--color-error);
|
||||||
}
|
}
|
||||||
|
@ -30,18 +40,24 @@
|
||||||
color: var(--color-grey-dark);
|
color: var(--color-grey-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field__help {
|
||||||
|
color: var(--color-grey-dark);
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-top: $spacing-vertical * 1/3;
|
||||||
|
}
|
||||||
|
|
||||||
.form-field__prefix {
|
.form-field__prefix {
|
||||||
padding-right: 5px;
|
padding-right: $spacing-vertical * 1/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field__postfix {
|
.form-field__postfix {
|
||||||
padding-left: 5px;
|
padding-left: $spacing-vertical * 1/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not sure if I like these
|
// Not sure if I like these
|
||||||
// Maybe this should be in gui.scss?
|
// Maybe this should be in gui.scss?
|
||||||
.input--lbc-amount {
|
.input--price-amount {
|
||||||
width: 75px;
|
width: 50px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__actions-history {
|
.nav__actions-history {
|
||||||
|
|
Loading…
Reference in a new issue
@kauffj Added back the type prop back. You are definitely right it makes more sense to keep it. I do think it will be nice to offer extra customization if a consumer wants it. Still need to add something to handle
select
elements.