mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-08 05:51:47 -07:00
Initial Commit Rework
This commit is contained in:
parent
74a4cc048c
commit
95051cbd63
2483 changed files with 101351 additions and 111396 deletions
119
frontend/src/Components/Link/Button.css
Normal file
119
frontend/src/Components/Link/Button.css
Normal file
|
@ -0,0 +1,119 @@
|
|||
.button {
|
||||
composes: link from './Link.css';
|
||||
|
||||
overflow: hidden;
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: normal;
|
||||
|
||||
&:global(.isDisabled) {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.danger {
|
||||
border-color: $dangerBorderColor;
|
||||
background-color: $dangerBackgroundColor;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
border-color: $dangerHoverBorderColor;
|
||||
background-color: $dangerHoverBackgroundColor;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
border-color: $defaultBorderColor;
|
||||
background-color: $defaultBackgroundColor;
|
||||
color: $defaultColor;
|
||||
|
||||
&:hover {
|
||||
border-color: $defaultHoverBorderColor;
|
||||
background-color: $defaultHoverBackgroundColor;
|
||||
color: $defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
.primary {
|
||||
border-color: $primaryBorderColor;
|
||||
background-color: $primaryBackgroundColor;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
border-color: $primaryHoverBorderColor;
|
||||
background-color: $primaryHoverBackgroundColor;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.success {
|
||||
border-color: $successBorderColor;
|
||||
background-color: $successBackgroundColor;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
border-color: $successHoverBorderColor;
|
||||
background-color: $successHoverBackgroundColor;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.warning {
|
||||
border-color: $warningBorderColor;
|
||||
background-color: $warningBackgroundColor;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
border-color: $warningHoverBorderColor;
|
||||
background-color: $warningHoverBackgroundColor;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sizes
|
||||
*/
|
||||
|
||||
.small {
|
||||
padding: 1px 5px;
|
||||
font-size: $smallFontSize;
|
||||
}
|
||||
|
||||
.medium {
|
||||
padding: 6px 16px;
|
||||
font-size: $defaultFontSize;
|
||||
}
|
||||
|
||||
.large {
|
||||
padding: 10px 20px;
|
||||
font-size: $largeFontSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sizes
|
||||
*/
|
||||
|
||||
.left {
|
||||
margin-left: -1px;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin-left: -1px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.right {
|
||||
margin-left: -1px;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
54
frontend/src/Components/Link/Button.js
Normal file
54
frontend/src/Components/Link/Button.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { align, kinds, sizes } from 'Helpers/Props';
|
||||
import Link from './Link';
|
||||
import styles from './Button.css';
|
||||
|
||||
class Button extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
buttonGroupPosition,
|
||||
kind,
|
||||
size,
|
||||
children,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={classNames(
|
||||
className,
|
||||
styles[kind],
|
||||
styles[size],
|
||||
buttonGroupPosition && styles[buttonGroupPosition]
|
||||
)}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Button.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
buttonGroupPosition: PropTypes.oneOf(align.all),
|
||||
kind: PropTypes.oneOf(kinds.all),
|
||||
size: PropTypes.oneOf(sizes.all),
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
className: styles.button,
|
||||
kind: kinds.DEFAULT,
|
||||
size: sizes.MEDIUM
|
||||
};
|
||||
|
||||
export default Button;
|
33
frontend/src/Components/Link/ClipboardButton.css
Normal file
33
frontend/src/Components/Link/ClipboardButton.css
Normal file
|
@ -0,0 +1,33 @@
|
|||
.button {
|
||||
composes: button from 'Components/Form/FormInputButton.css';
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stateIconContainer {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -100%;
|
||||
display: inline-flex;
|
||||
visibility: hidden;
|
||||
transition: left $defaultSpeed;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
.clipboardIconContainer {
|
||||
position: relative;
|
||||
left: 0;
|
||||
transition: left $defaultSpeed, opacity $defaultSpeed;
|
||||
}
|
||||
|
||||
.showStateIcon {
|
||||
.stateIconContainer {
|
||||
left: 50%;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.clipboardIconContainer {
|
||||
left: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
128
frontend/src/Components/Link/ClipboardButton.js
Normal file
128
frontend/src/Components/Link/ClipboardButton.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Clipboard from 'Clipboard';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import getUniqueElememtId from 'Utilities/getUniqueElementId';
|
||||
import Icon from 'Components/Icon';
|
||||
import FormInputButton from 'Components/Form/FormInputButton';
|
||||
import styles from './ClipboardButton.css';
|
||||
|
||||
class ClipboardButton extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._id = getUniqueElememtId();
|
||||
this._successTimeout = null;
|
||||
|
||||
this.state = {
|
||||
showSuccess: false,
|
||||
showError: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._clipboard = new Clipboard(`#${this._id}`, {
|
||||
text: () => this.props.value
|
||||
});
|
||||
|
||||
this._clipboard.on('success', this.onSuccess);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const {
|
||||
showSuccess,
|
||||
showError
|
||||
} = this.state;
|
||||
|
||||
if (showSuccess || showError) {
|
||||
this._testResultTimeout = setTimeout(this.resetState, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._clipboard) {
|
||||
this._clipboard.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
resetState = () => {
|
||||
this.setState({
|
||||
showSuccess: false,
|
||||
showError: false
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSuccess = () => {
|
||||
this.setState({
|
||||
showSuccess: true
|
||||
});
|
||||
}
|
||||
|
||||
onError = () => {
|
||||
this.setState({
|
||||
showError: true
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
|
||||
const {
|
||||
showSuccess,
|
||||
showError
|
||||
} = this.state;
|
||||
|
||||
const showStateIcon = showSuccess || showError;
|
||||
const iconName = showError ? icons.DANGER : icons.CHECK;
|
||||
const iconKind = showError ? kinds.DANGER : kinds.SUCCESS;
|
||||
|
||||
return (
|
||||
<FormInputButton
|
||||
id={this._id}
|
||||
className={styles.button}
|
||||
{...otherProps}
|
||||
>
|
||||
<span className={showStateIcon && styles.showStateIcon}>
|
||||
{
|
||||
showSuccess &&
|
||||
<span className={styles.stateIconContainer}>
|
||||
<Icon
|
||||
name={iconName}
|
||||
kind={iconKind}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
<span className={styles.clipboardIconContainer}>
|
||||
<Icon name={icons.CLIPBOARD} />
|
||||
</span>
|
||||
}
|
||||
</span>
|
||||
</FormInputButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ClipboardButton.propTypes = {
|
||||
value: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default ClipboardButton;
|
16
frontend/src/Components/Link/IconButton.css
Normal file
16
frontend/src/Components/Link/IconButton.css
Normal file
|
@ -0,0 +1,16 @@
|
|||
.button {
|
||||
composes: link from 'Components/Link/Link.css';
|
||||
|
||||
margin: 0 2px;
|
||||
width: 22px;
|
||||
border-radius: 4px;
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
|
||||
&:hover {
|
||||
border: none;
|
||||
background-color: inherit;
|
||||
color: $iconButtonHoverColor;
|
||||
}
|
||||
}
|
44
frontend/src/Components/Link/IconButton.js
Normal file
44
frontend/src/Components/Link/IconButton.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import Link from './Link';
|
||||
import styles from './IconButton.css';
|
||||
|
||||
function IconButton(props) {
|
||||
const {
|
||||
className,
|
||||
iconClassName,
|
||||
name,
|
||||
kind,
|
||||
size,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
<Icon
|
||||
className={iconClassName}
|
||||
name={name}
|
||||
kind={kind}
|
||||
size={size}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
IconButton.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
iconClassName: PropTypes.string,
|
||||
kind: PropTypes.string,
|
||||
name: PropTypes.string.isRequired,
|
||||
size: PropTypes.number
|
||||
};
|
||||
|
||||
IconButton.defaultProps = {
|
||||
className: styles.button
|
||||
};
|
||||
|
||||
export default IconButton;
|
25
frontend/src/Components/Link/Link.css
Normal file
25
frontend/src/Components/Link/Link.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
.link {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
border: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
text-align: inherit;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:global(.isDisabled) {
|
||||
/*color: $disabledColor;*/
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.to {
|
||||
color: $linkColor;
|
||||
|
||||
&:hover {
|
||||
color: $linkHoverColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
101
frontend/src/Components/Link/Link.js
Normal file
101
frontend/src/Components/Link/Link.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import styles from './Link.css';
|
||||
|
||||
class Link extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onClick = (event) => {
|
||||
const {
|
||||
isDisabled,
|
||||
onPress
|
||||
} = this.props;
|
||||
|
||||
if (!isDisabled && onPress) {
|
||||
onPress(event);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
component,
|
||||
to,
|
||||
target,
|
||||
isDisabled,
|
||||
noRouter,
|
||||
onPress,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const linkProps = { target };
|
||||
let el = component;
|
||||
|
||||
if (to) {
|
||||
if (/\w+?:\/\//.test(to)) {
|
||||
el = 'a';
|
||||
linkProps.href = to;
|
||||
linkProps.target = target || '_blank';
|
||||
} else if (noRouter) {
|
||||
el = 'a';
|
||||
linkProps.href = to;
|
||||
linkProps.target = target || '_self';
|
||||
} else if (to.startsWith(window.Sonarr.urlBase)) {
|
||||
el = RouterLink;
|
||||
linkProps.to = to;
|
||||
linkProps.target = target;
|
||||
} else {
|
||||
el = RouterLink;
|
||||
linkProps.to = `${window.Sonarr.urlBase}/${to.replace(/^\//, '')}`;
|
||||
linkProps.target = target;
|
||||
}
|
||||
}
|
||||
|
||||
if (el === 'button' || el === 'input') {
|
||||
linkProps.type = otherProps.type || 'button';
|
||||
linkProps.disabled = isDisabled;
|
||||
}
|
||||
|
||||
linkProps.className = classNames(
|
||||
className,
|
||||
styles.link,
|
||||
to && styles.to,
|
||||
isDisabled && 'isDisabled'
|
||||
);
|
||||
|
||||
const props = {
|
||||
...otherProps,
|
||||
...linkProps
|
||||
};
|
||||
|
||||
props.onClick = this.onClick;
|
||||
|
||||
return (
|
||||
React.createElement(el, props)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Link.propTypes = {
|
||||
className: PropTypes.string,
|
||||
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
to: PropTypes.string,
|
||||
target: PropTypes.string,
|
||||
isDisabled: PropTypes.bool,
|
||||
noRouter: PropTypes.bool,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
Link.defaultProps = {
|
||||
component: 'button',
|
||||
noRouter: false
|
||||
};
|
||||
|
||||
export default Link;
|
37
frontend/src/Components/Link/SpinnerButton.css
Normal file
37
frontend/src/Components/Link/SpinnerButton.css
Normal file
|
@ -0,0 +1,37 @@
|
|||
.button {
|
||||
composes: button from 'Components/Link/Button.css';
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.spinnerContainer {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -100%;
|
||||
display: inline-flex;
|
||||
visibility: hidden;
|
||||
transition: left $defaultSpeed;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
.spinner {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.label {
|
||||
position: relative;
|
||||
left: 0;
|
||||
transition: left $defaultSpeed, opacity $defaultSpeed;
|
||||
}
|
||||
|
||||
.isSpinning {
|
||||
.spinnerContainer {
|
||||
left: 50%;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.label {
|
||||
left: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
59
frontend/src/Components/Link/SpinnerButton.js
Normal file
59
frontend/src/Components/Link/SpinnerButton.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from './Button';
|
||||
import styles from './SpinnerButton.css';
|
||||
|
||||
function SpinnerButton(props) {
|
||||
const {
|
||||
className,
|
||||
isSpinning,
|
||||
isDisabled,
|
||||
spinnerIcon,
|
||||
children,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={classNames(
|
||||
className,
|
||||
styles.button,
|
||||
isSpinning && styles.isSpinning
|
||||
)}
|
||||
isDisabled={isDisabled || isSpinning}
|
||||
{...otherProps}
|
||||
>
|
||||
<span className={styles.spinnerContainer}>
|
||||
<Icon
|
||||
className={styles.spinner}
|
||||
name={classNames(
|
||||
spinnerIcon,
|
||||
'fa-spin'
|
||||
)}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className={styles.label}>
|
||||
{children}
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
SpinnerButton.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
isSpinning: PropTypes.bool.isRequired,
|
||||
isDisabled: PropTypes.bool,
|
||||
spinnerIcon: PropTypes.string.isRequired,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
SpinnerButton.defaultProps = {
|
||||
className: styles.button,
|
||||
spinnerIcon: icons.SPINNER
|
||||
};
|
||||
|
||||
export default SpinnerButton;
|
23
frontend/src/Components/Link/SpinnerErrorButton.css
Normal file
23
frontend/src/Components/Link/SpinnerErrorButton.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
.iconContainer {
|
||||
composes: spinnerContainer from 'Components/Link/SpinnerButton.css';
|
||||
}
|
||||
|
||||
.icon {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.label {
|
||||
composes: label from 'Components/Link/SpinnerButton.css';
|
||||
}
|
||||
|
||||
.showIcon {
|
||||
.iconContainer {
|
||||
left: 50%;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.label {
|
||||
left: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
162
frontend/src/Components/Link/SpinnerErrorButton.js
Normal file
162
frontend/src/Components/Link/SpinnerErrorButton.js
Normal file
|
@ -0,0 +1,162 @@
|
|||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import styles from './SpinnerErrorButton.css';
|
||||
|
||||
function getTestResult(error) {
|
||||
if (!error) {
|
||||
return {
|
||||
wasSuccessful: true,
|
||||
hasWarning: false,
|
||||
hasError: false
|
||||
};
|
||||
}
|
||||
|
||||
if (error.status !== 400) {
|
||||
return {
|
||||
wasSuccessful: false,
|
||||
hasWarning: false,
|
||||
hasError: true
|
||||
};
|
||||
}
|
||||
|
||||
const failures = error.responseJSON;
|
||||
|
||||
const hasWarning = _.some(failures, { isWarning: true });
|
||||
const hasError = _.some(failures, (failure) => !failure.isWarning);
|
||||
|
||||
return {
|
||||
wasSuccessful: false,
|
||||
hasWarning,
|
||||
hasError
|
||||
};
|
||||
}
|
||||
|
||||
class SpinnerErrorButton extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._testResultTimeout = null;
|
||||
|
||||
this.state = {
|
||||
wasSuccessful: false,
|
||||
hasWarning: false,
|
||||
hasError: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
isSpinning,
|
||||
error
|
||||
} = this.props;
|
||||
|
||||
if (prevProps.isSpinning && !isSpinning) {
|
||||
const testResult = getTestResult(error);
|
||||
|
||||
this.setState(testResult, () => {
|
||||
const {
|
||||
wasSuccessful,
|
||||
hasWarning,
|
||||
hasError
|
||||
} = testResult;
|
||||
|
||||
if (wasSuccessful || hasWarning || hasError) {
|
||||
this._testResultTimeout = setTimeout(this.resetState, 3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._testResultTimeout) {
|
||||
clearTimeout(this._testResultTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
resetState = () => {
|
||||
this.setState({
|
||||
wasSuccessful: false,
|
||||
hasWarning: false,
|
||||
hasError: false
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isSpinning,
|
||||
error,
|
||||
children,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
wasSuccessful,
|
||||
hasWarning,
|
||||
hasError
|
||||
} = this.state;
|
||||
|
||||
const showIcon = wasSuccessful || hasWarning || hasError;
|
||||
|
||||
let iconName = icons.CHECK;
|
||||
let iconKind = kinds.SUCCESS;
|
||||
|
||||
if (hasWarning) {
|
||||
iconName = icons.WARNING;
|
||||
iconKind = kinds.WARNING;
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
iconName = icons.DANGER;
|
||||
iconKind = kinds.DANGER;
|
||||
}
|
||||
|
||||
return (
|
||||
<SpinnerButton
|
||||
isSpinning={isSpinning}
|
||||
{...otherProps}
|
||||
>
|
||||
<span className={showIcon && styles.showIcon}>
|
||||
{
|
||||
showIcon &&
|
||||
<span className={styles.iconContainer}>
|
||||
<Icon
|
||||
name={iconName}
|
||||
kind={iconKind}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
<span className={styles.label}>
|
||||
{
|
||||
children
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</span>
|
||||
</SpinnerButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SpinnerErrorButton.propTypes = {
|
||||
isSpinning: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
export default SpinnerErrorButton;
|
37
frontend/src/Components/Link/SpinnerIconButton.js
Normal file
37
frontend/src/Components/Link/SpinnerIconButton.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import IconButton from './IconButton';
|
||||
|
||||
function SpinnerIconButton(props) {
|
||||
const {
|
||||
name,
|
||||
spinningName,
|
||||
isDisabled,
|
||||
isSpinning,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
name={isSpinning ? `${spinningName || name} fa-spin` : name}
|
||||
isDisabled={isDisabled || isSpinning}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
SpinnerIconButton.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
spinningName: PropTypes.string.isRequired,
|
||||
isDisabled: PropTypes.bool.isRequired,
|
||||
isSpinning: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
SpinnerIconButton.defaultProps = {
|
||||
spinningName: icons.SPINNER,
|
||||
isDisabled: false,
|
||||
isSpinning: false
|
||||
};
|
||||
|
||||
export default SpinnerIconButton;
|
Loading…
Add table
Add a link
Reference in a new issue