mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-14 00:53:57 -07:00
New: UI Updates (Backup Restore in App, Profile Cloning)
UI Pulls from Sonarr
This commit is contained in:
parent
80a5701b99
commit
744742b5ff
80 changed files with 2376 additions and 795 deletions
|
@ -1,4 +1,5 @@
|
|||
.card {
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
|
@ -6,3 +7,13 @@
|
|||
box-shadow: 0 0 10px 1px $cardShadowColor;
|
||||
color: $defaultColor;
|
||||
}
|
||||
|
||||
.underlay {
|
||||
@add-mixin cover;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
@add-mixin linkOverlay;
|
||||
|
||||
position: relative;
|
||||
}
|
|
@ -11,10 +11,27 @@ class Card extends Component {
|
|||
render() {
|
||||
const {
|
||||
className,
|
||||
overlayClassName,
|
||||
overlayContent,
|
||||
children,
|
||||
onPress
|
||||
} = this.props;
|
||||
|
||||
if (overlayContent) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<Link
|
||||
className={styles.underlay}
|
||||
onPress={onPress}
|
||||
/>
|
||||
|
||||
<div className={overlayClassName}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={className}
|
||||
|
@ -28,12 +45,16 @@ class Card extends Component {
|
|||
|
||||
Card.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
overlayClassName: PropTypes.string.isRequired,
|
||||
overlayContent: PropTypes.bool.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
Card.defaultProps = {
|
||||
className: styles.card
|
||||
className: styles.card,
|
||||
overlayClassName: styles.overlay,
|
||||
overlayContent: false
|
||||
};
|
||||
|
||||
export default Card;
|
||||
|
|
|
@ -42,10 +42,8 @@ function CaptchaInput(props) {
|
|||
onPress={onRefreshPress}
|
||||
>
|
||||
<Icon
|
||||
name={classNames(
|
||||
icons.REFRESH,
|
||||
refreshing && 'fa-spin'
|
||||
)}
|
||||
name={icons.REFRESH}
|
||||
isSpinning={refreshing}
|
||||
/>
|
||||
</FormInputButton>
|
||||
</div>
|
||||
|
|
|
@ -5,14 +5,107 @@ import styles from './TextInput.css';
|
|||
|
||||
class TextInput extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._input = null;
|
||||
this._selectionStart = null;
|
||||
this._selectionEnd = null;
|
||||
this._selectionTimeout = null;
|
||||
this._isMouseTarget = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('mouseup', this.onDocumentMouseUp);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('mouseup', this.onDocumentMouseUp);
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
setInputRef = (ref) => {
|
||||
this._input = ref;
|
||||
}
|
||||
|
||||
selectionChange() {
|
||||
if (this._selectionTimeout) {
|
||||
this._selectionTimeout = clearTimeout(this._selectionTimeout);
|
||||
}
|
||||
|
||||
this._selectionTimeout = setTimeout(() => {
|
||||
const selectionStart = this._input.selectionStart;
|
||||
const selectionEnd = this._input.selectionEnd;
|
||||
|
||||
const selectionChanged = (
|
||||
this._selectionStart !== selectionStart ||
|
||||
this._selectionEnd !== selectionEnd
|
||||
);
|
||||
|
||||
this._selectionStart = selectionStart;
|
||||
this._selectionEnd = selectionEnd;
|
||||
|
||||
if (this.props.onSelectionChange && selectionChanged) {
|
||||
this.props.onSelectionChange(selectionStart, selectionEnd);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onChange = (event) => {
|
||||
this.props.onChange({
|
||||
name: this.props.name,
|
||||
const {
|
||||
name,
|
||||
type,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
value: event.target.value
|
||||
});
|
||||
};
|
||||
|
||||
// Also return the files for a file input type.
|
||||
|
||||
if (type === 'file') {
|
||||
payload.files = event.target.files;
|
||||
}
|
||||
|
||||
onChange(payload);
|
||||
}
|
||||
|
||||
onFocus = (event) => {
|
||||
if (this.props.onFocus) {
|
||||
this.props.onFocus(event);
|
||||
}
|
||||
|
||||
this.selectionChange();
|
||||
}
|
||||
|
||||
onKeyUp = () => {
|
||||
this.selectionChange();
|
||||
}
|
||||
|
||||
onMouseDown = () => {
|
||||
this._isMouseTarget = true;
|
||||
}
|
||||
|
||||
onMouseUp = () => {
|
||||
this.selectionChange();
|
||||
}
|
||||
|
||||
onDocumentMouseUp = () => {
|
||||
if (this._isMouseTarget) {
|
||||
this.selectionChange();
|
||||
}
|
||||
|
||||
this._isMouseTarget = false;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -29,12 +122,12 @@ class TextInput extends Component {
|
|||
value,
|
||||
hasError,
|
||||
hasWarning,
|
||||
hasButton,
|
||||
onFocus
|
||||
hasButton
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<input
|
||||
ref={this.setInputRef}
|
||||
type={type}
|
||||
readOnly={readOnly}
|
||||
autoFocus={autoFocus}
|
||||
|
@ -49,7 +142,10 @@ class TextInput extends Component {
|
|||
name={name}
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
onFocus={onFocus}
|
||||
onFocus={this.onFocus}
|
||||
onKeyUp={this.onKeyUp}
|
||||
onMouseDown={this.onMouseDown}
|
||||
onMouseUp={this.onMouseUp}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -67,7 +163,8 @@ TextInput.propTypes = {
|
|||
hasWarning: PropTypes.bool,
|
||||
hasButton: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onFocus: PropTypes.func
|
||||
onFocus: PropTypes.func,
|
||||
onSelectionChange: PropTypes.func
|
||||
};
|
||||
|
||||
TextInput.defaultProps = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import classNames from 'classnames';
|
||||
import styles from './Icon.css';
|
||||
|
||||
|
@ -10,7 +10,8 @@ function Icon(props) {
|
|||
name,
|
||||
kind,
|
||||
size,
|
||||
title
|
||||
title,
|
||||
isSpinning
|
||||
} = props;
|
||||
|
||||
return (
|
||||
|
@ -18,7 +19,8 @@ function Icon(props) {
|
|||
className={classNames(
|
||||
name,
|
||||
className,
|
||||
styles[kind]
|
||||
styles[kind],
|
||||
isSpinning && icons.SPIN
|
||||
)}
|
||||
title={title}
|
||||
style={{
|
||||
|
@ -33,12 +35,14 @@ Icon.propTypes = {
|
|||
name: PropTypes.string.isRequired,
|
||||
kind: PropTypes.string.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
title: PropTypes.string
|
||||
title: PropTypes.string,
|
||||
isSpinning: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
Icon.defaultProps = {
|
||||
kind: kinds.DEFAULT,
|
||||
size: 14
|
||||
size: 14,
|
||||
isSpinning: false
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
|
|
|
@ -11,6 +11,7 @@ function IconButton(props) {
|
|||
name,
|
||||
kind,
|
||||
size,
|
||||
isSpinning,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
|
@ -24,6 +25,7 @@ function IconButton(props) {
|
|||
name={name}
|
||||
kind={kind}
|
||||
size={size}
|
||||
isSpinning={isSpinning}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
|
@ -34,7 +36,8 @@ IconButton.propTypes = {
|
|||
iconClassName: PropTypes.string,
|
||||
kind: PropTypes.string,
|
||||
name: PropTypes.string.isRequired,
|
||||
size: PropTypes.number
|
||||
size: PropTypes.number,
|
||||
isSpinning: PropTypes.bool
|
||||
};
|
||||
|
||||
IconButton.defaultProps = {
|
||||
|
|
|
@ -29,10 +29,8 @@ function SpinnerButton(props) {
|
|||
<span className={styles.spinnerContainer}>
|
||||
<Icon
|
||||
className={styles.spinner}
|
||||
name={classNames(
|
||||
spinnerIcon,
|
||||
'fa-spin'
|
||||
)}
|
||||
name={spinnerIcon}
|
||||
isSpinning={true}
|
||||
/>
|
||||
</span>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ function SpinnerIconButton(props) {
|
|||
|
||||
return (
|
||||
<IconButton
|
||||
name={isSpinning ? `${spinningName || name} fa-spin` : name}
|
||||
name={isSpinning ? (spinningName || name) : name}
|
||||
isDisabled={isDisabled || isSpinning}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
|
|
@ -26,7 +26,8 @@ function PageToolbarButton(props) {
|
|||
{...otherProps}
|
||||
>
|
||||
<Icon
|
||||
name={isSpinning ? `${spinningName || iconName} fa-spin` : iconName}
|
||||
name={isSpinning ? (spinningName || iconName) : iconName}
|
||||
isSpinning={isSpinning}
|
||||
size={22}
|
||||
/>
|
||||
|
||||
|
|
|
@ -312,7 +312,8 @@ class SignalRConnector extends Component {
|
|||
this.props.setAppValue({
|
||||
isConnected: true,
|
||||
isReconnecting: false,
|
||||
isDisconnected: false
|
||||
isDisconnected: false,
|
||||
isRestarting: false
|
||||
});
|
||||
|
||||
this.retryInterval = 5;
|
||||
|
|
|
@ -13,7 +13,7 @@ function SpinnerIcon(props) {
|
|||
|
||||
return (
|
||||
<Icon
|
||||
name={isSpinning ? `${spinningName || name} fa-spin` : name}
|
||||
name={isSpinning ? (spinningName || name) : name}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue