Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

feat: Move all legend's to vertical designs #4550

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 14 additions & 104 deletions packages/app/src/components/choropleth-legenda.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import { ChoroplethThresholdsValue, colors } from '@corona-dashboard/common';
import { css, SystemStyleObject } from '@styled-system/css';
import styled from 'styled-components';
import { ValueAnnotation } from '~/components/value-annotation';
import { useIntl } from '~/intl';
import { space, fontSizes } from '~/style/theme';
import { replaceVariablesInText } from '~/utils';
import { useBreakpoints } from '~/utils/use-breakpoints';
import { useResizeObserver } from '~/utils/use-resize-observer';
import { Box } from './base';
import { Legend, LegendItem } from './legend';
import { InlineText, Text } from './typography';
import { Text } from './typography';

interface ChoroplethLegendaProps {
title: string;
thresholds: ChoroplethThresholdsValue[];
valueAnnotation?: string;
type?: 'default' | 'bar';
pageType?: string;
outdatedDataLabel?: string;
}

export function ChoroplethLegenda({ title, thresholds, valueAnnotation, type = 'bar', pageType, outdatedDataLabel }: ChoroplethLegendaProps) {
const [itemRef, itemSize] = useResizeObserver<HTMLLIElement>();
const [endLabelRef, endLabelSize] = useResizeObserver<HTMLSpanElement>();
const { commonTexts, formatNumber } = useIntl();
export function ChoroplethLegenda({ title, thresholds, valueAnnotation, pageType, outdatedDataLabel }: ChoroplethLegendaProps) {
const { commonTexts } = useIntl();
const breakpoints = useBreakpoints(true);

const legendItems = thresholds.map(
(x: ChoroplethThresholdsValue, i) =>
({
Expand All @@ -41,105 +35,21 @@ export function ChoroplethLegenda({ title, thresholds, valueAnnotation, type = '
} as LegendItem)
);

if (pageType === 'sewer') {
legendItems.push({
label: outdatedDataLabel,
shape: 'square',
color: colors.yellow1,
} as LegendItem);
}

return (
<Box width="100%" paddingRight={`${endLabelSize.width ?? 0 / 2}px`} spacing={2} aria-hidden="true">
<Box width="100%" spacing={2} aria-hidden="true">
{title && <Text variant="subtitle1">{title}</Text>}

{pageType === 'sewer' && (
<Box display="flex" alignItems="center" paddingBottom={space[2]}>
<LegendaColor first={true} width={`${100 / thresholds.length}%`} color={colors.yellow1} />
<Box paddingLeft={space[3]} fontSize={fontSizes[1]}>
<InlineText>{outdatedDataLabel}</InlineText>
</Box>
</Box>
)}

{'bar' === type ? (
Jorrik-Klijnsma-Work marked this conversation as resolved.
Show resolved Hide resolved
<List>
{thresholds.map(({ color, threshold, label, endLabel }, index) => {
const isFirst = index === 0;
const isLast = index === thresholds.length - 1;
const displayLabel = (itemSize.width ?? 0) > 35 || index % 2 === 0;
const formattedTreshold = formatNumber(threshold);
<Legend items={legendItems} columns={breakpoints.lg ? 1 : 2} />

return (
<Item key={color + threshold} ref={index === 0 ? itemRef : undefined} width={`${100 / thresholds.length}%`}>
<LegendaColor color={color} first={isFirst} last={isLast} />
{isFirst ? <StartLabel>{label ?? formattedTreshold}</StartLabel> : displayLabel && <Label>{label ?? formattedTreshold}</Label>}

{isLast && endLabel && <EndLabel ref={endLabelRef}>{endLabel}</EndLabel>}
</Item>
);
})}
</List>
) : (
<Legend items={legendItems} columns={breakpoints.md ? 1 : 2} />
)}
<ValueAnnotation>{valueAnnotation}</ValueAnnotation>
</Box>
);
}

const List = styled.ul(
css({
width: '100%',
marginTop: 0,
paddingLeft: 0,
listStyle: 'none',
display: 'flex',
})
);

// Assigning a flex-basis based on number of items in threshold so that legend items outside of the threshold array can be displayed using the same measurement.
const Item = styled.li<{
width: string;
}>(({ width }) =>
css({
flex: 1,
flexBasis: width,
position: 'relative',
})
);

const LegendaColor = styled.div<{
first?: boolean;
last?: boolean;
width?: string;
color: string;
}>((x) =>
css({
width: '100%',
height: '10px',
flexGrow: 0,
flexShrink: 0,
flexBasis: x.width,
borderRadius: x.first ? '2px 0 0 2px' : x.last ? '0 2px 2px 0' : 0,
backgroundColor: x.color,
})
);

const labelStyles: SystemStyleObject = {
pt: 1,
display: 'inline-block',
transform: 'translateX(-50%)',
fontSize: [0, null, 1],
};

const Label = styled.span(css(labelStyles));

const StartLabel = styled.span(
css({
...labelStyles,
transform: 'translateX(0)',
})
);

const EndLabel = styled.span(
css({
...labelStyles,
position: 'absolute',
top: [12, null, 10],
right: 0,
transform: 'translateX(50%)',
})
);
21 changes: 7 additions & 14 deletions packages/app/src/components/choropleth-tile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ChoroplethThresholdsValue } from '@corona-dashboard/common';
import { space } from '~/style/theme';
import { ChoroplethLegenda } from '~/components/choropleth-legenda';
import { DataProps } from '~/types/attributes';
import { useBreakpoints } from '~/utils/use-breakpoints';
Expand All @@ -16,7 +17,6 @@ type ChoroplethTileProps = DataProps & {
legend?: {
title: string;
thresholds: ChoroplethThresholdsValue[];
type?: 'default' | 'bar';
outdatedDataLabel?: string;
};
metadata?: MetadataProps;
Expand Down Expand Up @@ -50,45 +50,38 @@ export function ChoroplethTile({
const breakpoints = useBreakpoints(true);
const legendaComponent = legend && (
<Box maxWidth={300} width="100%">
<ChoroplethLegenda
thresholds={legend.thresholds}
title={legend.title}
valueAnnotation={valueAnnotation}
type={legend.type}
pageType={pageType}
outdatedDataLabel={legend.outdatedDataLabel}
/>
<ChoroplethLegenda thresholds={legend.thresholds} title={legend.title} valueAnnotation={valueAnnotation} pageType={pageType} outdatedDataLabel={legend.outdatedDataLabel} />
</Box>
);

return (
<FullscreenChartTile metadata={metadata}>
<Box display="flex" flexDirection={{ _: 'column', lg: 'row' }} m={0} as="figure" {...dataProps} height="100%" spacing={3}>
<Box display="flex" flexDirection={{ _: 'column', lg: 'row' }} margin={space[0]} as="figure" {...dataProps} height="100%" spacing={3}>
<Box flex={{ lg: 1 }} as="figcaption" spacing={3}>
<Heading level={3}>{title}</Heading>

{typeof description === 'string' ? <Text>{description}</Text> : description}

{onChartRegionChange && chartRegion && (
<Box display="flex" justifyContent={{ _: 'center', lg: 'flex-start' }} pt={4}>
<Box display="flex" justifyContent="flex-start" paddingTop={space[4]}>
<ChartRegionControls value={chartRegion} onChange={onChartRegionChange} />
</Box>
)}

{legendaComponent && breakpoints.lg && (
<Box display="flex" flexDirection="row" alignItems="flex-center">
<Box display="flex" flexDirection="row" alignItems="flex-start">
{legendaComponent}
</Box>
)}
</Box>

<Box flex={{ lg: 1 }} display="flex" flexDirection="column" height="100%" spacing={3}>
<Box height="100%" mt={4} pl={hasPadding && breakpoints.lg ? 4 : undefined}>
<Box height="100%" marginTop={space[4]} pl={hasPadding && breakpoints.lg ? 4 : undefined}>
<ErrorBoundary>{children}</ErrorBoundary>
</Box>

{legendaComponent && !breakpoints.lg && (
<Box display="flex" justifyContent="center">
<Box display="flex" justifyContent="flex-start">
{legendaComponent}
</Box>
)}
Expand Down
Loading