diff --git a/src/ui/theme/carto-theme.js b/src/ui/theme/carto-theme.js index bd784e203..82b95d31a 100644 --- a/src/ui/theme/carto-theme.js +++ b/src/ui/theme/carto-theme.js @@ -386,6 +386,7 @@ export const cartoThemeOptions = { overrides: { MuiCssBaseline: { '@global': { + // Custom scrollbars '*::-webkit-scrollbar': { position: 'fixed', width: '5px', @@ -400,11 +401,62 @@ export const cartoThemeOptions = { outline: 'none', }, + // iOS Search clear button + 'input[type="search"]::-webkit-search-cancel-button': { + '-webkit-appearance': 'none', + height: spacing(2), + width: spacing(2), + display: 'block', + backgroundImage: `url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAn0lEQVR42u3UMQrDMBBEUZ9WfQqDmm22EaTyjRMHAlM5K+Y7lb0wnUZPIKHlnutOa+25Z4D++MRBX98MD1V/trSppLKHqj9TTBWKcoUqffbUcbBBEhTjBOV4ja4l4OIAZThEOV6jHO8ARXD+gPPvKMABinGOrnu6gTNUawrcQKNCAQ7QeTxORzle3+sDfjJpPCqhJh7GixZq4rHcc9l5A9qZ+WeBhgEuAAAAAElFTkSuQmCC)`, + backgroundRepeat: 'no-repeat', + backgroundSize: spacing(2) + }, + // Mapbox controls '.mapboxgl-ctrl-bottom-left, .mapboxgl-ctrl-bottom-right': { '@media (max-width: 600px)': { // sm bottom: spacing(16) } + }, + '.mapboxgl-ctrl-attrib.mapboxgl-compact': { + maxWidth: '75%', + backgroundColor: 'transparent', + + '& .mapboxgl-ctrl-attrib-button': { + backgroundImage: `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20height='24'%20viewBox='0%200%2024%2024'%20width='24'%3E%3Cg%3E%3Crect%20fill='none'%20height='24'%20width='24'%20x='0'/%3E%3C/g%3E%3Cg%3E%3Cg%3E%3Cg%3E%3Cpath%20d='M11.88,9.14c1.28,0.06,1.61,1.15,1.63,1.66h1.79c-0.08-1.98-1.49-3.19-3.45-3.19C9.64,7.61,8,9,8,12.14%20c0,1.94,0.93,4.24,3.84,4.24c2.22,0,3.41-1.65,3.44-2.95h-1.79c-0.03,0.59-0.45,1.38-1.63,1.44C10.55,14.83,10,13.81,10,12.14%20C10,9.25,11.28,9.16,11.88,9.14z%20M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z%20M12,20c-4.41,0-8-3.59-8-8%20s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20z'%20fill='${variables.palette.text.secondary}'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + backgroundColor: 'rgba(255,255,255,.8)', + top: 'auto', + bottom: 0, + + '&:not(:disabled):hover': { + backgroundColor: 'rgba(255,255,255,.8)' + } + }, + + '& .mapboxgl-ctrl-attrib-inner': { + backgroundColor: 'rgba(255,255,255,.8)', + ...variables.typography.overline, + textTransform: 'none', + letterSpacing: '0.75px', + padding: spacing(.5, 1), + borderRadius: spacing(1.5), + color: variables.palette.text.secondary, + + '& a': { + color: variables.palette.primary.main + } + }, + + '&.mapboxgl-compact-show': { + '& .mapboxgl-ctrl-attrib-button': { + backgroundImage: `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20height='24'%20viewBox='0%200%2024%2024'%20width='24'%3E%3Cpath%20d='M0%200h24v24H0z'%20fill='none'/%3E%3Cpath%20d='M19%206.41L17.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z'%20fill='white'/%3E%3C/svg%3E")`, + backgroundColor: variables.palette.common.black, + + '&:not(:disabled):hover': { + backgroundColor: variables.palette.common.black + } + } + } } }, }, diff --git a/src/ui/utils/detectTouchScreen.js b/src/ui/utils/detectTouchScreen.js new file mode 100644 index 000000000..84549000a --- /dev/null +++ b/src/ui/utils/detectTouchScreen.js @@ -0,0 +1,20 @@ +// https://patrickhlauke.github.io/touch/touchscreen-detection/ +export default function detectTouchscreen() { + var result = false; + if (window.PointerEvent && ('maxTouchPoints' in navigator)) { + // if Pointer Events are supported, just check maxTouchPoints + if (navigator.maxTouchPoints > 0) { + result = true; + } + } else { + // no Pointer Events... + if (window.matchMedia && window.matchMedia("(any-pointer:coarse)").matches) { + // check for any-pointer:coarse which mostly means touchscreen + result = true; + } else if (window.TouchEvent || ('ontouchstart' in window)) { + // last resort - check for exposed touch events API / event handler + result = true; + } + } + return result; +} \ No newline at end of file diff --git a/src/ui/widgets/HistogramWidgetUI.js b/src/ui/widgets/HistogramWidgetUI.js index 60ee21e25..f11401f25 100644 --- a/src/ui/widgets/HistogramWidgetUI.js +++ b/src/ui/widgets/HistogramWidgetUI.js @@ -2,6 +2,9 @@ import React, { useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; import ReactEcharts from 'echarts-for-react'; import { Grid, Link, Typography, useTheme, makeStyles } from '@material-ui/core'; +import detectTouchScreen from '../utils/detectTouchScreen'; + +const IS_TOUCH_SCREEN = detectTouchScreen(); const useStyles = makeStyles((theme) => ({ optionsSelectedBar: { @@ -34,7 +37,7 @@ function __dataEqual(optionPrev, optionNext) { } function __generateDefaultConfig( - { dataAxis, tooltipFormatter, xAxisFormatter = (v) => v, yAxisFormatter = (v) => v }, + { dataAxis, tooltip, tooltipFormatter, xAxisFormatter = (v) => v, yAxisFormatter = (v) => v }, data, theme ) { @@ -51,6 +54,7 @@ function __generateDefaultConfig( }, }, tooltip: { + show: tooltip, trigger: 'axis', padding: [theme.spacing(0.5), theme.spacing(1)], textStyle: { @@ -155,11 +159,11 @@ function __generateSerie(name, data, selectedBars = [], theme) { }), barCategoryGap: 1, barMinWidth: '95%', - ...(theme + ...(!IS_TOUCH_SCREEN && theme ? { emphasis: { itemStyle: { - color: '#31996b', // FIXME: This color don't appears in carto-theme. Secondary dark is red instead of green. It is correct? + color: theme.palette.secondary.dark, }, }, } @@ -170,7 +174,9 @@ function __generateSerie(name, data, selectedBars = [], theme) { function __disableBar(bar, theme) { bar.disabled = true; - bar.itemStyle = { color: theme.palette.charts.disabled }; + bar.itemStyle = { + color: theme.palette.charts.disabled + }; } function __clearFilter(serie) { @@ -221,6 +227,7 @@ function HistogramWidgetUI(props) { dataAxis, onSelectedBarsChange, selectedBars, + tooltip, tooltipFormatter, xAxisFormatter, yAxisFormatter, @@ -231,7 +238,7 @@ function HistogramWidgetUI(props) { const chartInstance = useRef(); const options = useMemo(() => { const config = __generateDefaultConfig( - { dataAxis, tooltipFormatter, xAxisFormatter, yAxisFormatter }, + { dataAxis, tooltip, tooltipFormatter, xAxisFormatter, yAxisFormatter }, data, theme ); @@ -318,6 +325,7 @@ function HistogramWidgetUI(props) { } HistogramWidgetUI.defaultProps = { + tooltip: true, tooltipFormatter: (v) => v, xAxisFormatter: (v) => v, yAxisFormatter: (v) => v, @@ -328,6 +336,7 @@ HistogramWidgetUI.defaultProps = { HistogramWidgetUI.propTypes = { data: PropTypes.arrayOf(PropTypes.number).isRequired, + tooltip: PropTypes.bool, tooltipFormatter: PropTypes.func, xAxisFormatter: PropTypes.func, yAxisFormatter: PropTypes.func, diff --git a/src/widgets/GeocoderWidget.js b/src/widgets/GeocoderWidget.js index 9e428f230..da9e6c5d8 100644 --- a/src/widgets/GeocoderWidget.js +++ b/src/widgets/GeocoderWidget.js @@ -37,7 +37,7 @@ const useStyles = makeStyles((theme) => ({ }, input: { ...theme.typography.body2, - width: 'calc(100% - 64px)', + width: `calc(100% - ${theme.spacing(5)}px)`, marginLeft: theme.spacing(1) }, })); diff --git a/src/widgets/HistogramWidget.js b/src/widgets/HistogramWidget.js index 807c699ac..cc82485ac 100644 --- a/src/widgets/HistogramWidget.js +++ b/src/widgets/HistogramWidget.js @@ -28,7 +28,7 @@ function HistogramWidget(props) { const dispatch = useDispatch(); const viewport = useSelector((state) => props.viewportFilter && state.carto.viewport); const source = useSelector((state) => selectSourceById(state, props.dataSource) || {}); - const { title, formatter, xAxisFormatter, dataAxis, ticks } = props; + const { title, formatter, xAxisFormatter, dataAxis, ticks, tooltip } = props; const { data, credentials } = source; const tooltipFormatter = ([serie]) => { @@ -106,6 +106,7 @@ function HistogramWidget(props) { dataAxis={dataAxis || [...ticks, `> ${ticks[ticks.length - 1]}`]} selectedBars={selectedBars} onSelectedBarsChange={handleSelectedBarsChange} + tooltip={tooltip} tooltipFormatter={tooltipFormatter} xAxisFormatter={xAxisFormatter} yAxisFormatter={formatter} @@ -122,12 +123,14 @@ HistogramWidget.propTypes = { operation: PropTypes.oneOf(Object.values(AggregationTypes)).isRequired, xAxisFormatter: PropTypes.func, formatter: PropTypes.func, + tooltip: PropTypes.bool, ticks: PropTypes.array.isRequired, viewportFilter: PropTypes.bool, onError: PropTypes.func }; HistogramWidget.defaultProps = { + tooltip: true, viewportFilter: false };