use @lbry/components

This commit is contained in:
Sean Yesmunt 2019-02-13 12:27:20 -04:00
parent f9a681a425
commit 4c76050460
79 changed files with 1117 additions and 1671 deletions

View file

@ -89,8 +89,7 @@
"y18n": "^4.0.0"
},
"devDependencies": {
"@lbry/color": "^1.0.2",
"@lbry/components": "^1.5.1",
"@lbry/components": "^2.2.0",
"babel-eslint": "^8.2.2",
"babel-plugin-module-resolver": "^3.1.1",
"babel-polyfill": "^6.26.0",

View file

@ -41,7 +41,7 @@ class App extends React.PureComponent<Props> {
});
// $FlowFixMe
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.setAttribute('data-mode', theme);
}
componentDidMount() {
@ -78,7 +78,7 @@ class App extends React.PureComponent<Props> {
if (prevTheme !== theme) {
// $FlowFixMe
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.setAttribute('data-mode', theme);
}
}

View file

@ -21,7 +21,6 @@ type Props = {
type: string,
button: ?string, // primary, secondary, alt, link
noPadding: ?boolean, // to remove padding and allow circular buttons
uppercase: ?boolean,
iconColor?: string,
iconSize?: number,
constrict: ?boolean, // to shorten the button and ellipsis, only use for links
@ -51,7 +50,6 @@ class Button extends React.PureComponent<Props> {
button,
type,
noPadding,
uppercase,
iconColor,
iconSize,
constrict,
@ -60,25 +58,23 @@ class Button extends React.PureComponent<Props> {
} = this.props;
const combinedClassName = classnames(
'btn',
'button',
{
'btn--no-padding': noPadding,
'button--no-padding': noPadding,
},
button
? {
'btn--primary': button === 'primary',
'btn--secondary': button === 'secondary',
'btn--alt': button === 'alt',
'btn--danger': button === 'danger',
'btn--inverse': button === 'inverse',
'btn--disabled': disabled,
'btn--link': button === 'link',
'btn--external-link': button === 'link' && href,
'btn--uppercase': uppercase,
'btn--constrict': constrict,
'btn--selected': selected,
'button--primary': button === 'primary',
'button--secondary': button === 'secondary',
'button--alt': button === 'alt',
'button--danger': button === 'danger',
'button--inverse': button === 'inverse',
'button--disabled': disabled,
'button--link': button === 'link',
'button--constrict': constrict,
'button--selected': selected,
}
: 'btn--no-style',
: 'button--no-style',
className
);
@ -91,9 +87,9 @@ class Button extends React.PureComponent<Props> {
: onClick;
const content = (
<span className="btn__content">
<span className="button__content">
{icon && <Icon icon={icon} iconColor={iconColor} size={iconSize} />}
{label && <span className="btn__label">{label}</span>}
{label && <span className="button__label">{label}</span>}
{children && children}
{iconRight && <Icon icon={iconRight} iconColor={iconColor} size={iconSize} />}
</span>

View file

@ -309,7 +309,7 @@ class CategoryList extends PureComponent<Props, State> {
)}
</header>
{obscureNsfw && isCommunityTopBids ? (
<p className="media__message media__message--help">
<p className="media__message help--warning">
{__(
'The community top bids section is only visible if you allow mature content in the app. You can change your content viewing preferences'
)}{' '}

View file

@ -2,7 +2,7 @@
import React from 'react';
import { remote } from 'electron';
import Button from 'component/button';
import { FormRow } from 'component/common/form';
import { FormField } from 'component/common/form';
import path from 'path';
type FileFilters = {
@ -63,22 +63,22 @@ class FileSelector extends React.PureComponent<Props> {
type === 'file' ? fileLabel || __('Choose File') : directoryLabel || __('Choose Directory');
return (
<FormRow>
<Button button="primary" onClick={() => this.handleButtonClick()} label={label} />
<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>
<FormField
webkitdirectory="true"
className="form-field--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')}
inputButton={
<Button button="primary" onClick={() => this.handleButtonClick()} label={label} />
}
/>
);
}
}

View file

@ -2,7 +2,6 @@
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,
@ -11,7 +10,6 @@ type Props = {
min: number,
disabled: boolean,
name: string,
label: string,
step: ?number,
};
@ -41,35 +39,40 @@ export class FormFieldPrice extends React.PureComponent<Props> {
}
render() {
const { price, placeholder, min, disabled, name, label, step } = this.props;
const { price, placeholder, min, disabled, name, step } = 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}
step={step || 'any'}
/>
<FormField
name={`${name}_currency`}
type="select"
id={`${name}_currency`}
disabled={disabled}
onChange={this.handleCurrencyChange}
value={price.currency}
>
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
<option value="USD">{__('US Dollars')}</option>
</FormField>
</FormRow>
<fieldset-group class="fieldset-group--smushed">
<fieldset-section>
<FormField
name={`${name}_amount`}
label={__('Price')}
type="number"
className="form-field--price-amount"
min={min}
value={price.amount}
onChange={this.handleAmountChange}
placeholder={placeholder || 5}
disabled={disabled}
step={step || 'any'}
/>
</fieldset-section>
<fieldset-section>
<FormField
label={__('Currency')}
name={`${name}_currency`}
type="select"
id={`${name}_currency`}
className="input--currency-select"
disabled={disabled}
onChange={this.handleCurrencyChange}
value={price.currency}
>
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
<option value="USD">{__('US Dollars')}</option>
</FormField>
</fieldset-section>
</fieldset-group>
);
}
}

View file

@ -1,7 +1,6 @@
// @flow
import * as React from 'react';
import ReactDOMServer from 'react-dom/server';
import classnames from 'classnames';
import MarkdownPreview from 'component/common/markdown-preview';
import SimpleMDE from 'react-simplemde-editor';
import 'simplemde/dist/simplemde.min.css'; // eslint-disable-line import/no-extraneous-dependencies
@ -25,12 +24,18 @@ type Props = {
affixClass?: string, // class applied to prefix/postfix label
firstInList?: boolean, // at the top of a list, no padding top
autoFocus?: boolean,
labelOnLeft: boolean,
inputProps?: {
disabled?: boolean,
},
inputButton: ?React.Node,
};
export class FormField extends React.PureComponent<Props> {
static defaultProps = {
labelOnLeft: false,
};
constructor(props) {
super(props);
this.input = React.createRef();
@ -59,20 +64,51 @@ export class FormField extends React.PureComponent<Props> {
stretch,
affixClass,
autoFocus,
inputButton,
labelOnLeft,
...inputProps
} = this.props;
const errorMessage = typeof error === 'object' ? error.message : error;
let input;
if (type) {
if (type === 'select') {
if (type === 'radio') {
input = (
<div className="form-field__select-wrapper">
<select className="form-field__select" id={name} {...inputProps}>
<fieldset-section>
<radio-element>
<input id={name} type="radio" {...inputProps} />
<label htmlFor={name}>{label}</label>
<radio-toggle onClick={inputProps.onChange} />
</radio-element>
</fieldset-section>
);
} else if (type === 'checkbox') {
input = (
<fieldset-section>
<checkbox-element>
<input id={name} type="checkbox" {...inputProps} />
<label htmlFor={name}>{label}</label>
<checkbox-toggle onClick={inputProps.onChange} />
</checkbox-element>
</fieldset-section>
);
} else if (type === 'setting') {
// 'setting' should only be used for settings. Forms should use "checkbox"
input = (
<input-submit>
{labelOnLeft && <label htmlFor={name}>{label}</label>}
<Toggle id={name} {...inputProps} />
{!labelOnLeft && <label htmlFor={name}>{label}</label>}
</input-submit>
);
} else if (type === 'select') {
input = (
<fieldset-section>
{label && <label htmlFor={name}>{label}</label>}
<select id={name} {...inputProps}>
{children}
</select>
</div>
</fieldset-section>
);
} else if (type === 'markdown') {
const handleEvents = {
@ -81,64 +117,59 @@ export class FormField extends React.PureComponent<Props> {
input = (
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
<SimpleMDE
{...inputProps}
type="textarea"
events={handleEvents}
options={{
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
<fieldset-section>
<label htmlFor={name}>{label}</label>
<SimpleMDE
{...inputProps}
id={name}
type="textarea"
events={handleEvents}
options={{
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
</fieldset-section>
</div>
);
} else if (type === 'textarea') {
input = <textarea type={type} id={name} {...inputProps} />;
} else if (type === 'checkbox') {
input = <Toggle id={name} {...inputProps} />;
input = (
<fieldset-section>
<textarea type={type} id={name} {...inputProps} />
</fieldset-section>
);
} else {
input = <input type={type} id={name} {...inputProps} ref={this.input} />;
const inputElement = <input type={type} id={name} {...inputProps} ref={this.input} />;
const inner = inputButton ? (
<input-submit>
{inputElement}
{inputButton}
</input-submit>
) : (
inputElement
);
input = (
<React.Fragment>
<fieldset-section>
<label htmlFor={name}>{label}</label>
{inner}
</fieldset-section>
{errorMessage && <div className="error-text">{errorMessage}</div>}
</React.Fragment>
);
}
}
return (
<div
className={classnames('form-field', {
'form-field--stretch': stretch || type === 'markdown',
'form-field--disabled': inputProps.disabled,
})}
>
{(label || errorMessage) && (
<label
className={classnames('form-field__label', { 'form-field__error': errorMessage })}
htmlFor={name}
>
{!errorMessage && label}
{errorMessage}
</label>
)}
<div
className={classnames('form-field__input', {
'form-field--auto-height': type === 'markdown',
})}
>
{prefix && (
<label htmlFor={name} className={classnames('form-field__prefix', affixClass)}>
{prefix}
</label>
)}
{input}
{postfix && (
<label htmlFor={name} className={classnames('form-field__postfix', affixClass)}>
{postfix}
</label>
)}
</div>
<React.Fragment>
{input}
{helper && <div className="form-field__help">{helper}</div>}
</div>
</React.Fragment>
);
}
}

View file

@ -1,38 +0,0 @@
// @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,
stretch?: boolean,
alignRight?: boolean,
centered?: boolean,
};
export class FormRow extends React.PureComponent<Props> {
static defaultProps = {
padded: false,
};
render() {
const { children, padded, verticallyCentered, stretch, alignRight, centered } = this.props;
return (
<div
className={classnames('form-row', {
'form-row--padded': padded,
'form-row--vertically-centered': verticallyCentered,
'form-row--stretch': stretch,
'form-row--right': alignRight,
'form-row--centered': centered,
})}
>
{children}
</div>
);
}
}
export default FormRow;

View file

@ -1,5 +1,4 @@
export { Form } from './form-components/form';
export { FormRow } from './form-components/form-row';
export { FormField } from './form-components/form-field';
export { FormFieldPrice } from './form-components/form-field-price';
export { Submit } from './form-components/submit';

View file

@ -2,7 +2,7 @@
import * as ICONS from 'constants/icons';
import * as React from 'react';
import { clipboard } from 'electron';
import { FormRow } from 'component/common/form';
import { FormField } from 'component/common/form';
import Button from 'component/button';
type Props = {
@ -24,33 +24,32 @@ export default class CopyableText extends React.PureComponent<Props> {
const { copyable, doToast, snackMessage } = this.props;
return (
<FormRow verticallyCentered stretch>
<input
className="input-copyable form-field__input"
readOnly
value={copyable || ''}
ref={input => {
this.input = input;
}}
onFocus={() => {
if (this.input) {
this.input.select();
}
}}
/>
<Button
noPadding
button="secondary"
icon={ICONS.CLIPBOARD}
onClick={() => {
clipboard.writeText(copyable);
doToast({
message: snackMessage || __('Text copied'),
});
}}
/>
</FormRow>
<FormField
type="text"
className="form-field--copyable"
readOnly
value={copyable || ''}
ref={input => {
this.input = input;
}}
onFocus={() => {
if (this.input) {
this.input.select();
}
}}
inputButton={
<Button
button="primary"
icon={ICONS.CLIPBOARD}
onClick={() => {
clipboard.writeText(copyable);
doToast({
message: snackMessage || __('Text copied'),
});
}}
/>
}
/>
);
}
}

View file

@ -37,7 +37,7 @@ class ExternalLink extends React.PureComponent<Props> {
iconRight={ICONS.EXTERNAL}
title={title || href}
label={children}
className="btn--external-link"
className="button--external-link"
onClick={() => openModal(MODALS.CONFIRM_EXTERNAL_LINK, { uri: href })}
/>
);

View file

@ -1,7 +1,7 @@
// @flow
import * as React from 'react';
import { buildURI, SORT_OPTIONS } from 'lbry-redux';
import { FormField } from 'component/common/form';
import { FormField, Form } from 'component/common/form';
import FileCard from 'component/fileCard';
import type { FileInfo } from 'types/file_info';
@ -160,7 +160,7 @@ class FileList extends React.PureComponent<Props> {
return (
<section>
{!hideFilter && (
<div className="file-list__sort">
<Form>
<FormField
prefix={__('Sort by')}
affixClass="form-field--align-center"
@ -172,7 +172,7 @@ class FileList extends React.PureComponent<Props> {
<option value={SORT_OPTIONS.DATE_OLD}>{__('Oldest First')}</option>
<option value={SORT_OPTIONS.TITLE}>{__('Title')}</option>
</FormField>
</div>
</Form>
)}
<section className="media-group--list">

View file

@ -2,7 +2,6 @@
import classnames from 'classnames';
import React from 'react';
import Button from 'component/button';
import * as ICONS from 'constants/icons';
type Props = {
play: (SyntheticInputEvent<*>) => void,
@ -17,16 +16,14 @@ class VideoPlayButton extends React.PureComponent<Props> {
const disabled = isLoading || fileInfo === undefined;
const doesPlayback = ['audio', 'video'].indexOf(mediaType) !== -1;
const label = doesPlayback ? __('Play') : __('View');
const icon = doesPlayback ? ICONS.PLAY : ICONS.VIEW;
return (
<Button
disabled={disabled}
label={label}
icon={icon}
iconSize={30}
className={classnames('btn--icon', {
'btn--play': doesPlayback,
'btn--view': !doesPlayback,
title={label}
className={classnames('button--icon', {
'button--play': doesPlayback,
'button--view': !doesPlayback,
})}
onClick={play}
/>

View file

@ -67,7 +67,7 @@ class InviteList extends React.PureComponent<Props> {
</header>
<div className="card__content">
<table className="table table--invites table--stretch">
<table className="table table--invites">
<thead>
<tr>
<th>{__('Invitee Email')}</th>

View file

@ -2,7 +2,7 @@
/* eslint-disable react/no-multi-comp */
import React from 'react';
import Button from 'component/button';
import { Form, FormRow, FormField, Submit } from 'component/common/form';
import { Form, FormField, Submit } from 'component/common/form';
type FormProps = {
inviteNew: string => void,
@ -41,24 +41,19 @@ class FormInviteNew extends React.PureComponent<FormProps, FormState> {
return (
<Form onSubmit={this.handleSubmit}>
<FormRow>
<FormField
stretch
type="text"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
error={errorMessage}
onChange={event => {
this.handleEmailChanged(event);
}}
/>
</FormRow>
<div className="card__actions">
<Submit label="Invite" disabled={isPending} />
</div>
<FormField
stretch
type="text"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
error={errorMessage}
inputButton={<Submit label="Invite" disabled={isPending} />}
onChange={event => {
this.handleEmailChanged(event);
}}
/>
</Form>
);
}

View file

@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
import { FormRow, FormField } from 'component/common/form';
import { FormField } from 'component/common/form';
import { CC_LICENSES, COPYRIGHT, OTHER, PUBLIC_DOMAIN, NONE } from 'constants/licenses';
type Props = {
@ -41,7 +41,7 @@ class LicenseType extends React.PureComponent<Props> {
} = this.props;
return (
<div className="card__content">
<React.Fragment>
<FormField
label={__('License (Optional)')}
type="select"
@ -61,41 +61,40 @@ class LicenseType extends React.PureComponent<Props> {
</FormField>
{licenseType === COPYRIGHT && (
<FormRow padded>
<FormField
stretch
label={__('Copyright notice')}
type="text"
name="copyright-notice"
value={otherLicenseDescription}
onChange={handleLicenseDescriptionChange}
/>
</FormRow>
<FormField
label={__('Copyright notice')}
type="text"
name="copyright-notice"
value={otherLicenseDescription}
onChange={handleLicenseDescriptionChange}
/>
)}
{licenseType === OTHER && (
<React.Fragment>
<FormRow padded>
<fieldset>
<legend>{__('Provide a description and link to your license')}</legend>
<fieldset-group>
<FormField
label={__('License description')}
placeholder={__("The 'cool' license - TM")}
type="text"
name="other-license-description"
value={otherLicenseDescription}
onChange={handleLicenseDescriptionChange}
/>
</FormRow>
<FormRow padded>
<FormField
label={__('License URL')}
placeholder={__('mywebsite.com/license')}
type="text"
name="other-license-url"
value={licenseUrl}
onChange={handleLicenseUrlChange}
/>
</FormRow>
</React.Fragment>
</fieldset-group>
</fieldset>
)}
</div>
</React.Fragment>
);
}
}

View file

@ -42,7 +42,16 @@ class NameHelpText extends React.PureComponent<Props> {
);
}
return <React.Fragment>{nameHelpText || __('Create a URL for this content.')}</React.Fragment>;
return (
<React.Fragment>
{nameHelpText || (
<span>
{__('Create a URL for this content.')}{' '}
{uri && `${__('The uri for this name is')} ${uri}`}
</span>
)}
</React.Fragment>
);
}
}

View file

@ -6,7 +6,7 @@ import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/c
import * as ICONS from 'constants/icons';
import * as React from 'react';
import { isNameValid, buildURI, regexInvalidURI, THUMBNAIL_STATUSES } from 'lbry-redux';
import { Form, FormField, FormRow, FormFieldPrice, Submit } from 'component/common/form';
import { Form, FormField, FormFieldPrice, Submit } from 'component/common/form';
import Button from 'component/button';
import ChannelSection from 'component/selectChannel';
import classnames from 'classnames';
@ -283,7 +283,7 @@ class PublishForm extends React.PureComponent<Props> {
// If there is an error it will be presented as an inline error as well
return (
!isFormValid && (
<div className="card__content card__subtitle form-field__error">
<div className="card__content card__subtitle error-text">
{!title && <div>{__('A title is required')}</div>}
{!name && <div>{__('A URL is required')}</div>}
{name && nameError && <div>{__('The URL you created is not valid')}</div>}
@ -349,7 +349,17 @@ class PublishForm extends React.PureComponent<Props> {
<Form onSubmit={this.handlePublish}>
<section className={classnames('card card--section', { 'card--disabled': publishing })}>
<header className="card__header">
<h2 className="card__title">{__('Content')}</h2>
<h2 className="card__title card__title--flex-between">
{__('Content')}
{(filePath || !!editingURI) && (
<Button
button="inverse"
icon={ICONS.CLOSE}
label={__('Clear')}
onClick={clearPublish}
/>
)}
</h2>
<p className="card__subtitle">
{isStillEditing
? __('You are currently editing a claim.')
@ -360,16 +370,6 @@ class PublishForm extends React.PureComponent<Props> {
</p>
</header>
{(filePath || !!editingURI) && (
<div className="card__internal-links">
<Button
button="inverse"
icon={ICONS.CLOSE}
label={__('Clear')}
onClick={clearPublish}
/>
</div>
)}
<div className="card__content">
<FileSelector currentPath={filePath} onFileChosen={this.handleFileChange} />
{!!isStillEditing &&
@ -384,9 +384,8 @@ class PublishForm extends React.PureComponent<Props> {
</section>
<div className={classnames({ 'card--disabled': formDisabled })}>
<section className="card card--section">
<FormRow>
<div className="card__content">
<FormField
stretch
type="text"
name="content_title"
label={__('Title')}
@ -395,10 +394,8 @@ class PublishForm extends React.PureComponent<Props> {
value={title}
onChange={e => updatePublishForm({ title: e.target.value })}
/>
</FormRow>
<FormRow padded>
<FormField
stretch
type="markdown"
name="content_description"
label={__('Description')}
@ -407,7 +404,7 @@ class PublishForm extends React.PureComponent<Props> {
disabled={formDisabled}
onChange={text => updatePublishForm({ description: text })}
/>
</FormRow>
</div>
</section>
<section className="card card--section">
@ -443,22 +440,26 @@ class PublishForm extends React.PureComponent<Props> {
</header>
<div className="card__content">
<FormField
type="radio"
name="content_free"
postfix={__('Free')}
checked={contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: true })}
/>
<FormField
type="radio"
name="content_cost"
postfix={__('Choose price')}
checked={!contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: false })}
/>
<fieldset-section>
<FormField
type="radio"
name="content_free"
label={__('Free')}
checked={contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: true })}
/>
</fieldset-section>
<fieldset-section>
<FormField
type="radio"
name="content_cost"
label={__('Choose price')}
checked={!contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: false })}
/>
</fieldset-section>
{!contentIsFree && (
<FormFieldPrice
name="content_cost_amount"
@ -503,36 +504,33 @@ class PublishForm extends React.PureComponent<Props> {
</header>
<div className="card__content">
<FormRow>
<FormField
stretch
label={__('Name')}
prefix={`lbry://${
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
? ''
: `${channel}/`
}`}
type="text"
name="content_name"
placeholder="myname"
value={name}
onChange={event => this.handleNameChange(event.target.value)}
error={nameError}
helper={
<NameHelpText
isStillEditing={isStillEditing}
uri={uri}
myClaimForUri={myClaimForUri}
onEditMyClaim={this.editExistingClaim}
/>
}
/>
</FormRow>
<FormField
label={__('Name')}
prefix={`lbry://${
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
? ''
: `${channel}/`
}`}
type="text"
name="content_name"
placeholder="myname"
value={name}
onChange={event => this.handleNameChange(event.target.value)}
error={nameError}
helper={
<NameHelpText
isStillEditing={isStillEditing}
uri={uri}
myClaimForUri={myClaimForUri}
onEditMyClaim={this.editExistingClaim}
/>
}
/>
</div>
<div className={classnames('card__content', { 'card--disabled': !name })}>
<FormField
className="input--price-amount"
className="form-field--price-amount"
type="number"
name="content_bid"
step="any"
@ -557,39 +555,35 @@ class PublishForm extends React.PureComponent<Props> {
<section className="card card--section">
<div className="card__content">
<FormRow>
<FormField
type="checkbox"
name="content_is_mature"
postfix={__('Mature audiences only')}
checked={nsfw}
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
/>
</FormRow>
<FormField
type="checkbox"
name="content_is_mature"
label={__('Mature audiences only')}
checked={nsfw}
onChange={() => updatePublishForm({ nsfw: !nsfw })}
/>
<FormRow padded>
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={event => updatePublishForm({ language: event.target.value })}
>
<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>
<option value="id">{__('Indonesian')}</option>
<option value="it">{__('Italian')}</option>
<option value="nl">{__('Dutch')}</option>
<option value="tr">{__('Turkish')}</option>
<option value="pl">{__('Polish')}</option>
<option value="ms">{__('Malay')}</option>
</FormField>
</FormRow>
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={event => updatePublishForm({ language: event.target.value })}
>
<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>
<option value="id">{__('Indonesian')}</option>
<option value="it">{__('Italian')}</option>
<option value="nl">{__('Dutch')}</option>
<option value="tr">{__('Turkish')}</option>
<option value="pl">{__('Polish')}</option>
<option value="ms">{__('Malay')}</option>
</FormField>
<LicenseType
licenseType={licenseType}
@ -636,13 +630,13 @@ class PublishForm extends React.PureComponent<Props> {
uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS
}
/>
<Button button="alt" onClick={this.handleCancelPublish} label={__('Cancel')} />
<Button button="link" onClick={this.handleCancelPublish} label={__('Cancel')} />
</div>
</div>
</section>
{!formDisabled && !formValid && this.renderFormErrors()}
</div>
{!formDisabled && !formValid && this.renderFormErrors()}
</Form>
);
}

View file

@ -34,7 +34,7 @@ const RewardListClaimed = (props: Props) => {
</p>
</header>
<table className="table table--rewards table--stretch">
<table className="card__content table table--rewards">
<thead>
<tr>
<th>{__('Title')}</th>

View file

@ -1,7 +1,7 @@
// @flow
import React from 'react';
import { isNameValid } from 'lbry-redux';
import { FormRow, FormField } from 'component/common/form';
import { FormField } from 'component/common/form';
import BusyIndicator from 'component/common/busy-indicator';
import Button from 'component/button';
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
@ -152,54 +152,54 @@ class ChannelSection extends React.PureComponent<Props, State> {
return (
<div className="card__content">
{createChannelError && <div className="form-field__error">{createChannelError}</div>}
{createChannelError && <div className="error-text">{createChannelError}</div>}
{fetchingChannels ? (
<BusyIndicator message="Updating channels" />
) : (
<FormField
key="channel"
type="select"
onChange={this.handleChannelChange}
value={channel}
>
<option value={CHANNEL_ANONYMOUS}>{__('Anonymous')}</option>
{channels.map(({ name }) => (
<option key={name} value={name}>
{name}
</option>
))}
<option value={CHANNEL_NEW}>{__('New channel...')}</option>
</FormField>
<fieldset-section>
<FormField
key="channel"
type="select"
onChange={this.handleChannelChange}
value={channel}
>
<option value={CHANNEL_ANONYMOUS}>{__('Anonymous')}</option>
{channels.map(({ name }) => (
<option key={name} value={name}>
{name}
</option>
))}
<option value={CHANNEL_NEW}>{__('New channel...')}</option>
</FormField>
</fieldset-section>
)}
{addingChannel && (
<div className="card__content">
<FormRow padded>
<FormField
label={__('Name')}
type="text"
prefix="@"
placeholder={__('myChannelName')}
error={newChannelNameError}
value={newChannelName}
onChange={this.handleNewChannelNameChange}
/>
</FormRow>
<FormRow padded>
<FormField
className="input--price-amount"
label={__('Deposit')}
postfix="LBC"
step="any"
min="0"
type="number"
helper={__(
'This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.'
)}
error={newChannelBidError}
value={newChannelBid}
onChange={event => this.handleNewChannelBidChange(parseFloat(event.target.value))}
/>
</FormRow>
<FormField
label={__('Name')}
type="text"
prefix="@"
placeholder={__('myChannelName')}
error={newChannelNameError}
value={newChannelName}
onChange={this.handleNewChannelNameChange}
/>
<FormField
className="form-field--price-amount"
label={__('Deposit')}
postfix="LBC"
step="any"
min="0"
type="number"
helper={__(
'This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.'
)}
error={newChannelBidError}
value={newChannelBid}
onChange={event => this.handleNewChannelBidChange(parseFloat(event.target.value))}
/>
<div className="card__actions">
<Button
button="primary"

View file

@ -92,7 +92,6 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
</div>
<div className="column__item">
<FormField
className="input--thumbnail"
type="text"
name="content_thumbnail"
label="URL"

View file

@ -1,7 +1,6 @@
// @flow
import * as React from 'react';
import QRCode from 'component/common/qr-code';
import { FormRow } from 'component/common/form';
import * as statuses from 'constants/shape_shift';
import CopyableText from 'component/copyableText';
import Button from 'component/button';
@ -94,10 +93,10 @@ class ActiveShapeShift extends React.PureComponent<Props> {
/>
{shiftDepositAddress && (
<FormRow verticallyCentered padded>
<React.Fragment>
<QRCode value={shiftDepositAddress} paddingRight />
<CopyableText copyable={shiftDepositAddress} />
</FormRow>
</React.Fragment>
)}
</div>
)}

View file

@ -1,7 +1,7 @@
// @flow
import React from 'react';
import { getExampleAddress } from 'util/shape_shift';
import { FormField, FormRow, Submit } from 'component/common/form';
import { FormField, Submit } from 'component/common/form';
import type { ShapeShiftFormValues, Action } from 'redux/actions/shape_shift';
import type { Dispatch, ThunkAction } from 'types/redux';
import ShiftMarketInfo from './market_info';
@ -70,19 +70,17 @@ export default (props: Props) => {
originCoinDepositMax={originCoinDepositMax}
/>
<FormRow padded>
<FormField
label={__('Return address')}
error={touched.returnAddress && !!errors.returnAddress && errors.returnAddress}
type="text"
name="returnAddress"
className="input--address"
placeholder={getExampleAddress(originCoin)}
onChange={handleChange}
onBlur={handleBlur}
value={values.returnAddress}
/>
</FormRow>
<FormField
label={__('Return address')}
error={touched.returnAddress && !!errors.returnAddress && errors.returnAddress}
type="text"
name="returnAddress"
className="form-field--address"
placeholder={getExampleAddress(originCoin)}
onChange={handleChange}
onBlur={handleBlur}
value={values.returnAddress}
/>
<span className="help">
({__('optional but recommended')})<br />

View file

@ -79,14 +79,13 @@ class ShapeShift extends React.PureComponent<Props> {
<p className="card__subtitle">
{__('Powered by ShapeShift. Read our FAQ')}{' '}
<Button button="link" label={__('here')} href="https://lbry.io/faq/shapeshift" />.
{hasActiveShift && shiftState !== 'complete' && (
<span>{__('This will update automatically.')}</span>
)}
{hasActiveShift &&
shiftState !== 'complete' && <span>{__('This will update automatically.')}</span>}
</p>
</header>
<div className="card__content">
{error && <div className="form-field__error">{error}</div>}
{error && <div className="error-text">{error}</div>}
{!hasActiveShift && (
<Formik
onSubmit={createShapeShift}

View file

@ -35,7 +35,7 @@ class LoadScreen extends React.PureComponent<Props> {
<div className="load-screen__actions">
<Button
label="Refresh"
className="btn--load-screen"
className="button--load-screen"
onClick={() => window.location.reload()}
/>
</div>
@ -48,7 +48,7 @@ class LoadScreen extends React.PureComponent<Props> {
<p>
{__('Reach out to hello@lbry.io for help, or check out')}{' '}
<Button
className="btn--load-screen"
className="button--load-screen"
href="https://lbry.io/faq/startup-troubleshooting"
label="this link"
/>

View file

@ -3,7 +3,7 @@ import type { Transaction } from 'types/transaction';
import * as icons from 'constants/icons';
import * as MODALS from 'constants/modal_types';
import * as React from 'react';
import { FormField } from 'component/common/form';
import { FormField, Form } from 'component/common/form';
import Button from 'component/button';
import FileExporter from 'component/common/file-exporter';
import { TRANSACTIONS } from 'lbry-redux';
@ -80,27 +80,29 @@ class TransactionList extends React.PureComponent<Props> {
defaultPath={__('lbry-transactions-history')}
/>
<FormField
type="select"
value={filterSetting || TRANSACTIONS.ALL}
onChange={this.handleFilterChanged}
affixClass="form-field--align-center"
prefix={__('Show')}
postfix={
<Button
button="link"
icon={icons.HELP}
href="https://lbry.io/faq/transaction-types"
title={__('Help')}
/>
}
>
{transactionTypes.map(tt => (
<option key={tt} value={tt}>
{__(`${this.capitalize(tt)}`)}
</option>
))}
</FormField>
<Form>
<FormField
type="select"
value={filterSetting || TRANSACTIONS.ALL}
onChange={this.handleFilterChanged}
affixClass="form-field--align-center"
prefix={__('Show')}
postfix={
<Button
button="link"
icon={icons.HELP}
href="https://lbry.io/faq/transaction-types"
title={__('Help')}
/>
}
>
{transactionTypes.map(tt => (
<option key={tt} value={tt}>
{__(`${this.capitalize(tt)}`)}
</option>
))}
</FormField>
</Form>
</div>
)}
</header>
@ -110,7 +112,7 @@ class TransactionList extends React.PureComponent<Props> {
{!!transactionList.length && (
<div className="card__content">
<table className="table table--transactions table--stretch">
<table className="table table--transactions">
<thead>
<tr>
<th>{__('Amount')}</th>

View file

@ -12,7 +12,7 @@ type State = {
disabled: boolean,
};
class TransactionListRecent extends PureComponent<Props, State> {
class TransactionRefreshButton extends PureComponent<Props, State> {
constructor() {
super();
@ -48,4 +48,4 @@ class TransactionListRecent extends PureComponent<Props, State> {
}
}
export default TransactionListRecent;
export default TransactionRefreshButton;

View file

@ -61,7 +61,7 @@ class UriIndicator extends React.PureComponent<Props> {
return (
<Button
noPadding
className="btn--uri-indicator"
className="button--uri-indicator"
navigate="/show"
navigateParams={{ uri: channelLink, page: 1 }}
>

View file

@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
import { FormField, Form, FormRow, Submit } from 'component/common/form';
import { FormField, Form, Submit } from 'component/common/form';
type Props = {
cancelButton: React.Node,
@ -50,24 +50,18 @@ class UserEmailNew extends React.PureComponent<Props, State> {
</header>
<Form className="card__content" onSubmit={this.handleSubmit}>
<FormRow>
<FormField
stretch
type="email"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
error={errorMessage}
onChange={this.handleEmailChanged}
/>
</FormRow>
<div className="card__actions">
<Submit label="Submit" disabled={isPending || !this.state.email} />
{cancelButton}
</div>
<FormField
type="email"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
error={errorMessage}
onChange={this.handleEmailChanged}
inputButton={<Submit label="Submit" disabled={isPending || !this.state.email} />}
/>
</Form>
<div className="card__actions">{cancelButton}</div>
<p className="help">
{__('Your email address will never be sold and you can unsubscribe at any time.')}
</p>

View file

@ -1,7 +1,7 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import { FormField, FormRow } from 'component/common/form';
import { Form, FormField } from 'component/common/form';
import ReactPaginate from 'react-paginate';
import UserHistoryItem from 'component/userHistoryItem';
@ -94,9 +94,9 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
}
render() {
const { history, page, pageCount } = this.props;
const { history, page } = this.props;
const { itemsSelected } = this.state;
const pageCount = 20;
const allSelected = Object.keys(itemsSelected).length === history.length;
const selectHandler = allSelected ? this.unselectAll : this.selectAll;
@ -131,32 +131,35 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
))}
</section>
)}
{pageCount > 1 && (
<FormRow padded verticallyCentered centered>
<ReactPaginate
pageCount={pageCount}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected)}
forcePage={page}
initialPage={page}
containerClassName="pagination"
/>
<FormField
className="paginate-channel"
onKeyUp={e => this.paginate(e)}
prefix={__('Go to page:')}
type="text"
/>
</FormRow>
{pageCount > -1 && (
<Form>
<fieldset-group class="fieldset-group--smushed fieldgroup--paginate">
<fieldset-section>
<ReactPaginate
pageCount={pageCount}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected)}
forcePage={page}
initialPage={page}
containerClassName="pagination"
/>
</fieldset-section>
<FormField
className="paginate-channel"
onKeyUp={e => this.paginate(e)}
label={__('Go to page:')}
type="text"
/>
</fieldset-group>
</Form>
)}
</React.Fragment>
) : (

View file

@ -4,6 +4,7 @@ import type { Claim } from 'types/claim';
import moment from 'moment';
import classnames from 'classnames';
import Button from 'component/button';
import { FormField } from 'component/common/form';
type Props = {
lastViewed: number,
@ -43,7 +44,7 @@ class UserHistoryItem extends React.PureComponent<Props> {
'item-list__item--selected': selected,
})}
>
<input checked={selected} type="checkbox" onClick={onSelect} />
<FormField checked={selected} type="checkbox" onClick={onSelect} />
<span className="time time--ago">{moment(lastViewed).from(moment())}</span>
<span className="item-list__item--cutoff">{title}</span>
<Button

View file

@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
import { Form, FormRow, FormField, Submit } from 'component/common/form';
import { Form, FormField, Submit } from 'component/common/form';
const os = require('os').type();
const countryCodes = require('country-data')
@ -95,27 +95,29 @@ class UserPhoneNew extends React.PureComponent<Props, State> {
</section>
<Form className="card__content" onSubmit={this.handleSubmit}>
<FormRow padded>
<FormField type="select" name="country-codes" onChange={this.handleSelect}>
{countryCodes.map((country, index) => (
// eslint-disable-next-line
<option key={index} value={country.countryCallingCode}>
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`}{' '}
{country.countryCallingCode}
</option>
))}
</FormField>
<FormField
type="text"
placeholder={this.state.countryCode === '+1' ? '(555) 555-5555' : '5555555555'}
name="phone"
value={this.state.phone}
error={phoneErrorMessage}
onChange={event => {
this.handleChanged(event);
}}
/>
</FormRow>
<fieldset-section>
<fieldset-group class="fieldset-group--smushed">
<FormField type="select" name="country-codes" onChange={this.handleSelect}>
{countryCodes.map((country, index) => (
// eslint-disable-next-line
<option key={index} value={country.countryCallingCode}>
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`}{' '}
{country.countryCallingCode}
</option>
))}
</FormField>
<FormField
type="text"
placeholder={this.state.countryCode === '+1' ? '(555) 555-5555' : '5555555555'}
name="phone"
value={this.state.phone}
error={phoneErrorMessage}
onChange={event => {
this.handleChanged(event);
}}
/>
</fieldset-group>
</fieldset-section>
<div className="card__actions">
<Submit label="Submit" disabled={isPending} />
{cancelButton}

View file

@ -2,7 +2,7 @@
/* eslint-disable */
import React from 'react';
import Button from 'component/button';
import { Form, FormField, Submit, FormRow } from 'component/common/form';
import { Form, FormField, Submit } from 'component/common/form';
class UserPhoneVerify extends React.PureComponent {
constructor(props) {
@ -43,24 +43,20 @@ class UserPhoneVerify extends React.PureComponent {
</p>
</section>
<Form className="card__content" onSubmit={this.handleSubmit.bind(this)}>
<FormRow>
<FormField
type="text"
name="code"
placeholder="1234"
value={this.state.code}
onChange={event => {
this.handleCodeChanged(event);
}}
label={__('Verification Code')}
error={phoneErrorMessage}
/>
</FormRow>
<FormField
type="text"
name="code"
placeholder="1234"
value={this.state.code}
onChange={event => {
this.handleCodeChanged(event);
}}
label={__('Verification Code')}
error={phoneErrorMessage}
inputButton={<Submit label={__('Verify')} />}
/>
<div className="card__actions">
<Submit label={__('Verify')} />
{cancelButton}
</div>
<div className="card__actions">{cancelButton}</div>
</Form>
<p className="help">

View file

@ -51,7 +51,7 @@ class UserVerify extends React.PureComponent<Props> {
<div className="card__content">
<div className="card__actions">
{errorMessage && <p className="form-field__error">{errorMessage}</p>}
{errorMessage && <p className="error-text">{errorMessage}</p>}
<CardVerify
label={__('Perform Card Verification')}
disabled={isPending}

View file

@ -16,9 +16,7 @@ const WalletBalance = (props: Props) => {
</header>
<div className="card__content">
{(balance || balance === 0) && (
<CreditAmount badge={false} large amount={balance} precision={8} />
)}
{(balance || balance === 0) && <CreditAmount large amount={balance} precision={8} />}
</div>
</section>
);

View file

@ -2,7 +2,7 @@
import React from 'react';
import * as MODALS from 'constants/modal_types';
import Button from 'component/button';
import { Form, FormRow, FormField } from 'component/common/form';
import { Form, FormField } from 'component/common/form';
import { Formik } from 'formik';
import { validateSendTx } from 'util/form-validation';
@ -39,25 +39,26 @@ class WalletSend extends React.PureComponent<Props> {
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Send Credits')}</h2>
<p className="card__subtitle">{__('Send LBC to your friends or favorite creators')}</p>
</header>
<div className="card__content">
<Formik
initialValues={{
address: '',
amount: '',
}}
onSubmit={this.handleSubmit}
validate={validateSendTx}
render={({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
<Form onSubmit={handleSubmit}>
<FormRow>
<Formik
initialValues={{
address: '',
amount: '',
}}
onSubmit={this.handleSubmit}
validate={validateSendTx}
render={({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
<Form onSubmit={handleSubmit}>
<div className="card__content">
<fieldset-group class="fieldset-group--smushed">
<FormField
type="number"
name="amount"
label={__('Amount')}
postfix={__('LBC')}
className="input--price-amount"
className="form-field--price-amount"
affixClass="form-field--fix-no-height"
min="0"
step="any"
@ -65,44 +66,45 @@ class WalletSend extends React.PureComponent<Props> {
onChange={handleChange}
onBlur={handleBlur}
value={values.amount}
error={
(!!values.amount && touched.amount && errors.amount) ||
(values.amount === balance &&
__('Decrease amount to account for transaction fee')) ||
(values.amount > balance && __('Not enough credits'))
}
/>
</FormRow>
<FormRow>
<FormField
type="text"
name="address"
placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs"
className="input--address"
className="form-field--address"
label={__('Recipient address')}
error={!!values.address && touched.address && errors.address}
onChange={handleChange}
onBlur={handleBlur}
value={values.address}
/>
</FormRow>
<div className="card__actions">
<Button
button="primary"
type="submit"
label={__('Send')}
disabled={
!values.address ||
!!Object.keys(errors).length ||
!(parseFloat(values.amount) > 0.0) ||
parseFloat(values.amount) === balance
}
/>
</div>
</Form>
)}
/>
</div>
</fieldset-group>
</div>
<div className="card__actions">
<Button
button="primary"
type="submit"
label={__('Send')}
disabled={
!values.address ||
!!Object.keys(errors).length ||
!(parseFloat(values.amount) > 0.0) ||
parseFloat(values.amount) === balance
}
/>
{!!Object.keys(errors).length && (
<span className="error-text">
{(!!values.address && touched.address && errors.address) ||
(!!values.amount && touched.amount && errors.amount) ||
(values.amount === balance &&
__('Decrease amount to account for transaction fee')) ||
(values.amount > balance && __('Not enough credits'))}
</span>
)}
</div>
</Form>
)}
/>
</section>
);
}

View file

@ -1,7 +1,7 @@
// @flow
import React from 'react';
import Button from 'component/button';
import { FormField, FormRow } from 'component/common/form';
import { FormField, Form } from 'component/common/form';
import type { Claim } from 'types/claim';
type Props = {
@ -75,7 +75,7 @@ class WalletSendTip extends React.PureComponent<Props, State> {
return (
<React.Fragment>
<FormRow className="card__content">
<Form>
<FormField
autoFocus
label={
@ -85,13 +85,21 @@ class WalletSendTip extends React.PureComponent<Props, State> {
__('Amount')
}
postfix={__('LBC')}
className="input--price-amount"
className="form-field--price-amount"
error={tipError}
min="0"
step="any"
type="number"
placeholder="1.23"
onChange={event => this.handleSupportPriceChange(event)}
inputButton={
<Button
button="primary"
label={__('Send')}
disabled={isPending || tipError}
onClick={this.handleSendButtonClicked}
/>
}
helper={
<p>
{__(`This will appear as a tip for "${title}".`)}{' '}
@ -99,15 +107,8 @@ class WalletSendTip extends React.PureComponent<Props, State> {
</p>
}
/>
</FormRow>
</Form>
<div className="card__actions">
<Button
button="primary"
label={__('Send')}
disabled={isPending || tipError}
onClick={this.handleSendButtonClicked}
/>
<Button button="link" label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
</div>
</React.Fragment>

View file

@ -1,7 +1,7 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import { FormField, FormRow } from 'component/common/form';
import { FormField } from 'component/common/form';
type Props = {
upload: (string, boolean) => void,
@ -36,15 +36,14 @@ class ModalConfirmThumbnailUpload extends React.PureComponent<Props> {
<p>{__('Are you sure you want to upload this thumbnail to spee.ch')}?</p>
<blockquote>{path}</blockquote>
<FormRow>
<FormField
type="checkbox"
name="content_is_mature"
postfix={__('For mature audiences only')}
checked={nsfw}
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
/>
</FormRow>
<FormField
type="checkbox"
name="content_is_mature"
label={__('For mature audiences only')}
checked={nsfw}
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
/>
</section>
</Modal>
);

View file

@ -27,13 +27,13 @@ class ModalIncompatibleDaemon extends React.PureComponent<Props> {
<p>
{__(
'This app is running with an incompatible version of the LBRY protocol. You can still use it, but there may be issues. Re-run the installation package for best results.'
)}
)}{' '}
<Button
button="link"
label={__('Learn more')}
href="https://lbry.io/faq/incompatible-protocol-version"
/>.
</p>
<Button
button="link"
label={__('Learn more')}
href="https://lbry.io/faq/incompatible-protocol-version"
/>.
</div>
</Modal>
);

View file

@ -1,7 +1,7 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import { FormRow, FormField } from 'component/common/form';
import { FormField } from 'component/common/form';
type Props = {
claimIsMine: boolean,
@ -74,23 +74,20 @@ class ModalRemoveFile extends React.PureComponent<Props, State> {
</p>
</section>
<section className="card__content">
<FormRow>
<FormField
prefix={__('Also delete this file from my computer')}
type="checkbox"
checked={deleteChecked}
onChange={this.handleDeleteCheckboxClicked}
/>
</FormRow>
<FormField
label={__('Also delete this file from my computer')}
type="checkbox"
checked={deleteChecked}
onChange={this.handleDeleteCheckboxClicked}
/>
{claimIsMine && (
<FormRow>
<FormField
prefix={__('Abandon the claim for this URI')}
type="checkbox"
checked={abandonClaimChecked}
onChange={this.handleAbandonClaimCheckboxClicked}
/>
</FormRow>
<FormField
label={__('Abandon the claim for this URI')}
type="checkbox"
checked={abandonClaimChecked}
onChange={this.handleAbandonClaimCheckboxClicked}
/>
)}
</section>
</Modal>

View file

@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
import { FormRow, FormField } from 'component/common/form';
import { FormField, Form, Submit } from 'component/common/form';
import { Modal } from 'modal/modal';
import Button from 'component/button';
@ -41,14 +41,10 @@ class ModalRewardCode extends React.PureComponent<Props, State> {
isOpen
title={__('Enter Reward Code')}
contentLabel={__('Enter Reward Code')}
type="confirm"
confirmButtonLabel={__('Redeem')}
abortButtonLabel={__('Cancel')}
onConfirmed={this.handleSubmit}
type="custom"
onAborted={closeModal}
confirmButtonDisabled={rewardIsPending}
>
<section className="card__content">
<Form className="card__content" onSubmit={this.handleSubmit}>
<p>
{__('Redeem a custom reward code for LBC')}
{'. '}
@ -58,19 +54,25 @@ class ModalRewardCode extends React.PureComponent<Props, State> {
label={__('Learn more')}
/>.
</p>
<FormRow padded>
<FormField
stretch
autoFocus
type="text"
label={__('Code')}
placeholder="0123abc"
error={error}
value={rewardCode}
onChange={e => this.setState({ rewardCode: e.target.value })}
/>
</FormRow>
</section>
<FormField
autoFocus
type="text"
inputButton={
<Submit
disabled={!rewardCode || rewardIsPending}
label={rewardIsPending ? __('Redeeming') : __('Redeem')}
/>
}
label={__('Code')}
placeholder="0123abc"
error={error}
value={rewardCode}
onChange={e => this.setState({ rewardCode: e.target.value })}
/>
</Form>
<div className="card__actions">
<Button button="link" label={__('Cancel')} onClick={closeModal} />
</div>
</Modal>
);
}

View file

@ -1,6 +1,6 @@
// @flow
import React from 'react';
import { Form, FormRow, FormField } from 'component/common/form';
import { Form, FormField } from 'component/common/form';
import { Modal } from 'modal/modal';
import Button from 'component/button';
@ -101,59 +101,53 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
onConfirmed={() => this.submitEncryptForm()}
onAborted={closeModal}
>
<Form onSubmit={() => this.submitEncryptForm()}>
<section className="card__content">
<p>
{__(
'Encrypting your wallet will require a password to access your local wallet data when LBRY starts. Please enter a new password for your wallet.'
)}{' '}
<Button
button="link"
label={__('Learn more')}
href="https://lbry.io/faq/wallet-encryption"
/>.
</p>
<FormRow padded>
<FormField
stretch
autoFocus
error={passwordMismatch === true ? 'Passwords do not match' : false}
label={__('Password')}
type="password"
name="wallet-new-password"
onChange={event => this.onChangeNewPassword(event)}
/>
</FormRow>
<FormRow padded>
<FormField
stretch
error={passwordMismatch === true ? 'Passwords do not match' : false}
label={__('Confirm Password')}
type="password"
name="wallet-new-password-confirm"
onChange={event => this.onChangeNewPasswordConfirm(event)}
/>
</FormRow>
</section>
<section className="card__content">
<p>
{__(
'If your password is lost, it cannot be recovered. You will not be able to access your wallet without a password.'
)}
</p>
<FormRow padded>
<FormField
stretch
error={understandError === true ? 'You must enter "I understand"' : false}
label={__('Enter "I understand"')}
type="text"
name="wallet-understand"
onChange={event => this.onChangeUnderstandConfirm(event)}
/>
</FormRow>
<div className="card__actions" />
{failMessage && <div className="error-text">{__(failMessage)}</div>}
</section>
<Form className="card__content" onSubmit={() => this.submitEncryptForm()}>
<p>
{__(
'Encrypting your wallet will require a password to access your local wallet data when LBRY starts. Please enter a new password for your wallet.'
)}{' '}
<Button
button="link"
label={__('Learn more')}
href="https://lbry.io/faq/wallet-encryption"
/>.
</p>
<fieldset-section>
<FormField
autoFocus
error={passwordMismatch === true ? 'Passwords do not match' : false}
label={__('Password')}
placeholder={__('Shh...')}
type="password"
name="wallet-new-password"
onChange={event => this.onChangeNewPassword(event)}
/>
</fieldset-section>
<fieldset-section>
<FormField
error={passwordMismatch === true ? 'Passwords do not match' : false}
label={__('Confirm Password')}
placeholder={__('Your eyes only')}
type="password"
name="wallet-new-password-confirm"
onChange={event => this.onChangeNewPasswordConfirm(event)}
/>
</fieldset-section>
<div className="help help--warning">
{__(
'If your password is lost, it cannot be recovered. You will not be able to access your wallet without a password.'
)}
</div>
<FormField
error={understandError === true ? 'You must enter "I understand"' : false}
label={__('Enter "I understand"')}
placeholder={__('Dear computer, I understand')}
type="text"
name="wallet-understand"
onChange={event => this.onChangeUnderstandConfirm(event)}
/>
{failMessage && <div className="error-text">{__(failMessage)}</div>}
</Form>
</Modal>
);

View file

@ -1,6 +1,6 @@
// @flow
import React from 'react';
import { Form, FormRow, FormField } from 'component/common/form';
import { Form, FormField } from 'component/common/form';
import { Modal } from 'modal/modal';
import Button from 'component/button';
@ -57,17 +57,14 @@ class ModalWalletUnlock extends React.PureComponent<Props> {
href="https://lbry.io/faq/wallet-encryption"
/>.
</p>
<FormRow padded>
<FormField
stretch
autoFocus
error={walletUnlockSucceded === false ? 'Incorrect Password' : false}
label={__('Wallet Password')}
type="password"
name="wallet-password"
onChange={event => this.onChangePassword(event)}
/>
</FormRow>
<FormField
autoFocus
error={walletUnlockSucceded === false ? 'Incorrect Password' : false}
label={__('Wallet Password')}
type="password"
name="wallet-password"
onChange={event => this.onChangePassword(event)}
/>
</Form>
</section>
</Modal>

View file

@ -4,7 +4,7 @@ import * as icons from 'constants/icons';
import * as MODALS from 'constants/modal_types';
import React from 'react';
import BusyIndicator from 'component/common/busy-indicator';
import { FormField, FormRow } from 'component/common/form';
import { FormField } from 'component/common/form';
import ReactPaginate from 'react-paginate';
import SubscribeButton from 'component/subscribeButton';
import Page from 'component/page';
@ -108,7 +108,7 @@ class ChannelPage extends React.PureComponent<Props> {
{(!fetching || (claimsInChannel && claimsInChannel.length)) &&
totalPages > 1 && (
<FormRow verticallyCentered centered>
<React.Fragment>
<ReactPaginate
pageCount={totalPages}
pageRangeDisplayed={2}
@ -132,7 +132,7 @@ class ChannelPage extends React.PureComponent<Props> {
prefix={__('Go to page:')}
type="text"
/>
</FormRow>
</React.Fragment>
)}
{!channelIsMine && <HiddenNsfwClaims className="card__content help" uri={uri} />}

View file

@ -226,7 +226,7 @@ class HelpPage extends React.PureComponent<Props, State> {
<div className="card__content">
{this.state.uiVersion && ver ? (
<table className="table table--stretch table--help">
<table className="table table--stretch">
<tbody>
<tr>
<td>{__('App')}</td>

View file

@ -1,6 +1,6 @@
import React from 'react';
import Button from 'component/button';
import { FormRow, FormField } from 'component/common/form';
import { FormField } from 'component/common/form';
import { Lbry, doToast } from 'lbry-redux';
import Page from 'component/page';
@ -56,19 +56,18 @@ class ReportPage extends React.Component {
</header>
<div className="card__content">
<FormRow>
<FormField
type="textarea"
rows="10"
name="message"
stretch
value={this.state.message}
onChange={event => {
this.onMessageChange(event);
}}
placeholder={__('Description of your issue or feature request')}
/>
</FormRow>
<FormField
type="textarea"
rows="10"
name="message"
stretch
value={this.state.message}
onChange={event => {
this.onMessageChange(event);
}}
placeholder={__('Description of your issue or feature request')}
/>
<div className="card__actions">
<Button
button="primary"

View file

@ -3,7 +3,7 @@ import * as SETTINGS from 'constants/settings';
import * as ICONS from 'constants/icons';
import * as React from 'react';
import { isURIValid, normalizeURI, parseURI } from 'lbry-redux';
import { FormField, FormRow } from 'component/common/form';
import { FormField } from 'component/common/form';
import FileTile from 'component/fileTile';
import ChannelTile from 'component/channelTile';
import FileListSearch from 'component/fileListSearch';
@ -49,49 +49,50 @@ class SearchPage extends React.PureComponent<Props> {
return (
<Page noPadding>
<section className="search">
{query && isValid && (
<header className="search__header">
<h1 className="search__title">
{`lbry://${query}`}
<ToolTip
icon
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
>
<Icon icon={ICONS.HELP} />
</ToolTip>
</h1>
{isChannel ? (
<ChannelTile size="large" uri={uri} />
) : (
<FileTile size="large" displayHiddenMessage uri={uri} />
)}
</header>
)}
{query &&
isValid && (
<header className="search__header">
<h1 className="search__title">
{`lbry://${query}`}
<ToolTip
icon
body={__(
'This is the resolution of a LBRY URL and not controlled by LBRY Inc.'
)}
>
<Icon icon={ICONS.HELP} />
</ToolTip>
</h1>
{isChannel ? (
<ChannelTile size="large" uri={uri} />
) : (
<FileTile size="large" displayHiddenMessage uri={uri} />
)}
</header>
)}
<div className="search__results-wrapper">
<FormRow alignRight>
<FormField
type="number"
name="result_count"
min={10}
max={1000}
value={resultCount}
onChange={this.onSearchResultCountChange}
postfix={__('returned results')}
/>
{
// Removing this for now, it currently doesn't do anything but ideally it would
// display content that we don't think is currently available to download
// It is like a "display all" setting
// <FormField
// type="checkbox"
// name="show_unavailable"
// onChange={this.onShowUnavailableChange}
// checked={showUnavailable}
// postfix={__('Include unavailable content')}
// />
}
</FormRow>
<FormField
type="number"
name="result_count"
min={10}
max={1000}
value={resultCount}
onChange={this.onSearchResultCountChange}
postfix={__('returned results')}
/>
{
// Removing this for now, it currently doesn't do anything but ideally it would
// display content that we don't think is currently available to download
// It is like a "display all" setting
// <FormField
// type="checkbox"
// name="show_unavailable"
// onChange={this.onShowUnavailableChange}
// checked={showUnavailable}
// postfix={__('Include unavailable content')}
// />
}
<FileListSearch query={query} />
<div className="help">{__('These search results are provided by LBRY, Inc.')}</div>
</div>

View file

@ -2,7 +2,7 @@
import * as ICONS from 'constants/icons';
import * as SETTINGS from 'constants/settings';
import * as React from 'react';
import { FormField, FormFieldPrice, FormRow } from 'component/common/form';
import { FormField, FormFieldPrice, Form } from 'component/common/form';
import Button from 'component/button';
import Page from 'component/page';
import FileSelector from 'component/common/file-selector';
@ -53,19 +53,12 @@ class SettingsPage extends React.PureComponent<Props, State> {
clearingCache: false,
};
(this: any).onDownloadDirChange = this.onDownloadDirChange.bind(this);
(this: any).onKeyFeeChange = this.onKeyFeeChange.bind(this);
(this: any).onKeyFeeDisableChange = this.onKeyFeeDisableChange.bind(this);
(this: any).onInstantPurchaseMaxChange = this.onInstantPurchaseMaxChange.bind(this);
(this: any).onShowNsfwChange = this.onShowNsfwChange.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).onAutoplayChange = this.onAutoplayChange.bind(this);
(this: any).clearCache = this.clearCache.bind(this);
(this: any).onDesktopNotificationsChange = this.onDesktopNotificationsChange.bind(this);
(this: any).onAutoDownloadChange = this.onAutoDownloadChange.bind(this);
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
}
componentDidMount() {
@ -73,18 +66,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
this.props.updateWalletStatus();
}
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_dir', newDirectory);
}
onKeyFeeChange(newValue: Price) {
this.setDaemonSetting('max_key_fee', newValue);
}
@ -107,10 +88,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
this.props.setClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, value);
}
onAutoplayChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(SETTINGS.AUTOPLAY, event.target.checked);
}
onInstantPurchaseEnabledChange(enabled: boolean) {
this.props.setClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED, enabled);
}
@ -119,14 +96,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
this.props.setClientSetting(SETTINGS.INSTANT_PURCHASE_MAX, newValue);
}
onShowNsfwChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(SETTINGS.SHOW_NSFW, event.target.checked);
}
onAutoDownloadChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(SETTINGS.AUTO_DOWNLOAD, event.target.checked);
}
onChangeEncryptWallet() {
const { decryptWallet, walletEncrypted, encryptWallet } = this.props;
if (walletEncrypted) {
@ -136,10 +105,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
}
onDesktopNotificationsChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(SETTINGS.OS_NOTIFICATIONS_ENABLED, event.target.checked);
}
setDaemonSetting(name: string, value: ?SetDaemonSettingArg): void {
this.props.setDaemonSetting(name, value);
}
@ -170,6 +135,8 @@ class SettingsPage extends React.PureComponent<Props, State> {
walletEncrypted,
osNotificationsEnabled,
autoDownload,
setDaemonSetting,
setClientSetting,
} = this.props;
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
@ -193,11 +160,13 @@ class SettingsPage extends React.PureComponent<Props, State> {
</header>
<div className="card__content">
<FileSelector
type="openDirectory"
currentPath={daemonSettings.download_dir}
onFileChosen={this.onDownloadDirChange}
/>
<Form>
<FileSelector
type="openDirectory"
currentPath={daemonSettings.download_dir}
onFileChosen={this.onDownloadDirChange}
/>
</Form>
</div>
</section>
@ -211,30 +180,34 @@ class SettingsPage extends React.PureComponent<Props, State> {
</p>
</header>
<div className="card__content">
<FormField
type="radio"
name="no_max_purchase_limit"
checked={disableMaxKeyFee}
postfix={__('No Limit')}
onChange={() => {
this.onKeyFeeDisableChange(true);
}}
/>
<FormField
type="radio"
name="max_purchase_limit"
checked={!disableMaxKeyFee}
onChange={() => {
this.onKeyFeeDisableChange(false);
this.onKeyFeeChange(defaultMaxKeyFee);
}}
postfix={__('Choose limit')}
/>
<Form className="card__content">
<fieldset-section>
<FormField
type="radio"
name="no_max_purchase_no_limit"
checked={disableMaxKeyFee}
label={__('No Limit')}
onChange={() => {
this.onKeyFeeDisableChange(true);
}}
/>
</fieldset-section>
<fieldset-section>
<FormField
type="radio"
name="max_purchase_limit"
checked={!disableMaxKeyFee}
onChange={() => {
this.onKeyFeeDisableChange(false);
this.onKeyFeeChange(defaultMaxKeyFee);
}}
label={__('Choose limit')}
/>
</fieldset-section>
{!disableMaxKeyFee && (
<FormFieldPrice
name="max_key_fee"
label="Max purchase price"
min={0}
onChange={this.onKeyFeeChange}
price={
@ -242,7 +215,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
}
/>
)}
</div>
</Form>
</section>
<section className="card card--section">
@ -255,34 +228,38 @@ class SettingsPage extends React.PureComponent<Props, State> {
</p>
</header>
<div className="card__content">
<FormField
type="radio"
name="confirm_all_purchases"
checked={!instantPurchaseEnabled}
postfix={__('Always confirm before purchasing content')}
onChange={() => {
this.onInstantPurchaseEnabledChange(false);
}}
/>
<FormField
type="radio"
name="instant_purchases"
checked={instantPurchaseEnabled}
postfix={__('Only confirm purchases over a certain price')}
onChange={() => {
this.onInstantPurchaseEnabledChange(true);
}}
/>
<Form className="card__content">
<fieldset-section>
<FormField
type="radio"
name="confirm_all_purchases"
checked={!instantPurchaseEnabled}
label={__('Always confirm before purchasing content')}
onChange={() => {
this.onInstantPurchaseEnabledChange(false);
}}
/>
</fieldset-section>
<fieldset-section>
<FormField
type="radio"
name="instant_purchases"
checked={instantPurchaseEnabled}
label={__('Only confirm purchases over a certain price')}
onChange={() => {
this.onInstantPurchaseEnabledChange(true);
}}
/>
</fieldset-section>
{instantPurchaseEnabled && (
<FormFieldPrice
label={__('Confirmation price')}
name="confirmation_price"
min={0.1}
onChange={this.onInstantPurchaseMaxChange}
price={instantPurchaseMax}
/>
)}
</div>
</Form>
</section>
<section className="card card--section">
@ -290,36 +267,38 @@ class SettingsPage extends React.PureComponent<Props, State> {
<h2 className="card__title">{__('Content Settings')}</h2>
</header>
<div className="card__content">
<FormRow>
<FormField
type="checkbox"
name="show_nsfw"
onChange={this.onShowNsfwChange}
checked={showNsfw}
postfix={__('Show NSFW content')}
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. '
)}
/>
</FormRow>
</div>
<Form className="card__content">
<FormField
type="setting"
name="show_nsfw"
onChange={() => setClientSetting(SETTINGS.SHOW_NSFW, !showNsfw)}
checked={showNsfw}
label={__('Show NSFW content')}
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. '
)}
/>
</Form>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Notifications')}</h2>
</header>
<div className="card__content">
<Form className="card__content">
<FormField
type="checkbox"
type="setting"
name="desktopNotification"
onChange={this.onDesktopNotificationsChange}
onChange={() =>
setClientSetting(SETTINGS.OS_NOTIFICATIONS_ENABLED, !osNotificationsEnabled)
}
checked={osNotificationsEnabled}
postfix={__('Show Desktop Notifications')}
label={__('Show Desktop Notifications')}
helper={__(
'Get notified when a publish is confirmed, or when new content is available to watch.'
)}
/>
</div>
</Form>
</section>
<section className="card card--section">
@ -327,32 +306,35 @@ class SettingsPage extends React.PureComponent<Props, State> {
<h2 className="card__title">{__('Share Diagnostic Data')}</h2>
</header>
<div className="card__content">
<Form className="card__content">
<FormField
type="checkbox"
type="setting"
name="share_usage_data"
onChange={this.onShareDataChange}
onChange={() =>
setDaemonSetting('share_usage_data', !daemonSettings.share_usage_data)
}
checked={daemonSettings.share_usage_data}
postfix={__(
label={__(
'Help make LBRY better by contributing analytics and diagnostic data about my usage.'
)}
helper={__(
'You will be ineligible to earn rewards while diagnostics are not being shared.'
)}
/>
</div>
</Form>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Theme')}</h2>
<h2 className="card__title">{__('Appearance')}</h2>
</header>
<div className="card__content">
<FormRow>
<Form className="card__content">
<fieldset-section>
<FormField
name="theme_select"
type="select"
label={__('Theme')}
onChange={this.onThemeChange}
value={currentTheme}
disabled={automaticDarkModeEnabled}
@ -363,17 +345,18 @@ class SettingsPage extends React.PureComponent<Props, State> {
</option>
))}
</FormField>
</FormRow>
<FormField
type="checkbox"
name="automatic_dark_mode"
onChange={e => this.onAutomaticDarkModeChange(e.target.checked)}
checked={automaticDarkModeEnabled}
disabled={isDarkModeEnabled}
postfix={__('Automatic dark mode (9pm to 8am)')}
/>
</div>
</fieldset-section>
<fieldset-section>
<FormField
type="setting"
name="automatic_dark_mode"
onChange={() => this.onAutomaticDarkModeChange(!automaticDarkModeEnabled)}
checked={automaticDarkModeEnabled}
disabled={isDarkModeEnabled}
label={__('Automatic dark mode (9pm to 8am)')}
/>
</fieldset-section>
</Form>
</section>
<section className="card card--section">
@ -381,13 +364,13 @@ class SettingsPage extends React.PureComponent<Props, State> {
<h2 className="card__title">{__('Wallet Security')}</h2>
</header>
<div className="card__content">
<Form className="card__content">
<FormField
type="checkbox"
type="setting"
name="encrypt_wallet"
onChange={() => this.onChangeEncryptWallet()}
checked={walletEncrypted}
postfix={__('Encrypt my wallet with a custom password.')}
label={__('Encrypt my wallet with a custom password.')}
helper={
<React.Fragment>
{__('Secure your local wallet data with a custom password.')}{' '}
@ -401,7 +384,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
</React.Fragment>
}
/>
</div>
</Form>
</section>
<section className="card card--section">
@ -409,32 +392,29 @@ class SettingsPage extends React.PureComponent<Props, State> {
<h2 className="card__title">{__('Experimental Settings')}</h2>
</header>
<div className="card__content">
<FormRow>
<FormField
type="checkbox"
name="auto_download"
onChange={this.onAutoDownloadChange}
checked={autoDownload}
postfix={__('Automatically download new content from my subscriptions')}
helper={__(
"The latest file from each of your subscriptions will be downloaded for quick access as soon as it's published."
)}
/>
</FormRow>
<FormRow>
<FormField
type="checkbox"
name="autoplay"
onChange={this.onAutoplayChange}
checked={autoplay}
postfix={__('Autoplay media files')}
helper={__(
'Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.'
)}
/>
</FormRow>
</div>
<Form className="card__content">
<FormField
type="setting"
name="auto_download"
onChange={() => setClientSetting(SETTINGS.AUTO_DOWNLOAD, !autoDownload)}
checked={autoDownload}
label={__('Automatically download new content from my subscriptions')}
helper={__(
"The latest file from each of your subscriptions will be downloaded for quick access as soon as it's published."
)}
/>
<FormField
type="setting"
name="autoplay"
onChange={() => setClientSetting(SETTINGS.AUTOPLAY, !autoplay)}
checked={autoplay}
label={__('Autoplay media files')}
helper={__(
'Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.'
)}
/>
</Form>
</section>
<section className="card card--section">
@ -450,7 +430,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
button="primary"
label={this.state.clearingCache ? __('Clearing') : __('Clear Cache')}
icon={ICONS.ALERT}
onClick={this.clearCache}
// onClick={this.clearCache}
disabled={this.state.clearingCache}
/>
</div>

View file

@ -57,11 +57,12 @@ export default (props: Props) => {
</div>
<Tooltip onComponent body={__('Automatically download new subscriptions.')}>
<FormField
type="checkbox"
type="setting"
name="auto_download"
onChange={onChangeAutoDownload}
checked={autoDownload}
prefix={__('Auto download')}
label={__('Auto download')}
labelOnLeft
/>
</Tooltip>
</div>

View file

@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types';
const getCurrentPath = () => {
const { hash } = document.location;
if (hash !== '') return hash.replace(/^#/, '');
return '/discover';
return '/settings';
};
const reducers = {};

View file

@ -1,10 +1,12 @@
@charset "utf-8";
@import '~@lbry/color/lbry-color';
// @import "~@lbry/components/sass/index";
// @import '~@lbry/color/lbry-color';
@import '~@lbry/components/sass/init/_color.scss';
@import '~@lbry/components/sass/init/_mixins.scss';
@import '~@lbry/components/sass/init/_variables.scss';
@import '~@lbry/components/sass/init/_reset.scss';
@import 'init/vars';
@import 'init/mixins';
@import 'init/reset';
@import 'init/type';
@import 'init/gui';
@import 'component/animation';
@ -20,7 +22,6 @@
@import 'component/file-download';
@import 'component/file-render';
@import 'component/form-field';
@import 'component/form-row';
@import 'component/header';
@import 'component/item-list';
@import 'component/load-screen';

View file

@ -1,54 +1 @@
.badge {
font-weight: 600;
vertical-align: top;
white-space: nowrap;
&:not(.badge--large) {
border-radius: 0.2rem;
display: inline-block;
font-size: 0.8rem;
letter-spacing: 0.05rem;
line-height: 2;
padding-right: var(--spacing-vertical-small);
padding-left: var(--spacing-vertical-small);
}
}
.badge--alert {
background-color: $lbry-red-2;
color: $lbry-white;
}
.badge--cost:not(.badge--large) {
background-color: $lbry-yellow-2;
color: $lbry-black;
html[data-theme='dark'] & {
background-color: $lbry-yellow-3;
color: $lbry-black;
}
}
.badge--free {
background-color: $lbry-blue-2;
html[data-theme='dark'] & {
background-color: $lbry-blue-3;
color: $lbry-black;
}
}
.badge--large {
font-weight: 600;
font-size: 3.5rem;
line-height: 1;
}
.badge--nsfw {
background-color: $lbry-grape-2;
html[data-theme='dark'] & {
background-color: $lbry-grape-3;
color: $lbry-black;
}
}
@import '~@lbry/components/sass/badge/_index.scss';

View file

@ -1,6 +1,7 @@
.btn {
fill: currentColor;
position: relative;
@import '~@lbry/components/sass/button/_index.scss';
.button {
border-radius: 0;
svg {
stroke-width: 1.9;
@ -19,123 +20,60 @@
}
}
.btn__label {
margin: 0;
}
svg + .btn__label {
svg + .button__label {
margin-left: var(--spacing-vertical-small);
}
}
.btn--alt {
&:hover {
text-decoration: underline;
&.button--icon {
border-radius: 50%;
}
}
.btn--constrict {
@include constrict;
}
.btn--disabled {
opacity: 0.3;
}
.btn--external-link,
.btn--link {
transition: color 0.2s;
&:not(.btn--disabled):not(:hover) {
color: $lbry-teal-5;
html[data-theme='dark'] & {
color: $lbry-teal-3;
}
}
&:not(.btn--disabled):hover {
color: $lbry-teal-3;
html[data-theme='dark'] & {
color: $lbry-teal-4;
}
}
}
.btn--external-link {
font-weight: 500;
text-align: left;
}
// Large icons used for play/view on the file page
.btn--icon {
width: 5rem;
height: 5rem;
background-repeat: no-repeat;
background-size: 50%;
border-radius: 50%;
color: $lbry-white;
transition: background-color 0.2s;
&:not(:hover) {
background-color: rgba($lbry-black, 0.7);
}
// The play icon looks a little weird without this
.btn--play {
padding-left: 0.25rem;
}
.btn__label {
display: none;
}
.button--primary,
.button--alt,
.button--no-style {
svg {
width: 3rem;
height: 3rem;
margin-right: 0;
position: relative;
top: 0.1rem;
width: 1.2rem;
height: 1.2rem;
}
}
.btn--inverse {
border: 1px solid $lbry-gray-1;
border-radius: 1rem;
color: inherit;
.button--inverse {
font-size: 1rem;
padding: var(--spacing-vertical-miniscule) var(--spacing-vertical-medium);
transition: background-color 0.2s;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-white, 0.1);
background-color: rgba($lbry-black, 0.3);
}
&:not(:hover) {
background-color: transparent;
background-color: $lbry-white;
}
&:hover {
background-color: $lbry-gray-1;
color: $lbry-black;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1);
color: $lbry-white;
}
}
.btn__content {
.button__content {
svg {
color: $lbry-gray-4;
}
}
}
.button--link:not(:hover):not(:disabled) {
html[data-mode='dark'] & {
color: $lbry-teal-4;
}
}
.btn--load-screen {
.button--load-screen {
border-bottom: 1px solid $lbry-white;
display: inline-block;
@ -145,31 +83,7 @@
}
}
.btn--primary {
align-self: center; // fixes buttons next to tall elements inside one with `display: flex`
border-radius: 1rem;
color: $lbry-white;
padding: var(--spacing-vertical-miniscule) var(--spacing-vertical-medium);
transition: background-color 0.2s;
&:not(:hover) {
background-color: $lbry-teal-5;
}
&:hover {
background-color: $lbry-teal-3;
html[data-theme='dark'] & {
background-color: $lbry-teal-4;
}
}
}
.btn--uppercase {
text-transform: uppercase;
}
.btn--selected {
.button--selected {
font-weight: 800;
color: $lbry-teal-5;
@ -177,7 +91,7 @@
opacity: 1;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-teal-3;
}
}

View file

@ -1,11 +1,10 @@
.card {
background-color: $lbry-white;
border: 1px solid $lbry-gray-1;
border-radius: 0.5rem;
margin-bottom: var(--spacing-vertical-large);
position: relative;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1);
border-color: rgba($lbry-white, 0.1);
}
@ -199,8 +198,8 @@
display: flex;
align-items: center;
.card__title + .btn,
.btn:not(:first-of-type) {
.card__title + .button,
.button:not(:first-of-type) {
margin-left: var(--spacing-vertical-medium);
}
}
@ -209,9 +208,4 @@
display: flex;
@include between;
align-items: center;
.btn {
font-size: 1.2rem; // Don't make buttons the size of the title
font-weight: 400;
}
}

View file

@ -28,8 +28,8 @@
&:hover {
cursor: pointer;
.btn--view,
.btn--play {
.button--view,
.button--play {
background-color: $lbry-green-3;
}
}

View file

@ -3,7 +3,7 @@
margin-bottom: var(--spacing-vertical-medium);
padding-bottom: var(--spacing-vertical-medium);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
}
@ -37,7 +37,7 @@
content: '';
position: absolute;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-image: linear-gradient(to bottom, transparent 0%, $lbry-black 90%);
}
}

View file

@ -5,11 +5,6 @@
margin-top: $spacing-vertical * 2/3;
}
.file-list__sort {
display: flex;
justify-content: flex-end;
}
.file-list__header {
font-size: 24px;
padding-top: $spacing-vertical * 4/3;

View file

@ -8,7 +8,7 @@
position: absolute;
z-index: 1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border: 1px solid rgba($lbry-gray-1, 0.3);
}
}
@ -17,7 +17,7 @@
.document-viewer {
background-color: $lbry-white;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: transparent;
}
}

View file

@ -1,131 +1,113 @@
.form-field {
&.form-field--disabled {
opacity: 0.4;
pointer-events: none;
}
@import '~@lbry/components/sass/form/_index.scss';
// lbry/components overrides and minor styles
checkbox-element,
radio-element,
fieldset:last-child,
fieldset-section:last-child {
margin-bottom: 0;
}
.form-field--SimpleMDE {
display: block;
width: 100%;
}
fieldset-group.fieldset-group--smushed {
justify-content: flex-start;
.form-field__input {
align-items: center;
display: flex;
font-size: 1.25rem;
fieldset-section {
width: auto;
margin-bottom: 0;
&.form-field--auto-height {
height: auto;
}
&.form-field--first-item {
padding: 0;
}
input {
&.paginate-channel {
width: 35px;
&:first-of-type {
input {
border-right: none;
}
}
}
&.input--thumbnail {
width: 400px;
&.fieldgroup--paginate {
margin-top: var(--spacing-vertical-medium);
align-items: center;
justify-content: center;
.pagination {
margin-bottom: -1em;
}
}
}
.form-field__input--level {
line-height: 2;
}
.form-field__help,
.form-field__label,
.form-field__error {
font-weight: 500;
}
// TODO: Refactor to remove need for `!important`
.form-field__error {
color: $lbry-red-5 !important;
html[data-theme='dark'] & {
color: $lbry-red-2 !important;
// form buttons are black by default
form {
[data-mode='dark'] & {
.button--primary:not(:hover) {
background-color: $lbry-teal-5;
border-color: $lbry-teal-5;
}
}
}
fieldset-section {
[data-mode='dark'] & {
input,
textarea,
select {
color: $lbry-white;
}
input:not(:focus):not(.form-field--copyable),
textarea:not(:focus),
select:not(:focus) {
border-color: $lbry-white;
}
input-submit {
input,
select {
&:first-child:not(:focus) {
border-right-color: transparent;
}
}
}
}
select {
max-width: 12em;
background-color: $lbry-white;
[data-mode='dark'] & {
background-color: transparent;
}
}
}
.form-field--copyable {
background-color: rgba($lbry-gray-1, 0.3);
border: 1px solid $lbry-gray-1;
color: $lbry-gray-5;
flex: 1;
padding: 0.2rem 0.75rem;
text-overflow: ellipsis;
user-select: text;
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.3);
border-color: $lbry-gray-5;
color: inherit;
}
}
label + .react-toggle,
.react-toggle + label {
margin-left: var(--spacing-vertical-small);
}
.form-field__help {
color: $lbry-gray-5;
padding-top: var(--spacing-vertical-small);
@extend .help;
margin-top: var(--spacing-vertical-small);
}
.form-field__label {
color: inherit;
font-size: 1.25rem;
opacity: 0.7;
.form-field--price-amount {
width: 7em;
}
.form-field__prefix,
.form-field__postfix {
font-weight: 500;
// line-height: 2;
&.form-field--align-center {
align-self: center;
}
&.form-field--fix-no-height {
line-height: 1;
}
}
.form-field__prefix {
padding-right: var(--spacing-vertical-small);
}
.form-field__postfix {
padding-left: var(--spacing-vertical-small);
}
// Keeps radio buttons aligned with the labels
// This can probably be done in a better way, but after setting align-items: center on the parent, the label is still off a bit.
input[type='radio'] + .form-field__postfix {
padding-top: 3px;
}
.form-field__select-wrapper {
position: relative;
width: 20rem;
height: 2rem;
&::after {
width: 100%;
height: 100%;
top: 0;
left: 0;
// TRIANGLE_DOWN
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cpath d='M3 4 L21 4 12 20 3 4 Z' stroke='black' stroke-width='2' fill='black' fill-rule='evenodd' stroke-linejoin='round'/%3E %3C/svg%3E");
background-position: 95% center, right top;
background-repeat: no-repeat;
background-size: 0.8rem, 100%;
content: '';
pointer-events: none;
position: absolute;
}
}
.form-field__select {
width: 100%;
height: 100%;
background-color: $lbry-gray-1;
border-radius: 0;
padding: 0 var(--spacing-vertical-small);
-webkit-appearance: none;
&:disabled {
opacity: 0.5;
}
.form-field--address {
width: 370px;
}

View file

@ -1,51 +0,0 @@
.form-row {
display: flex;
flex-direction: row;
align-items: flex-end;
&:not(.form-row--padded):not(:last-of-type) {
margin-bottom: var(--spacing-vertical-medium);
}
.form-field {
&:not(:first-of-type) {
padding-left: var(--spacing-vertical-medium);
}
&.form-field--stretch {
width: 100%;
input {
max-width: 400px;
width: 100%;
}
}
}
button + input,
input + button {
margin-left: var(--spacing-vertical-medium);
}
}
.form-row--centered {
justify-content: center;
}
.form-row--padded {
// Ignore the class name, margin allows these to collapse with other items
margin-top: var(--spacing-vertical-large);
margin-bottom: var(--spacing-vertical-large);
}
.form-row--right {
justify-content: flex-end;
}
.form-row--stretch {
flex: 1;
}
.form-row--vertically-centered {
align-items: center;
}

View file

@ -9,7 +9,7 @@
position: fixed;
z-index: 1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-black, 0.9);
color: $lbry-white;
}
@ -19,7 +19,7 @@
display: flex;
&:first-of-type {
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: $lbry-gray-5;
}
@ -45,7 +45,7 @@
&:not(:disabled):hover {
background-color: $lbry-gray-1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-gray-5;
}
}
@ -56,7 +56,7 @@
}
.header__navigation-item--back {
html[data-theme='dark'] & {
html[data-mode='dark'] & {
svg {
stroke: $lbry-white;
}
@ -64,7 +64,7 @@
}
.header__navigation-item--forward {
html[data-theme='dark'] & {
html[data-mode='dark'] & {
svg {
stroke: $lbry-white;
}
@ -72,7 +72,7 @@
}
.header__navigation-item--home {
html[data-theme='dark'] & {
html[data-mode='dark'] & {
svg {
stroke: $lbry-white;
}
@ -80,7 +80,7 @@
}
.header__navigation-item--menu {
html[data-theme='dark'] & {
html[data-mode='dark'] & {
svg {
stroke: $lbry-white;
}
@ -116,12 +116,12 @@
justify-content: center;
position: relative;
.btn__content {
.button__content {
display: flex;
padding: 0 var(--spacing-vertical-large);
}
.btn__label {
.button__label {
line-height: 1.4;
padding-left: 0.5rem;
}
@ -134,7 +134,7 @@
border-right: 1px solid $lbry-gray-1;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
svg {
stroke: $lbry-white;
}
@ -145,11 +145,11 @@
border-right: 1px solid $lbry-gray-1;
width: calc(100% - (var(--header-height) * 3));
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: $lbry-gray-5;
}
.btn__content {
.button__content {
line-height: var(--header-height);
overflow: hidden;
text-align: center;

View file

@ -3,7 +3,7 @@
margin-top: var(--spacing-vertical-large);
padding: var(--spacing-vertical-large);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1);
}
}
@ -17,6 +17,10 @@
.item-list__item--cutoff {
margin-right: var(--spacing-vertical-large);
}
fieldset-section {
margin-bottom: 0;
}
}
.item-list__item--cutoff {
@ -29,7 +33,7 @@
.item-list__item--selected {
background-color: $lbry-gray-1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-black, 0.5);
}
}

View file

@ -21,7 +21,7 @@
text-decoration-style: dotted;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-left: 1px solid rgba($lbry-white, 0.2);
border-right: 1px solid rgba($lbry-white, 0.2);
border-bottom: 1px solid rgba($lbry-white, 0.2);
@ -91,7 +91,7 @@
border: none;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.2);
a {
@ -124,7 +124,11 @@
font-size: 1rem;
padding: var(--spacing-vertical-medium) 0; // overriding styles from elsewhere
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: inherit;
}
}
.form-field--SimpleMDE {
margin-top: var(--spacing-vertical-large);
}

View file

@ -67,7 +67,7 @@
position: relative;
top: 1rem;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-gray-5, 0.2);
}
}
@ -87,10 +87,6 @@
font-family: Consolas, 'Lucida Console', 'Source Sans', monospace;
}
table {
@extend .table;
}
a {
color: $lbry-blue-1;
display: inline-block;

View file

@ -221,7 +221,7 @@
.media__subtext {
color: rgba($lbry-black, 0.8);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: rgba($lbry-white, 0.7);
}
}
@ -234,7 +234,7 @@
position: relative;
// Quick fix to fix channel overlapping on the home page. This style shouldn't exist here.
.btn--uri-indicator {
.button--uri-indicator {
width: 100%;
text-align: left;
overflow: hidden;
@ -262,7 +262,7 @@
.media__info {
word-wrap: break-word;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
}
@ -271,7 +271,7 @@
border-top: 1px solid $lbry-gray-1;
padding-top: var(--spacing-vertical-medium);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
}
@ -300,42 +300,8 @@
.media__message {
font-size: 1.1rem;
padding: var(--spacing-vertical-medium);
white-space: normal;
}
.media__message--help {
background-color: $lbry-yellow-3;
margin: var(--spacing-vertical-medium) var(--spacing-vertical-large);
.btn--link {
// The normal colors we use for .btn--link are too light for the warning background
// This just darkens them a bit and adds an border-bottom so they are easier to see.
$altered-color: mix($lbry-teal-5, $lbry-black, 80%);
$altered-hover-color: mix($lbry-teal-5, $lbry-black, 60%);
&:not(.btn--disabled) {
color: $altered-color;
border-bottom: 1px solid $altered-color;
&:hover {
color: $altered-hover-color;
}
html[data-theme='dark'] & {
color: $altered-color;
border-bottom: 1px solid $altered-color;
&:hover {
color: $altered-hover-color;
}
}
}
}
html[data-theme='dark'] & {
background-color: $lbry-yellow-4;
color: $lbry-black;
}
white-space: normal;
}
// M E D I A
@ -391,7 +357,7 @@
.media__text {
font-size: 2.5rem;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-white;
}
}
@ -408,7 +374,7 @@
background-repeat: no-repeat;
background-size: cover;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1);
}
}
@ -516,7 +482,7 @@
width: 30rem;
padding-left: var(--spacing-vertical-large);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
@ -530,7 +496,7 @@
padding-top: var(--spacing-vertical-small);
padding-bottom: var(--spacing-vertical-medium);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
}
@ -541,7 +507,7 @@
white-space: nowrap;
width: 100%;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: mix($lbry-white, $lbry-gray-3, 50%);
}
@ -549,7 +515,7 @@
background-image: linear-gradient(to bottom right, $lbry-black, $lbry-cyan-5 80%);
color: $lbry-white;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-image: linear-gradient(
to bottom right,
transparent,
@ -572,7 +538,7 @@
&:not(:first-of-type):not(:last-of-type) {
border-bottom: 1px solid rgba($lbry-gray-1, 0.7);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: rgba($lbry-gray-5, 0.2);
}
}
@ -588,7 +554,7 @@
-webkit-background-clip: text;
background-image: linear-gradient(to right, $lbry-white 80%, transparent 100%);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-image: linear-gradient(
to right,
mix($lbry-white, $lbry-gray-3, 50%) 80%,
@ -646,7 +612,7 @@
button:first-of-type {
font-size: 2rem;
.btn__label {
.button__label {
margin: 0;
}
}

View file

@ -11,7 +11,7 @@
position: fixed;
z-index: 9999;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-black, 0.7);
}
}
@ -19,7 +19,6 @@
.modal {
background-color: $lbry-white;
border: 1px solid $lbry-gray-3;
border-radius: 4px;
line-height: 1.55;
max-width: var(--modal-width);
overflow: auto;
@ -30,7 +29,7 @@
min-width: 500px;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-black;
border-color: $lbry-gray-5;
}
@ -39,10 +38,10 @@
margin-bottom: var(--spacing-vertical-large);
}
.btn.btn--alt {
.button.button--alt {
background-color: $lbry-white; // Set modal buttons bg color
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: transparent;
}
}

View file

@ -6,7 +6,7 @@
padding-right: var(--spacing-vertical-small);
position: relative;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-black;
border-right: 1px solid $lbry-black;
}
@ -38,7 +38,7 @@
position: absolute;
z-index: 0;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-image: linear-gradient(
to bottom right,
transparent,
@ -78,7 +78,7 @@
&.navigation__link--active {
color: $lbry-black;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-gray-1;
}
@ -90,7 +90,7 @@
&.navigation__link--guide:not(:hover) {
color: rgba($lbry-black, 0.75);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: rgba($lbry-white, 0.75);
}
@ -145,7 +145,7 @@
&::before {
background-color: $lbry-black;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-gray-1;
}
}

View file

@ -9,7 +9,7 @@
position: absolute;
z-index: 0;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-black;
}
@ -24,7 +24,7 @@
position: absolute;
z-index: 1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-black;
}
}

View file

@ -9,7 +9,7 @@
::-webkit-scrollbar-thumb {
background-color: $lbry-gray-3;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-gray-5;
}
}

View file

@ -4,7 +4,7 @@
min-height: 300px;
padding: var(--spacing-vertical-large);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: transparent;
border-bottom: 1px solid rgba($lbry-white, 0.1);
}

View file

@ -1,85 +1,18 @@
@import '~@lbry/components/sass/table/_index.scss';
.table {
max-width: 100%;
text-align: left;
word-wrap: break-word;
[data-mode='dark'] & {
background-color: transparent;
th,
td {
&:first-of-type {
padding-left: var(--spacing-vertical-medium);
th {
border-bottom: 2px solid $lbry-white;
}
}
}
th {
font-size: 1.25rem;
font-weight: 700;
padding-top: var(--spacing-vertical-small);
padding-bottom: var(--spacing-vertical-small);
}
td {
color: $lbry-gray-5;
font-weight: 500;
padding-top: var(--spacing-vertical-small);
padding-bottom: var(--spacing-vertical-small);
html[data-theme='dark'] & {
color: inherit;
}
&:not(:last-of-type) {
padding-right: var(--spacing-vertical-large);
}
.btn:not(.btn--link) {
display: inline;
}
&.table__item--actionable {
span + .btn {
margin-left: var(--spacing-vertical-small);
}
.btn svg {
top: 3px;
}
}
}
thead {
border-bottom: 1px solid rgba($lbry-gray-1, 0.7);
html[data-theme='dark'] & {
border-color: rgba($lbry-gray-5, 0.3);
}
}
tbody {
border: 1px solid $lbry-gray-1;
html[data-theme='dark'] & {
border-color: rgba($lbry-gray-5, 0.3);
}
tr {
padding-top: var(--spacing-vertical-small);
padding-bottom: var(--spacing-vertical-small);
&:not(:last-of-type) {
border-bottom: 1px solid $lbry-gray-1;
html[data-theme='dark'] & {
border-color: rgba($lbry-gray-5, 0.3);
}
}
&:nth-child(even) {
background-color: rgba($lbry-gray-1, 0.3);
html[data-theme='dark'] & {
background-color: rgba($lbry-white, 0.1);
}
}
}
.table__item--actionable {
.button svg {
top: 3px;
}
}
@ -90,14 +23,10 @@
}
td:nth-of-type(2) {
@include constrict;
@include constrict(20vw);
}
}
.table--stretch {
width: 100%;
}
.table--transactions {
td:nth-of-type(1) {
// TX amounts

View file

@ -129,14 +129,7 @@
line-height: 0;
position: absolute;
transition: opacity 0.25s;
@media (min-resolution: 1.1dppx) {
top: 1px;
}
@media (max-resolution: 1dppx) {
top: 0;
}
top: 0;
}
.react-toggle-track-check {

View file

@ -25,8 +25,7 @@
width: 200px;
background-color: $lbry-white;
border: 1px solid $lbry-gray-1;
box-shadow: 5px 5px 5px rgba($lbry-black, 0.15);
border-radius: 0.5rem;
box-shadow: 0 2px 5px rgba($lbry-black, 0.15);
&.tooltip__body--short {
width: 110px;
@ -57,7 +56,7 @@
border-color: $tooltip-border transparent transparent transparent;
}
html[data-theme='dark'] & {
html[data-mode='dark'] & {
.tooltip__body {
border: none;
}

View file

@ -8,7 +8,7 @@
position: relative;
z-index: 1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-color: $lbry-gray-5;
}
@ -20,7 +20,7 @@
position: absolute;
z-index: 1;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-gray-5;
}
}
@ -30,7 +30,7 @@
background-color: $lbry-blue-2;
color: $lbry-black;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-blue-4;
color: inherit;
}
@ -43,12 +43,14 @@
align-items: center;
border-right: 1px solid $lbry-gray-1;
border-left: 1px solid $lbry-gray-1;
border-bottom: none;
border-top: none;
display: flex;
justify-content: center;
padding-left: var(--spacing-vertical-large);
transition: background-color 0.2s;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
border-right: 1px solid;
border-left: 1px solid;
color: $lbry-white;
@ -71,7 +73,7 @@
min-width: 100%;
overflow: hidden;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: $lbry-gray-5;
color: $lbry-white;
}

View file

@ -24,7 +24,7 @@ body {
line-height: 1.5;
overflow: hidden;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: mix($lbry-white, $lbry-gray-3, 50%);
}
}
@ -48,37 +48,6 @@ code {
font-size: 1.5rem;
}
input {
&.input-copyable {
background-color: rgba($lbry-gray-1, 0.3);
border: 1px dashed $lbry-gray-1;
color: $lbry-gray-5;
flex: 1;
padding: 0.8rem 1rem;
text-overflow: ellipsis;
user-select: text;
html[data-theme='dark'] & {
background-color: rgba($lbry-gray-1, 0.1);
border-color: $lbry-gray-5;
color: inherit;
}
}
// TODO: These need to be their own styles
&:not(.input-copyable):not(.wunderbar__input) {
border-bottom: var(--input-border-size) solid $lbry-gray-5;
}
}
.input--price-amount {
width: 80px;
}
.input--address {
width: 370px;
}
.columns {
display: flex;
justify-content: space-between;
@ -112,6 +81,7 @@ input {
.column__item:not(:first-child) {
padding-left: $spacing-width * 2/3;
flex: 1;
}
}
@ -142,31 +112,66 @@ input {
color: $lbry-red-3;
font-weight: 600;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: $lbry-red-1;
}
}
.card {
.help {
.help:last-child {
margin-bottom: 0;
}
}
.help {
font-size: 0.9em;
background-color: rgba($lbry-blue-1, 0.1);
border-radius: 0.5rem;
color: $lbry-gray-5;
display: block;
padding: 1rem;
margin-top: var(--spacing-vertical-large);
margin-bottom: var(--spacing-vertical-large);
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: inherit;
}
}
.help--warning {
background-color: $lbry-yellow-3;
color: $lbry-black;
.button--link {
// The normal colors we use for .button--link are too light for the warning background
// This just darkens them a bit and adds an border-bottom so they are easier to see.
$altered-color: mix($lbry-teal-5, $lbry-black, 80%);
$altered-hover-color: mix($lbry-teal-5, $lbry-black, 60%);
&:not(.button--disabled) {
color: $altered-color;
border-bottom: 1px solid $altered-color;
&:hover {
color: $altered-hover-color;
}
html[data-mode='dark'] & {
color: $altered-color;
border-bottom: 1px solid $altered-color;
&:hover {
color: $altered-hover-color;
}
}
}
}
html[data-mode='dark'] & {
background-color: $lbry-yellow-4;
color: $lbry-black;
}
}
.meta {
color: $lbry-gray-1;
font-size: 0.8rem;
@ -176,7 +181,7 @@ input {
color: $lbry-gray-5;
font-style: italic;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
color: inherit;
}
}

View file

@ -3,13 +3,6 @@
justify-content: space-between;
}
@mixin constrict {
max-width: 20vw;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@mixin ellipsis {
// to take over for truncate on LBRY Web
overflow: hidden;
@ -36,7 +29,7 @@
animation: pulse 2s infinite ease-in-out;
background-color: $lbry-gray-2;
html[data-theme='dark'] & {
html[data-mode='dark'] & {
background-color: rgba($lbry-white, 0.1);
}
}

View file

@ -1,170 +0,0 @@
// Mozilla prefixes are unnecessary for app, necessary for LBRY Web
html {
box-sizing: border-box;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
border: none;
box-sizing: inherit;
outline: 0 !important;
user-select: none;
}
a,
area,
button,
[role='button'],
input,
label,
select,
summary,
textarea {
// Remove touch delay on supported devices
touch-action: manipulation;
}
button,
input,
select,
textarea {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: normal;
}
ol,
ul {
list-style-position: inside;
> li {
list-style-position: inside;
}
}
ul {
list-style-type: none;
}
label[for] {
cursor: pointer;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
dl {
overflow-x: scroll;
overflow-y: hidden;
width: 100%;
}
dt {
float: left;
width: 20%;
}
dd {
float: left;
width: 80%;
}
textarea {
border: 1px solid $lbry-gray-2;
padding: $spacing-vertical * 1/3;
width: 100%;
}
img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
vertical-align: middle;
}
input {
background-color: transparent;
line-height: 1;
&::placeholder {
color: inherit;
opacity: 0.3;
}
&:not(:disabled) {
color: inherit;
}
&:not([type='checkbox']),
&:not([type='file']),
&:not([type='radio']),
&:not([type='select']) {
cursor: text;
}
&:not([type='file']):not(:disabled):not(.wunderbar__input):not(.input-copyable) {
border-bottom: var(--input-border-size) dotted $lbry-gray-5;
}
&[type='checkbox']:not(:disabled),
&[type='file']:not(:disabled),
&[type='radio']:not(:disabled),
&[type='select']:not(:disabled) {
cursor: pointer;
}
&[type='file'] {
border-bottom: none;
}
&:disabled {
border-bottom: var(--input-border-size) solid $lbry-gray-3;
color: $lbry-gray-3;
cursor: default;
}
&::-webkit-search-cancel-button {
-webkit-appearance: none;
}
}
button {
background-color: transparent;
color: inherit;
&:not(:disabled) {
cursor: pointer;
}
&:disabled {
cursor: default;
opacity: 0.3;
pointer-events: none;
}
}
a {
color: inherit;
text-decoration: none;
}

View file

@ -35,8 +35,8 @@ $large-breakpoint: 1921px;
--select-height: 30px;
// Button
--btn-radius: 20px;
--btn-height: 36px;
--button-radius: 20px;
--button-height: 36px;
// Header
--header-height: 3.25rem; // 60px;

View file

@ -111,13 +111,10 @@
version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
"@lbry/color@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@lbry/color/-/color-1.0.3.tgz#ec22b2c48b0e358759528fb3bbe7ba468d4e41ca"
"@lbry/components@^1.5.1":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@lbry/components/-/components-1.6.3.tgz#5187736e8d51d24a4678f972d3c062d880d6d853"
"@lbry/components@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@lbry/components/-/components-2.2.0.tgz#ce9e7667f28be832014d8f29d12796ce514ce039"
integrity sha512-AHzc3OZw6gtKESXm0IrGNMFLoJI2JJVDokRzoyHPOdYgLqqADqekC44u8dytGdPHixBo1kZKaoS2FTTXyZpqpw==
"@mapbox/hast-util-table-cell-style@^0.1.3":
version "0.1.3"