Skip to content

Commit

Permalink
TimeSeries Widget: Add a skeleton for loading state (#686)
Browse files Browse the repository at this point in the history
  • Loading branch information
vmilan authored May 26, 2023
1 parent 2b070c9 commit 4d673e4
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 8 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

## Not released

- TimeSeries Widget: Add a skeleton for loading state [#686](https://github.com/CartoDB/carto-react/pull/686)
- Pie & ComparativePie Widgets: Add a skeleton for loading state [#682](https://github.com/CartoDB/carto-react/pull/682)
- Range Widget: Add a skeleton for loading state [#681](https://github.com/CartoDB/carto-react/pull/681)
- Avoid reset of Table widget to page 0 when not necessary [#685](https://github.com/CartoDB/carto-react/pull/685)
- Fix widget calculation with very large viewports/masks [#680](https://github.com/CartoDB/carto-react/pull/680)
- Storybook: show figma codes/theme code snippets for colors [#684](https://github.com/CartoDB/carto-react/pull/684)
- Bar & Histogram & Formula & ComparativeFormula Widgets: Add a skeleton for loading state [#674](https://github.com/CartoDB/carto-react/pull/674)
- Category & ComparativeCategory Widgets: Add a skeleton for loading state [#679](https://github.com/CartoDB/carto-react/pull/679)
- Bar & Histogram & Formula & ComparativeFormula Widgets: Add a skeleton for loading state [#674](https://github.com/CartoDB/carto-react/pull/674)
- Improve Source types [#687](https://github.com/CartoDB/carto-react/pull/687)

## 2.0
Expand Down
16 changes: 16 additions & 0 deletions packages/react-ui/src/assets/images/GraphLine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { SvgIcon } from '@mui/material';

export default function GraphLine(props) {
return (
<SvgIcon width='720' height='124' viewBox='0 0 720 124' {...props}>
<path
d='M0.74707 123C11.8168 119.656 26.7934 118.37 53.4909 102.164C73.1959 90.2031 92.5604 81.3284 108.188 76.6983C122.841 72.357 136.188 74.3832 144.653 75.1549C150.496 75.6876 195.443 82.8718 207.164 83.6435C218.885 84.4152 241.676 87.502 274.234 80.5567C306.791 73.6115 305.869 75.4585 330.233 67.438C388.837 48.1456 433.461 2.6348 458.511 1.07229C495.627 -1.24279 512.557 52.7758 539.255 58.1776C565.952 63.5795 583.534 64.3512 601.766 55.0909C619.999 45.8305 625.859 40.4287 646.045 38.1136C666.231 35.7985 683.812 41.972 718.975 70.5247'
stroke='currentColor'
strokeWidth='2'
strokeLinejoin='round'
vectorEffect='non-scaling-stroke'
/>
</SvgIcon>
);
}
1 change: 1 addition & 0 deletions packages/react-ui/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export type TimeSeriesWidgetUI = {
timeWindow?: any[];
onTimeWindowUpdate?: Function;
showControls?: boolean;
isLoading?: boolean;
};

export type NoDataAlert = {
Expand Down
6 changes: 3 additions & 3 deletions packages/react-ui/src/widgets/SkeletonWidgets.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Skeleton, styled } from '@mui/material';
import { Box, Skeleton, styled } from '@mui/material';

export const SKELETON_HEIGHT = 240;

export const SkeletonBarsGrid = styled('div')(({ theme }) => ({
export const SkeletonBarsGrid = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'space-between',
Expand All @@ -24,7 +24,7 @@ export const SkeletonBarsGrid = styled('div')(({ theme }) => ({
}
}));

export const SkeletonGraphGrid = styled('div')(({ theme }) => ({
export const SkeletonGraphGrid = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'space-between',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { CHART_TYPES } from './utils/constants';
import PropTypes from 'prop-types';
import { GroupDateTypes, getMonday } from '@carto/react-core';
import Typography from '../../components/atoms/Typography';
import TimeSeriesSkeleton from './components/TimeSeriesSkeleton';

const FORMAT_DATE_BY_STEP_SIZE = {
[GroupDateTypes.YEARS]: yearCurrentDateRange,
Expand Down Expand Up @@ -65,8 +66,11 @@ function TimeSeriesWidgetUI({
onPlay,
isPaused,
onPause,
onStop
onStop,
isLoading
}) {
if (isLoading) return <TimeSeriesSkeleton height={height} />;

return (
<TimeSeriesProvider
isPlaying={isPlaying}
Expand Down Expand Up @@ -117,7 +121,8 @@ TimeSeriesWidgetUI.propTypes = {
onTimelineUpdate: PropTypes.func,
timeWindow: PropTypes.arrayOf(PropTypes.any),
onTimeWindowUpdate: PropTypes.func,
showControls: PropTypes.bool
showControls: PropTypes.bool,
isLoading: PropTypes.bool
};

TimeSeriesWidgetUI.defaultProps = {
Expand All @@ -131,7 +136,8 @@ TimeSeriesWidgetUI.defaultProps = {
isPaused: false,
timelinePosition: 0,
timeWindow: [],
showControls: true
showControls: true,
isLoading: false
};

export default TimeSeriesWidgetUI;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import { Box, Grid, styled } from '@mui/material';
import { Skeleton } from '@mui/material';
import { SKELETON_HEIGHT, SkeletonBarsGrid } from '../../SkeletonWidgets';
import { BREAKPOINTS } from '../../../theme/themeConstants';
import GraphLine from '../../../assets/images/GraphLine';

const Root = styled(Grid)(({ theme }) => ({
alignItems: 'stretch',
containerType: 'inline-size',

[`@container (max-width: ${BREAKPOINTS.XS}px)`]: {
' > div': {
marginRight: 0
}
}
}));

const Controls = styled(Grid)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
marginRight: theme.spacing(4)
}));

const Graph = styled(Grid)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
marginBottom: theme.spacing(2)
}));

const SkeletonGraphLine = styled(SkeletonBarsGrid)(({ theme }) => ({
svg: {
width: '100%',
height: 'auto',
minHeight: theme.spacing(20),
paddingTop: theme.spacing(4),
fontSize: 'initial',
fill: 'none',

path: {
stroke: theme.palette.black[8]
}
}
}));

const TimeSeriesSkeleton = ({ height }) => {
return (
<Root container height={height || SKELETON_HEIGHT}>
<Controls item>
<Grid item>
<Skeleton width={48} height={8} />
</Grid>

<Grid item>
{[...Array(3)].map((_, i) => (
<Box key={i} mt={2}>
<Skeleton width={24} height={24} />
</Box>
))}
</Grid>
</Controls>

<Graph item xs>
<SkeletonGraphLine height='80%'>
<GraphLine preserveAspectRatio='none' />
</SkeletonGraphLine>
</Graph>
</Root>
);
};

export default TimeSeriesSkeleton;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import TimeSeriesWidgetUI from '../../../src/widgets/TimeSeriesWidgetUI/TimeSeriesWidgetUI';
import { GroupDateTypes } from '@carto/react-core';
import { TIME_SERIES_CHART_TYPES } from '@carto/react-ui';
import { Label, ThinContainer } from '../../utils/storyStyles';

const data = [
{ name: 1514761200000, value: 310 },
Expand Down Expand Up @@ -154,6 +155,28 @@ const Template = (args) => {
return <TimeSeriesWidgetUI {...args} />;
};

const LoadingTemplate = (args) => {
if (args.timeWindow && !Array.isArray(args.timeWindow)) {
args.timeWindow = [];
}

return (
<>
<Label variant='body1' mb={3}>
{'Limited width'}
</Label>
<ThinContainer>
<TimeSeriesWidgetUI {...args} />
</ThinContainer>

<Label variant='body1' mt={8} mb={3}>
{'Responsive'}
</Label>
<TimeSeriesWidgetUI {...args} />
</>
);
};

const requiredProps = {
data,
stepSize: GroupDateTypes.WEEKS,
Expand All @@ -162,3 +185,6 @@ const requiredProps = {

export const Default = Template.bind({});
Default.args = requiredProps;

export const Loading = LoadingTemplate.bind({});
Loading.args = { ...requiredProps, isLoading: true };
2 changes: 1 addition & 1 deletion packages/react-widgets/src/widgets/TimeSeriesWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,10 @@ function TimeSeriesWidget({
isPaused={isPaused}
onPause={onPause}
onStop={handleStop}
// timelinePosition={timelinePosition}
onTimelineUpdate={handleTimelineUpdate}
timeWindow={timeWindow}
onTimeWindowUpdate={handleTimeWindowUpdate}
isLoading={isLoading}
/>
)}
</WidgetWithAlert>
Expand Down

0 comments on commit 4d673e4

Please sign in to comment.