diff --git a/src/client/components/facet_bar/slider/DateSlider.js b/src/client/components/facet_bar/slider/DateSlider.js index 1ece0a16aa6867d849f6be66ab324eb85d353e43..b791b08758da9359a3b20a300be410b664efad0c 100644 --- a/src/client/components/facet_bar/slider/DateSlider.js +++ b/src/client/components/facet_bar/slider/DateSlider.js @@ -1,27 +1,20 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider'; -import { withStyles } from '@material-ui/core/styles'; -import { SliderRail, Handle, Track, Tick } from './SliderComponents'; // example render components - source below +import { Handle, Track, Tick, TooltipRail } from './SliderComponents'; // example render components - source below -const style = () => ({ - root: { - height: 120, - width: '100%', - }, - slider: { - position: 'relative', - width: '100%', - }, -}); +const sliderStyle = { + position: 'relative', + width: '100%', +}; -const domain = [100, 500]; -const defaultValues = [150, 300, 400, 450]; +const defaultValues = [240, 360]; class Example extends Component { state = { + domain: [100, 600], values: defaultValues.slice(), update: defaultValues.slice(), + reversed: false, } onUpdate = update => { @@ -32,35 +25,41 @@ class Example extends Component { this.setState({ values }); } + setDomain = domain => { + this.setState({ domain }); + } + + toggleReverse = () => { + this.setState(prev => ({ reversed: !prev.reversed })); + } + render() { const { - props: { classes }, - state: { values, update }, + state: { domain, values, reversed }, } = this; return ( - <div className={classes.root}> + <div style={{ height: 150, width: '100%' }}> <Slider mode={1} step={1} domain={domain} - className={classes.slider} + reversed={reversed} + rootStyle={sliderStyle} onUpdate={this.onUpdate} onChange={this.onChange} values={values} > - <Rail> - {({ getRailProps }) => <SliderRail getRailProps={getRailProps} />} - </Rail> + <Rail>{railProps => <TooltipRail {...railProps} />}</Rail> <Handles> - {({ activeHandleID, handles, getHandleProps }) => ( - <div> + {({ handles, activeHandleID, getHandleProps }) => ( + <div className="slider-handles"> {handles.map(handle => ( <Handle key={handle.id} handle={handle} domain={domain} - activeHandleID={activeHandleID} + isActive={handle.id === activeHandleID} getHandleProps={getHandleProps} /> ))} @@ -69,7 +68,7 @@ class Example extends Component { </Handles> <Tracks left={false} right={false}> {({ tracks, getTrackProps }) => ( - <div> + <div className="slider-tracks"> {tracks.map(({ id, source, target }) => ( <Track key={id} @@ -81,9 +80,9 @@ class Example extends Component { </div> )} </Tracks> - <Ticks count={5}> + <Ticks count={10}> {({ ticks }) => ( - <div> + <div className="slider-ticks"> {ticks.map(tick => ( <Tick key={tick.id} tick={tick} count={ticks.length} /> ))} @@ -96,8 +95,4 @@ class Example extends Component { } } -Example.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(style)(Example); +export default Example; diff --git a/src/client/components/facet_bar/slider/SliderComponents.js b/src/client/components/facet_bar/slider/SliderComponents.js index 3c966d314efccfa0490dc5f26ff16830ee4aa89e..8faacab469f3ddd4c69eb2c8ae3d439493d1dc1a 100644 --- a/src/client/components/facet_bar/slider/SliderComponents.js +++ b/src/client/components/facet_bar/slider/SliderComponents.js @@ -1,154 +1,271 @@ -import React, { Fragment } from 'react'; -import clsx from 'clsx'; +import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { fade } from '@material-ui/core/styles/colorManipulator'; -import Typography from '@material-ui/core/Typography'; -import { withStyles } from '@material-ui/core/styles'; +//import './tooltip.css'; // ******************************************************* -// RAIL COMPONENT +// TOOLTIP RAIL // ******************************************************* -const railStyle = () => ({ - common: { - position: 'absolute', - width: '100%', - transform: 'translate(0%, -50%)', - }, - outer: { - height: 42, - borderRadius: 21, - cursor: 'pointer', - border: '1px solid white', - }, - inner: { - height: 4, - borderRadius: 2, - pointerEvents: 'none', - backgroundColor: 'rgb(155,155,155)', - }, -}); - -function RailComponent({ classes, getRailProps }) { - return ( - <Fragment> - <div - className={clsx(classes.common, classes.outer)} - {...getRailProps()} - /> - <div className={clsx(classes.common, classes.inner)} /> - </Fragment> - ); +const railStyle = { + position: 'absolute', + width: '100%', + transform: 'translate(0%, -50%)', + height: 40, + cursor: 'pointer', + zIndex: 300, + // border: '1px solid grey', +}; + +const railCenterStyle = { + position: 'absolute', + width: '100%', + transform: 'translate(0%, -50%)', + height: 14, + borderRadius: 7, + cursor: 'pointer', + pointerEvents: 'none', + backgroundColor: 'rgb(155,155,155)', +}; + +const tooltipStyle = { + position: 'relative', + display: 'inline-block', + borderBottom: '1px dotted #444', + marginLeft: 22 +}; + +const tooltipTextStyle = { + width: 100, + backgroundColor: '#444', + color: '#f0f0f0', + opacity: 0.8, + textAlign: 'center', + borderRadius: 6, + padding: '5px 0', + position: 'absolute', + zIndex: 1, + bottom: '150%', + left: '50%', + marginLeft: '-60px' +}; + +export class TooltipRail extends Component { + state = { + value: null, + percent: null, + } + + onMouseEnter = () => { + document.addEventListener('mousemove', this.onMouseMove); + } + + onMouseLeave = () => { + this.setState({ value: null, percent: null }); + document.removeEventListener('mousemove', this.onMouseMove); + } + + onMouseMove = e => { + const { activeHandleID, getEventData } = this.props; + + if (activeHandleID) { + this.setState({ value: null, percent: null }); + } else { + this.setState(getEventData(e)); + } + } + + render() { + const { value, percent } = this.state; + const { activeHandleID, getRailProps } = this.props; + + return ( + <Fragment> + {!activeHandleID && value ? ( + <div + style={{ + left: `${percent}%`, + position: 'absolute', + marginLeft: '-11px', + marginTop: '-35px', + }} + > + <div style={tooltipStyle}> + <span style={tooltipTextStyle}>Value: {value}</span> + </div> + </div> + ) : null} + <div + style={railStyle} + {...getRailProps({ + onMouseEnter: this.onMouseEnter, + onMouseLeave: this.onMouseLeave, + })} + /> + <div style={railCenterStyle} /> + </Fragment> + ); + } } -RailComponent.propTypes = { - classes: PropTypes.object.isRequired, +TooltipRail.propTypes = { + getEventData: PropTypes.func, + activeHandleID: PropTypes.string, getRailProps: PropTypes.func.isRequired, }; -export const SliderRail = withStyles(railStyle)(RailComponent); +TooltipRail.defaultProps = { + disabled: false, +}; // ******************************************************* -// HANDLE COMPONENT +// SLIDER RAIL (no tooltips) // ******************************************************* -const handleStyle = theme => { - const colors = { - primary: theme.palette.primary.main, - thumbOutline: fade(theme.palette.primary.main, 0.16), - }; - - return { - common: { - position: 'absolute', - WebkitTapHighlightColor: 'rgba(0,0,0,0)', - }, - outer: { - zIndex: 5, - width: 20, - height: 40, - transform: 'translate(-50%, -50%)', - cursor: 'pointer', - backgroundColor: 'none', - }, - inner: { - zIndex: 2, - width: 12, - height: 12, - transform: 'translate(-50%, -50%)', - borderRadius: '50%', - backgroundColor: colors.primary, - }, - active: { - boxShadow: `0px 0px 0px 16px ${colors.thumbOutline}`, - }, - }; +const railOuterStyle = { + position: 'absolute', + transform: 'translate(0%, -50%)', + width: '100%', + height: 42, + borderRadius: 7, + cursor: 'pointer', + // border: '1px solid grey', }; -function HandleComponent({ - activeHandleID, - domain: [min, max], - handle: { id, value, percent }, - classes, - getHandleProps, -}) { - const active = activeHandleID === id; +const railInnerStyle = { + position: 'absolute', + width: '100%', + height: 14, + transform: 'translate(0%, -50%)', + borderRadius: 7, + pointerEvents: 'none', + backgroundColor: 'rgb(155,155,155)', +}; +export function SliderRail({ getRailProps }) { return ( <Fragment> - <div - className={clsx(classes.common, classes.outer)} - style={{ left: `${percent}%` }} - {...getHandleProps(id)} - /> - <div - role="slider" - aria-valuemin={min} - aria-valuemax={max} - aria-valuenow={value} - className={clsx( - classes.common, - classes.inner, - active && classes.active, - )} - style={{ left: `${percent}%` }} - /> + <div style={railOuterStyle} {...getRailProps()} /> + <div style={railInnerStyle} /> </Fragment> ); } -HandleComponent.propTypes = { - activeHandleID: PropTypes.string, +SliderRail.propTypes = { + getRailProps: PropTypes.func.isRequired, +}; + +// ******************************************************* +// HANDLE COMPONENT +// ******************************************************* +export class Handle extends Component { + state = { + mouseOver: false, + } + + onMouseEnter = () => { + this.setState({ mouseOver: true }); + } + + onMouseLeave = () => { + this.setState({ mouseOver: false }); + } + + render() { + const { + domain: [min, max], + handle: { id, value, percent }, + isActive, + disabled, + getHandleProps, + } = this.props; + const { mouseOver } = this.state; + + return ( + <Fragment> + {(mouseOver || isActive) && !disabled ? ( + <div + style={{ + left: `${percent}%`, + position: 'absolute', + marginLeft: '-11px', + marginTop: '-35px', + }} + > + <div style={tooltipStyle}> + <span style={tooltipTextStyle}>Value: {value}</span> + </div> + </div> + ) : null} + <div + style={{ + left: `${percent}%`, + position: 'absolute', + transform: 'translate(-50%, -50%)', + WebkitTapHighlightColor: 'rgba(0,0,0,0)', + zIndex: 400, + width: 26, + height: 42, + cursor: 'pointer', + // border: '1px solid grey', + backgroundColor: 'none', + }} + {...getHandleProps(id, { + onMouseEnter: this.onMouseEnter, + onMouseLeave: this.onMouseLeave, + })} + /> + <div + role="slider" + aria-valuemin={min} + aria-valuemax={max} + aria-valuenow={value} + style={{ + left: `${percent}%`, + position: 'absolute', + transform: 'translate(-50%, -50%)', + WebkitTapHighlightColor: 'rgba(0,0,0,0)', + zIndex: 300, + width: 24, + height: 24, + border: 0, + borderRadius: '50%', + boxShadow: '1px 1px 1px 1px rgba(0, 0, 0, 0.2)', + backgroundColor: disabled ? '#666' : '#8b6068', + }} + /> + </Fragment> + ); + } +} + +Handle.propTypes = { domain: PropTypes.array.isRequired, handle: PropTypes.shape({ id: PropTypes.string.isRequired, value: PropTypes.number.isRequired, percent: PropTypes.number.isRequired, }).isRequired, - classes: PropTypes.object.isRequired, getHandleProps: PropTypes.func.isRequired, + isActive: PropTypes.bool.isRequired, + disabled: PropTypes.bool, }; -export const Handle = withStyles(handleStyle)(HandleComponent); +Handle.defaultProps = { + disabled: false, +}; // ******************************************************* // TRACK COMPONENT // ******************************************************* -const trackStyle = theme => ({ - root: { - position: 'absolute', - transform: 'translate(0%, -50%)', - height: 4, - zIndex: 1, - borderRadius: 2, - cursor: 'pointer', - backgroundColor: theme.palette.primary.main, - }, -}); - -function TrackComponent({ classes, source, target, getTrackProps }) { +export function Track({ source, target, getTrackProps, disabled }) { return ( <div - className={classes.root} style={{ + position: 'absolute', + transform: 'translate(0%, -50%)', + height: 14, + zIndex: 1, + backgroundColor: disabled ? '#999' : '#8b6068', + borderRadius: 7, + cursor: 'pointer', left: `${source.percent}%`, width: `${target.percent - source.percent}%`, }} @@ -157,7 +274,7 @@ function TrackComponent({ classes, source, target, getTrackProps }) { ); } -TrackComponent.propTypes = { +Track.propTypes = { source: PropTypes.shape({ id: PropTypes.string.isRequired, value: PropTypes.number.isRequired, @@ -168,61 +285,57 @@ TrackComponent.propTypes = { value: PropTypes.number.isRequired, percent: PropTypes.number.isRequired, }).isRequired, - classes: PropTypes.object.isRequired, getTrackProps: PropTypes.func.isRequired, + disabled: PropTypes.bool, }; -export const Track = withStyles(trackStyle)(TrackComponent); +Track.defaultProps = { + disabled: false, +}; // ******************************************************* // TICK COMPONENT // ******************************************************* -const tickStyle = theme => ({ - tick: { - position: 'absolute', - marginTop: 10, - width: 1, - height: 5, - backgroundColor: theme.palette.text.primary, - }, - label: { - position: 'absolute', - marginTop: 16, - textAlign: 'center', - }, -}); - -export function TickComponent({ classes, tick, count, format }) { +export function Tick({ tick, count, format }) { return ( <div> - <div className={classes.tick} style={{ left: `${tick.percent}%` }} /> - <Typography - className={classes.label} + <div style={{ + position: 'absolute', + marginTop: 17, + width: 1, + height: 5, + backgroundColor: 'rgb(200,200,200)', + left: `${tick.percent}%`, + }} + /> + <div + style={{ + position: 'absolute', + marginTop: 25, + fontSize: 10, + textAlign: 'center', marginLeft: `${-(100 / count) / 2}%`, width: `${100 / count}%`, left: `${tick.percent}%`, }} > {format(tick.value)} - </Typography> + </div> </div> ); } -TickComponent.propTypes = { +Tick.propTypes = { tick: PropTypes.shape({ id: PropTypes.string.isRequired, value: PropTypes.number.isRequired, percent: PropTypes.number.isRequired, }).isRequired, - classes: PropTypes.object.isRequired, count: PropTypes.number.isRequired, format: PropTypes.func.isRequired, }; -TickComponent.defaultProps = { +Tick.defaultProps = { format: d => d, }; - -export const Tick = withStyles(tickStyle)(TickComponent); diff --git a/src/client/reducers/manuscriptsFacets.js b/src/client/reducers/manuscriptsFacets.js index 1ba62ca7e9880b96e051dd1a15fb909e79e126a2..5862376e0fa07163904f962163a2a0750962a8eb 100644 --- a/src/client/reducers/manuscriptsFacets.js +++ b/src/client/reducers/manuscriptsFacets.js @@ -78,9 +78,9 @@ export const INITIAL_STATE = { // sortBy: 'prefLabel', // sortDirection: 'asc', // sortButton: false, - // spatialFilterButton: true, + // spatialFilterButton: false, // isFetching: false, - // searchField: true, + // searchField: false, // containerClass: 'ten', // filterType: 'timespan', // startValue: null,