New: Alternate styling for progress bars when color impaired mode is enabled

pull/2900/head
Mark McDowall 6 years ago
parent 647e444a07
commit ef7a08879f

@ -209,7 +209,6 @@
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": false }], "lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": false }],
"max-depth": ["error", {"maximum": 5}], "max-depth": ["error", {"maximum": 5}],
"max-nested-callbacks": ["error", 4], "max-nested-callbacks": ["error", 4],
"max-params": ["error", 6],
"max-statements": "off", "max-statements": "off",
"max-statements-per-line": ["error", { "max": 1 }], "max-statements-per-line": ["error", { "max": 1 }],
"new-cap": ["error", {"capIsNewExceptions": ["$.Deferred", "DragDropContext", "DragLayer", "DragSource", "DropTarget"]}], "new-cap": ["error", {"capIsNewExceptions": ["$.Deferred", "DragDropContext", "DragLayer", "DragSource", "DropTarget"]}],

@ -24,7 +24,7 @@
"ignoreAtRules": [ "ignoreAtRules": [
"/^add\\-mixin$/", "/^add\\-mixin$/",
"/^define\\-mixin$/" "/^define\\-mixin$/"
] ]
} }
], ],
"at-rule-no-vendor-prefix": true, "at-rule-no-vendor-prefix": true,

@ -0,0 +1,6 @@
import React from 'react';
const ColorImpairedContext = React.createContext(false);
export const ColorImpairedConsumer = ColorImpairedContext.Consumer;
export default ColorImpairedContext;

@ -63,6 +63,21 @@ function Legend(props) {
/> />
</div> </div>
<div>
<LegendItem
status="onAir"
name="On Air"
tooltip="Episode is currently airing"
colorImpairedMode={colorImpairedMode}
/>
<LegendItem
status="missing"
tooltip="Episode has aired and is missing from disk"
colorImpairedMode={colorImpairedMode}
/>
</div>
<div> <div>
<LegendItem <LegendItem
status="downloading" status="downloading"

@ -2,8 +2,9 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import locationShape from 'Helpers/Props/Shapes/locationShape'; import locationShape from 'Helpers/Props/Shapes/locationShape';
import SignalRConnector from 'Components/SignalRConnector'; import SignalRConnector from 'Components/SignalRConnector';
import AppUpdatedModalConnector from 'App/AppUpdatedModalConnector'; import ColorImpairedContext from 'App/ColorImpairedContext';
import ConnectionLostModalConnector from 'App/ConnectionLostModalConnector'; import ConnectionLostModalConnector from 'App/ConnectionLostModalConnector';
import AppUpdatedModalConnector from 'App/AppUpdatedModalConnector';
import PageHeader from './Header/PageHeader'; import PageHeader from './Header/PageHeader';
import PageSidebar from './Sidebar/PageSidebar'; import PageSidebar from './Sidebar/PageSidebar';
import styles from './Page.css'; import styles from './Page.css';
@ -73,39 +74,42 @@ class Page extends Component {
children, children,
isSmallScreen, isSmallScreen,
isSidebarVisible, isSidebarVisible,
enableColorImpairedMode,
onSidebarToggle, onSidebarToggle,
onSidebarVisibleChange onSidebarVisibleChange
} = this.props; } = this.props;
return ( return (
<div className={className}> <ColorImpairedContext.Provider value={enableColorImpairedMode}>
<SignalRConnector /> <div className={className}>
<SignalRConnector />
<PageHeader
onSidebarToggle={onSidebarToggle} <PageHeader
/> onSidebarToggle={onSidebarToggle}
<div className={styles.main}>
<PageSidebar
location={location}
isSmallScreen={isSmallScreen}
isSidebarVisible={isSidebarVisible}
onSidebarVisibleChange={onSidebarVisibleChange}
/> />
{children} <div className={styles.main}>
</div> <PageSidebar
location={location}
isSmallScreen={isSmallScreen}
isSidebarVisible={isSidebarVisible}
onSidebarVisibleChange={onSidebarVisibleChange}
/>
<AppUpdatedModalConnector {children}
isOpen={this.state.isUpdatedModalOpen} </div>
onModalClose={this.onUpdatedModalClose}
/>
<ConnectionLostModalConnector <AppUpdatedModalConnector
isOpen={this.state.isConnectionLostModalOpen} isOpen={this.state.isUpdatedModalOpen}
onModalClose={this.onConnectionLostModalClose} onModalClose={this.onUpdatedModalClose}
/> />
</div>
<ConnectionLostModalConnector
isOpen={this.state.isConnectionLostModalOpen}
onModalClose={this.onConnectionLostModalClose}
/>
</div>
</ColorImpairedContext.Provider>
); );
} }
} }
@ -118,6 +122,7 @@ Page.propTypes = {
isSidebarVisible: PropTypes.bool.isRequired, isSidebarVisible: PropTypes.bool.isRequired,
isUpdated: PropTypes.bool.isRequired, isUpdated: PropTypes.bool.isRequired,
isDisconnected: PropTypes.bool.isRequired, isDisconnected: PropTypes.bool.isRequired,
enableColorImpairedMode: PropTypes.bool.isRequired,
onResize: PropTypes.func.isRequired, onResize: PropTypes.func.isRequired,
onSidebarToggle: PropTypes.func.isRequired, onSidebarToggle: PropTypes.func.isRequired,
onSidebarVisibleChange: PropTypes.func.isRequired onSidebarVisibleChange: PropTypes.func.isRequired

@ -32,25 +32,37 @@ function createMapStateToProps() {
(state) => state.series, (state) => state.series,
(state) => state.customFilters, (state) => state.customFilters,
(state) => state.tags, (state) => state.tags,
(state) => state.settings, (state) => state.settings.ui,
(state) => state.settings.qualityProfiles,
(state) => state.settings.languageProfiles,
(state) => state.app, (state) => state.app,
createDimensionsSelector(), createDimensionsSelector(),
(series, customFilters, tags, settings, app, dimensions) => { (
series,
customFilters,
tags,
uiSettings,
qualityProfiles,
languageProfiles,
app,
dimensions
) => {
const isPopulated = ( const isPopulated = (
series.isPopulated && series.isPopulated &&
customFilters.isPopulated && customFilters.isPopulated &&
tags.isPopulated && tags.isPopulated &&
settings.qualityProfiles.isPopulated && qualityProfiles.isPopulated &&
settings.ui.isPopulated languageProfiles.isPopulated &&
uiSettings.isPopulated
); );
const hasError = !!( const hasError = !!(
series.error || series.error ||
customFilters.error || customFilters.error ||
tags.error || tags.error ||
settings.qualityProfiles.error || qualityProfiles.error ||
settings.languageProfiles.error || languageProfiles.error ||
settings.ui.error uiSettings.error
); );
return { return {
@ -59,10 +71,12 @@ function createMapStateToProps() {
seriesError: series.error, seriesError: series.error,
customFiltersError: tags.error, customFiltersError: tags.error,
tagsError: tags.error, tagsError: tags.error,
qualityProfilesError: settings.qualityProfiles.error, qualityProfilesError: qualityProfiles.error,
uiSettingsError: settings.ui.error, languageProfilesError: languageProfiles.error,
uiSettingsError: uiSettings.error,
isSmallScreen: dimensions.isSmallScreen, isSmallScreen: dimensions.isSmallScreen,
isSidebarVisible: app.isSidebarVisible, isSidebarVisible: app.isSidebarVisible,
enableColorImpairedMode: uiSettings.item.enableColorImpairedMode,
version: app.version, version: app.version,
isUpdated: app.isUpdated, isUpdated: app.isUpdated,
isDisconnected: app.isDisconnected isDisconnected: app.isDisconnected

@ -43,10 +43,18 @@
.primary { .primary {
background-color: $primaryColor; background-color: $primaryColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $primaryColor, $primaryColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.danger { .danger {
background-color: $dangerColor; background-color: $dangerColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $dangerColor, $dangerColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.success { .success {
@ -59,6 +67,10 @@
.warning { .warning {
background-color: $warningColor; background-color: $warningColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $warningColor, $warningColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.info { .info {

@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { kinds, sizes } from 'Helpers/Props'; import { kinds, sizes } from 'Helpers/Props';
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import styles from './ProgressBar.css'; import styles from './ProgressBar.css';
function ProgressBar(props) { function ProgressBar(props) {
@ -23,55 +24,65 @@ function ProgressBar(props) {
const actualWidth = width ? `${width}px` : '100%'; const actualWidth = width ? `${width}px` : '100%';
return ( return (
<div <ColorImpairedConsumer>
className={classNames( {(enableColorImpairedMode) => {
containerClassName, return (
styles[size]
)}
title={title}
style={{ width: actualWidth }}
>
{
showText && !!width &&
<div <div
className={styles.backTextContainer} className={classNames(
containerClassName,
styles[size]
)}
title={title}
style={{ width: actualWidth }} style={{ width: actualWidth }}
> >
<div className={styles.backText}> {
<div> showText && width ?
{progressText} <div
</div> className={styles.backTextContainer}
</div> style={{ width: actualWidth }}
</div> >
} <div className={styles.backText}>
<div>
{progressText}
</div>
</div>
</div> :
null
}
<div <div
className={classNames( className={classNames(
className, className,
styles[kind] styles[kind],
)} enableColorImpairedMode && 'colorImpaired'
aria-valuenow={progress} )}
aria-valuemin="0" aria-valuenow={progress}
aria-valuemax="100" aria-valuemin="0"
style={{ width: progressPercent }} aria-valuemax="100"
/> style={{ width: progressPercent }}
{ />
showText &&
<div {
className={styles.frontTextContainer} showText ?
style={{ width: progressPercent }} <div
> className={styles.frontTextContainer}
<div style={{ width: progressPercent }}
className={styles.frontText} >
style={{ width: actualWidth }} <div
> className={styles.frontText}
<div> style={{ width: actualWidth }}
{progressText} >
</div> <div>
{progressText}
</div>
</div>
</div> :
null
}
</div> </div>
</div> );
} }}
</div> </ColorImpairedConsumer>
); );
} }

@ -22,6 +22,10 @@
composes: legendItemColor; composes: legendItemColor;
background-color: $primaryColor; background-color: $primaryColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $primaryColor, $primaryColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.ended { .ended {
@ -34,12 +38,20 @@
composes: legendItemColor; composes: legendItemColor;
background-color: $dangerColor; background-color: $dangerColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $dangerColor, $dangerColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.missingUnmonitored { .missingUnmonitored {
composes: legendItemColor; composes: legendItemColor;
background-color: $warningColor; background-color: $warningColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $warningColor, $warningColor 10px, $colorImpairedAlternateGradient 10px, $colorImpairedAlternateGradient 20px);
}
} }
.statistics { .statistics {

@ -1,6 +1,8 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import styles from './SeriesIndexFooter.css'; import styles from './SeriesIndexFooter.css';
@ -40,79 +42,105 @@ function SeriesIndexFooter({ series }) {
}); });
return ( return (
<div className={styles.footer}> <ColorImpairedConsumer>
<div> {(enableColorImpairedMode) => {
<div className={styles.legendItem}> return (
<div className={styles.continuing} /> <div className={styles.footer}>
<div>Continuing (All episodes downloaded)</div> <div>
</div> <div className={styles.legendItem}>
<div
<div className={styles.legendItem}> className={classNames(
<div className={styles.ended} /> styles.continuing,
<div>Ended (All episodes downloaded)</div> enableColorImpairedMode && 'colorImpaired'
</div> )}
/>
<div className={styles.legendItem}> <div>Continuing (All episodes downloaded)</div>
<div className={styles.missingMonitored} /> </div>
<div>Missing Episodes (Series monitored)</div>
</div> <div className={styles.legendItem}>
<div
<div className={styles.legendItem}> className={classNames(
<div className={styles.missingUnmonitored} /> styles.ended,
<div>Missing Episodes (Series not monitored)</div> enableColorImpairedMode && 'colorImpaired'
</div> )}
</div> />
<div>Ended (All episodes downloaded)</div>
<div className={styles.statistics}> </div>
<DescriptionList>
<DescriptionListItem <div className={styles.legendItem}>
title="Series" <div
data={count} className={classNames(
/> styles.missingMonitored,
enableColorImpairedMode && 'colorImpaired'
<DescriptionListItem )}
title="Ended" />
data={ended} <div>Missing Episodes (Series monitored)</div>
/> </div>
<DescriptionListItem <div className={styles.legendItem}>
title="Continuing" <div
data={continuing} className={classNames(
/> styles.missingUnmonitored,
</DescriptionList> enableColorImpairedMode && 'colorImpaired'
)}
<DescriptionList> />
<DescriptionListItem <div>Missing Episodes (Series not monitored)</div>
title="Monitored" </div>
data={monitored} </div>
/>
<div className={styles.statistics}>
<DescriptionListItem <DescriptionList>
title="Unmonitored" <DescriptionListItem
data={count - monitored} title="Series"
/> data={count}
</DescriptionList> />
<DescriptionList> <DescriptionListItem
<DescriptionListItem title="Ended"
title="Episodes" data={ended}
data={episodes} />
/>
<DescriptionListItem
<DescriptionListItem title="Continuing"
title="Files" data={continuing}
data={episodeFiles} />
/> </DescriptionList>
</DescriptionList>
<DescriptionList>
<DescriptionList> <DescriptionListItem
<DescriptionListItem title="Monitored"
title="Total File Size" data={monitored}
data={formatBytes(totalFileSize)} />
/>
</DescriptionList> <DescriptionListItem
</div> title="Unmonitored"
</div> data={count - monitored}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title="Episodes"
data={episodes}
/>
<DescriptionListItem
title="Files"
data={episodeFiles}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title="Total File Size"
data={formatBytes(totalFileSize)}
/>
</DescriptionList>
</div>
</div>
);
}}
</ColorImpairedConsumer>
); );
} }

@ -62,6 +62,7 @@ module.exports = {
inputWarningBorderColor: '#ffa500', inputWarningBorderColor: '#ffa500',
inputWarningBoxShadowColor: 'rgba(255, 165, 0, 0.6)', inputWarningBoxShadowColor: 'rgba(255, 165, 0, 0.6)',
colorImpairedGradient: '#fcfcfc', colorImpairedGradient: '#fcfcfc',
colorImpairedAlternateGradient: '#b0b0b0',
// //
// Buttons // Buttons

Loading…
Cancel
Save