mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 07:32:02 +00:00
DiscreteSelectInput component implemented
This commit is contained in:
parent
4e28aebc33
commit
bd428e3ec1
5 changed files with 123 additions and 86 deletions
|
|
@ -0,0 +1,45 @@
|
||||||
|
const React = require('react');
|
||||||
|
const PropTypes = require('prop-types');
|
||||||
|
const classnames = require('classnames');
|
||||||
|
const Icon = require('stremio-icons/dom');
|
||||||
|
const { Button } = require('stremio/common');
|
||||||
|
const styles = require('./styles');
|
||||||
|
|
||||||
|
const DiscreteSelectInput = ({ className, value, label, disabled, dataset, onChange }) => {
|
||||||
|
const buttonOnClick = React.useCallback((event) => {
|
||||||
|
if (typeof onChange === 'function') {
|
||||||
|
onChange({
|
||||||
|
type: 'change',
|
||||||
|
value: event.currentTarget.dataset.type,
|
||||||
|
dataset: dataset,
|
||||||
|
reactEvent: event,
|
||||||
|
nativeEvent: event.nativeEvent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [dataset, onChange]);
|
||||||
|
return (
|
||||||
|
<div className={classnames(className, styles['discrete-input-container'], { 'disabled': disabled })}>
|
||||||
|
<div className={styles['header']}>{label}</div>
|
||||||
|
<div className={styles['input-container']} title={disabled ? `${label} is not configurable` : null}>
|
||||||
|
<Button className={classnames(styles['button-container'], { 'disabled': disabled })} data-type={'decrement'} onClick={buttonOnClick}>
|
||||||
|
<Icon className={styles['icon']} icon={'ic_minus'} />
|
||||||
|
</Button>
|
||||||
|
<div className={styles['option-label']} title={value}>{value}</div>
|
||||||
|
<Button className={classnames(styles['button-container'], { 'disabled': disabled })} data-type={'increment'} onClick={buttonOnClick}>
|
||||||
|
<Icon className={styles['icon']} icon={'ic_plus'} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DiscreteSelectInput.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
value: PropTypes.string,
|
||||||
|
label: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
dataset: PropTypes.object,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DiscreteSelectInput;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
const DiscreteSelectInput = require('./DiscreteSelectInput');
|
||||||
|
|
||||||
|
module.exports = DiscreteSelectInput;
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
@import (reference) '~stremio-colors/dist/less/stremio-colors.less';
|
||||||
|
|
||||||
|
.discrete-input-container {
|
||||||
|
&:global(.disabled) {
|
||||||
|
.header {
|
||||||
|
color: @color-surface-90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
max-height: 2.4em;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: @color-surface-light5-90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
background: @color-background-dark1;
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
flex: none;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: @color-background-light2;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
fill: @color-surface-light5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-label {
|
||||||
|
flex: 1;
|
||||||
|
max-height: 2.4em;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
color: @color-surface-light5-90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ const PropTypes = require('prop-types');
|
||||||
const classnames = require('classnames');
|
const classnames = require('classnames');
|
||||||
const Icon = require('stremio-icons/dom');
|
const Icon = require('stremio-icons/dom');
|
||||||
const { Button, ColorInput } = require('stremio/common');
|
const { Button, ColorInput } = require('stremio/common');
|
||||||
|
const DiscreteSelectInput = require('./DiscreteSelectInput');
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
|
|
||||||
const SUBTITLES_SIZES = [75, 100, 125, 150, 175, 200, 250];
|
const SUBTITLES_SIZES = [75, 100, 125, 150, 175, 200, 250];
|
||||||
|
|
@ -57,11 +58,6 @@ const SubtitlesPicker = (props) => {
|
||||||
:
|
:
|
||||||
[];
|
[];
|
||||||
}, [props.tracks, selectedLanguage]);
|
}, [props.tracks, selectedLanguage]);
|
||||||
const offsetDisabled = React.useMemo(() => {
|
|
||||||
return typeof selectedLanguage !== 'string' ||
|
|
||||||
props.offset === null ||
|
|
||||||
isNaN(props.offset);
|
|
||||||
}, [selectedLanguage, props.offset]);
|
|
||||||
const onMouseDown = React.useCallback((event) => {
|
const onMouseDown = React.useCallback((event) => {
|
||||||
event.nativeEvent.subtitlesPickerClosePrevented = true;
|
event.nativeEvent.subtitlesPickerClosePrevented = true;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -81,9 +77,10 @@ const SubtitlesPicker = (props) => {
|
||||||
const trackOnClick = React.useCallback((event) => {
|
const trackOnClick = React.useCallback((event) => {
|
||||||
props.onTrackSelected(event.currentTarget.dataset.trackId);
|
props.onTrackSelected(event.currentTarget.dataset.trackId);
|
||||||
}, [props.onTrackSelected]);
|
}, [props.onTrackSelected]);
|
||||||
const onOffsetButtonClicked = React.useCallback((event) => {
|
const onOffsetChange = React.useCallback((event) => {
|
||||||
if (props.offset !== null && !isNaN(props.offset)) {
|
if (props.offset !== null && !isNaN(props.offset)) {
|
||||||
const offset = props.offset + parseInt(event.currentTarget.dataset.offset);
|
const delta = event.value === 'increment' ? 1 : -1;
|
||||||
|
const offset = props.offset + delta;
|
||||||
if (typeof props.onOffsetChanged === 'function') {
|
if (typeof props.onOffsetChanged === 'function') {
|
||||||
props.onOffsetChanged(offset);
|
props.onOffsetChanged(offset);
|
||||||
}
|
}
|
||||||
|
|
@ -143,38 +140,25 @@ const SubtitlesPicker = (props) => {
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['subtitles-settings-container']}>
|
<div className={styles['subtitles-settings-container']}>
|
||||||
<div className={styles['settings-header']}>Settings</div>
|
<div className={styles['settings-header']}>Settings</div>
|
||||||
<div className={styles['option-header']}>Delay</div>
|
<DiscreteSelectInput
|
||||||
<div className={styles['option-container']}>
|
className={styles['discrete-input']}
|
||||||
<Button className={styles['button-container']}>
|
label={'Delay'}
|
||||||
<Icon className={styles['icon']} icon={'ic_minus'} />
|
value={props.delay !== null && !isNaN(props.delay) ? `${props.delay}ms` : '--'}
|
||||||
</Button>
|
disabled={typeof selectedLanguage !== 'string' || props.delay === null || isNaN(props.delay)}
|
||||||
<div className={styles['option-label']} title={'150s'}>150s</div>
|
/>
|
||||||
<Button className={styles['button-container']}>
|
<DiscreteSelectInput
|
||||||
<Icon className={styles['icon']} icon={'ic_plus'} />
|
className={styles['discrete-input']}
|
||||||
</Button>
|
label={'Size'}
|
||||||
</div>
|
value={props.size !== null && !isNaN(props.size) ? `${props.size}ms` : '--'}
|
||||||
<div className={styles['option-header']}>Size</div>
|
disabled={typeof selectedLanguage !== 'string' || props.size === null || isNaN(props.size)}
|
||||||
<div className={styles['option-container']}>
|
/>
|
||||||
<Button className={styles['button-container']}>
|
<DiscreteSelectInput
|
||||||
<Icon className={styles['icon']} icon={'ic_minus'} />
|
className={styles['discrete-input']}
|
||||||
</Button>
|
label={'Vertical position'}
|
||||||
<div className={styles['option-label']} title={'100%'}>100%</div>
|
value={props.offset !== null && !isNaN(props.offset) ? `${props.offset}%` : '--'}
|
||||||
<Button className={styles['button-container']}>
|
disabled={typeof selectedLanguage !== 'string' || props.offset === null || isNaN(props.offset)}
|
||||||
<Icon className={styles['icon']} icon={'ic_plus'} />
|
onChange={onOffsetChange}
|
||||||
</Button>
|
/>
|
||||||
</div>
|
|
||||||
<div className={classnames(styles['option-header'], { 'disabled': offsetDisabled })}>Vertical position</div>
|
|
||||||
<div className={classnames(styles['option-container'], { 'disabled': offsetDisabled })} title={offsetDisabled ? 'Vertical position is not configurable' : null}>
|
|
||||||
<Button className={classnames(styles['button-container'], { 'disabled': offsetDisabled })} data-offset={-1} onClick={onOffsetButtonClicked}>
|
|
||||||
<Icon className={styles['icon']} icon={'ic_minus'} />
|
|
||||||
</Button>
|
|
||||||
<div className={styles['option-label']} title={props.offset !== null && !isNaN(props.offset) ? `${props.offset}%` : null}>
|
|
||||||
{props.offset !== null && !isNaN(props.offset) ? `${props.offset}%` : '--'}
|
|
||||||
</div>
|
|
||||||
<Button className={classnames(styles['button-container'], { 'disabled': offsetDisabled })} data-offset={1} onClick={onOffsetButtonClicked}>
|
|
||||||
<Icon className={styles['icon']} icon={'ic_plus'} />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className={styles['spacing']} />
|
<div className={styles['spacing']} />
|
||||||
<Button className={styles['advanced-button']}>Advanced</Button>
|
<Button className={styles['advanced-button']}>Advanced</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -192,7 +176,7 @@ SubtitlesPicker.propTypes = {
|
||||||
selectedTrackId: PropTypes.string,
|
selectedTrackId: PropTypes.string,
|
||||||
offset: PropTypes.number,
|
offset: PropTypes.number,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
felay: PropTypes.number,
|
delay: PropTypes.number,
|
||||||
textColor: PropTypes.string,
|
textColor: PropTypes.string,
|
||||||
backgroundColor: PropTypes.string,
|
backgroundColor: PropTypes.string,
|
||||||
outlineColor: PropTypes.string,
|
outlineColor: PropTypes.string,
|
||||||
|
|
|
||||||
|
|
@ -92,53 +92,9 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-header {
|
.discrete-input {
|
||||||
flex: none;
|
margin: 0 3rem 1rem;
|
||||||
align-self: stretch;
|
|
||||||
max-height: 2.4em;
|
|
||||||
margin: 0 3rem;
|
|
||||||
color: @color-surface-light5-90;
|
|
||||||
|
|
||||||
&:global(.disabled) {
|
|
||||||
color: @color-surface-90;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-container {
|
|
||||||
flex: none;
|
|
||||||
align-self: stretch;
|
|
||||||
margin: 0.5rem 3rem 1rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
background: @color-background-dark1;
|
|
||||||
|
|
||||||
&:global(.disabled) {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-container {
|
|
||||||
flex: none;
|
|
||||||
width: 3rem;
|
|
||||||
height: 3rem;
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: @color-background-light2;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
fill: @color-surface-light5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-label {
|
|
||||||
flex: 1;
|
|
||||||
max-height: 2.4em;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
color: @color-surface-light5-90;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.advanced-button {
|
.advanced-button {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue