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

Feature/cor 1268 modified legends #4592

Merged
merged 5 commits into from
Jan 12, 2023
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
103 changes: 55 additions & 48 deletions packages/app/src/components/interactive-legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import styled from 'styled-components';
import { isDefined } from 'ts-is-present';
import { BoldText } from '~/components/typography';
import { useIntl } from '~/intl';
import { space } from '~/style/theme';
import { Box } from './base';

export interface SelectOption<T = string> {
metricProperty: T;
label: string;
color: string;
shape?: 'line' | 'circle' | 'square' | 'gapped-area';
shape?: 'line' | 'circle' | 'square' | 'gapped-area' | 'dashed';
legendAriaLabel?: string;
}

Expand All @@ -22,13 +23,7 @@ interface InteractiveLegendProps<T = string> {
onReset?: () => void;
}

export function InteractiveLegend<T = string>({
helpText,
selectOptions,
selection,
onToggleItem,
onReset,
}: InteractiveLegendProps<T>) {
export function InteractiveLegend<T = string>({ helpText, selectOptions, selection, onToggleItem, onReset }: InteractiveLegendProps<T>) {
const { commonTexts } = useIntl();

const hasSelection = selection.length !== 0;
Expand All @@ -42,19 +37,17 @@ export function InteractiveLegend<T = string>({
const isSelected = selection.includes(item.metricProperty);
return (
<Item key={item.label}>
<StyledLabel
htmlFor={`checkboxgroup-${item.label}`}
isActive={hasSelection && isSelected}
borderColor={item.color}
data-text={item.label}
>
<StyledLabel htmlFor={`checkboxgroup-${item.label}`} isActive={hasSelection && isSelected} borderColor={item.color} data-text={item.label}>
{item.label}
{item.shape === 'line' && <Line color={item.color} />}
{item.shape === 'dashed' && (
<DashedContainer>
<Dashed color={item.color} />
</DashedContainer>
)}
{item.shape === 'circle' && <Circle color={item.color} />}
{item.shape === 'square' && <Square color={item.color} />}
{item.shape === 'gapped-area' && (
<GappedArea color={item.color} />
)}
{item.shape === 'gapped-area' && <GappedArea color={item.color} />}
</StyledLabel>
<StyledInput
type="checkbox"
Expand Down Expand Up @@ -89,16 +82,16 @@ const Legend = styled.div(
const List = styled.ul(
css({
listStyle: 'none',
px: 0,
m: 0,
mt: 2,
paddingX: 0,
margin: 0,
marginTop: space[2],
})
);

const Item = styled.li(
css({
mb: 2,
mr: 2,
marginBottom: space[2],
marginRight: space[2],
position: 'relative',
display: 'inline-block',
})
Expand All @@ -120,13 +113,11 @@ const StyledLabel = styled.label<{
cursor: 'pointer',
position: 'relative',
display: 'inline-flex',
pr: 13,
pl: 33,
py: 1,
paddingRight: '13px',
paddingLeft: '33px',
paddingY: space[1],
borderRadius: '5px',
boxShadow: `inset 0px 0px 0px ${
isActive ? `3px ${borderColor}` : `1px ${colors.gray4}`
}`,
boxShadow: `inset 0px 0px 0px ${isActive ? `3px ${borderColor}` : `1px ${colors.gray4}`}`,
fontWeight: 'normal',
fontFamily: 'inherit',
fontSize: 1,
Expand Down Expand Up @@ -189,7 +180,7 @@ const ResetButton = styled.button<{ isVisible: boolean }>(({ isVisible }) =>
backgroundColor: 'transparent',
cursor: 'pointer',
color: 'blue8',
py: '6px',
paddingY: '6px',
border: 'none',
fontFamily: 'inherit',
visibility: isVisible ? 'visible' : 'hidden',
Expand All @@ -200,26 +191,49 @@ const ResetButton = styled.button<{ isVisible: boolean }>(({ isVisible }) =>
})
);

const Line = styled.div<{ color: string }>(({ color }) =>
const DashedContainer = styled(Box)`
svg {
display: block;
left: 13px;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
`;

interface DashedProps {
color: string;
}

export const Dashed = ({ color }: DashedProps) => {
return (
<svg width={15} height={15} viewBox={`0 0 ${15} ${15}`}>
<line stroke={color} strokeWidth={3} strokeDasharray={4} strokeLinecap="round" strokeLinejoin="round" x1={2} y1={15 / 2} x2={15 - 2} y2={15 / 2} />
</svg>
DariaKwork marked this conversation as resolved.
Show resolved Hide resolved
);
};

const Shape = styled.div<{ color: string }>((x) =>
css({
display: 'block',
position: 'absolute',
left: 13,
backgroundColor: x.color,
})
);

const Line = styled(Shape)(
css({
top: '50%',
transform: 'translateY(-50%)',
width: '15px',
height: '3px',
borderRadius: '2px',
display: 'block',
position: 'absolute',
left: 13,
backgroundColor: color,
})
);

const Circle = styled.div<{ color: string }>(({ color }) =>
const Circle = styled(Shape)(
css({
display: 'block',
position: 'absolute',
left: 13,
backgroundColor: color,
top: '50%',
transform: 'translateY(-50%)',
width: '10px',
Expand All @@ -228,12 +242,8 @@ const Circle = styled.div<{ color: string }>(({ color }) =>
})
);

const Square = styled.div<{ color: string }>(({ color }) =>
const Square = styled(Shape)(
css({
display: 'block',
position: 'absolute',
left: 13,
backgroundColor: color,
top: '50%',
transform: 'translateY(-50%)',
width: '11px',
Expand All @@ -242,11 +252,8 @@ const Square = styled.div<{ color: string }>(({ color }) =>
})
);

const GappedArea = styled.div<{ color: string }>(({ color }) =>
const GappedArea = styled(Shape)<{ color: string }>(({ color }) =>
css({
display: 'block',
position: 'absolute',
left: 13,
backgroundColor: `${color}30`,
borderTop: `2px solid ${color}`,
top: '50%',
Expand Down
79 changes: 24 additions & 55 deletions packages/app/src/components/legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import { colors } from '@corona-dashboard/common';
import css, { SystemStyleObject } from '@styled-system/css';
import { ReactNode } from 'react';
import styled from 'styled-components';
import { space } from '~/style/theme';

type LegendShape =
| 'line'
| 'square'
| 'circle'
| 'dotted-square'
| 'outlined-square';
type LegendShape = 'line' | 'square' | 'circle' | 'dotted-square' | 'outlined-square';
type LegendLineStyle = 'solid' | 'dashed';

export type LegendItem = {
Expand Down Expand Up @@ -44,15 +40,9 @@ export function Legend({ items, columns }: LegendProps) {
<Item key={i}>
{item.label}
{item.shape === 'square' && <Square color={item.color} />}
{item.shape === 'outlined-square' && (
<OutlinedSquare color={item.color} />
)}
{item.shape === 'dotted-square' && (
<DottedSquare color={item.color} />
)}
{item.shape === 'line' && (
<Line color={item.color} lineStyle={item.style ?? 'solid'} />
)}
{item.shape === 'outlined-square' && <OutlinedSquare color={item.color} />}
{item.shape === 'dotted-square' && <DottedSquare color={item.color} />}
{item.shape === 'line' && <Line color={item.color} lineStyle={item.style ?? 'solid'} />}
{item.shape === 'circle' && <Circle color={item.color} />}
</Item>
);
Expand All @@ -64,8 +54,8 @@ export function Legend({ items, columns }: LegendProps) {
const List = styled.ul<{ columns?: number }>(({ columns }) =>
css({
listStyle: 'none',
px: 0,
m: 0,
paddingX: 0,
margin: 0,
fontSize: 1,
color: 'gray7',
columns,
Expand All @@ -75,11 +65,11 @@ const List = styled.ul<{ columns?: number }>(({ columns }) =>

const Item = styled.li(
css({
my: 1,
mr: 3,
marginY: space[1],
marginRight: space[3],
position: 'relative',
display: 'inline-block',
pl: '25px', // alignment with shape
paddingLeft: '25px', // alignment with shape
})
);

Expand Down Expand Up @@ -109,31 +99,14 @@ const Shape = styled.div<{ color: string }>((x) =>
function DottedSquare({ color }: { color: string }) {
return (
<Shape color="white" css={css({ top: '3px' })}>
<svg width={16} height={16} viewBox={`0 0 ${16} ${16}`}>
<svg width={'16px'} height={'16px'} viewBox={`0 0 ${16} ${16}`}>
<defs>
<pattern
id="dotted_legend"
width="4"
height="4"
patternUnits="userSpaceOnUse"
>
<line
x1="0"
y1="4"
x2="0"
y2="0"
style={{ stroke: color, strokeWidth: 4, strokeDasharray: 2 }}
/>
<pattern id="dotted_legend" width="4" height="4" patternUnits="userSpaceOnUse">
<line x1="0" y1="4" x2="0" y2="0" style={{ stroke: color, strokeWidth: 4, strokeDasharray: 2 }} />
</pattern>
</defs>
<g>
<rect
x={0}
y={0}
fill={`url(#dotted_legend)`}
width={16}
height={16}
/>
<rect x={0} y={0} fill={`url(#dotted_legend)`} width={'16px'} height={'16px'} />
</g>
</svg>
</Shape>
Expand Down Expand Up @@ -170,18 +143,14 @@ const Circle = styled(Shape)(
})
);

const Line = styled.div<{ color: string; lineStyle: LegendLineStyle }>(
({ color, lineStyle }) =>
css({
display: 'block',
position: 'absolute',
borderTopColor: color as SystemStyleObject,
borderTopStyle: lineStyle,
borderTopWidth: '3px',
top: '10px',
width: '15px',
height: 0,
borderRadius: '2px',
left: 0,
})
const Line = styled(Shape)<{ color: string; lineStyle: LegendLineStyle }>(({ color, lineStyle }) =>
css({
borderTopColor: color as SystemStyleObject,
borderTopStyle: lineStyle,
borderTopWidth: '3px',
top: '10px',
width: '15px',
height: '0',
borderRadius: '2px',
})
);
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function useLegendItems<T extends TimestampedValue>(
const legendItems = config
.filter(isVisible)
.filter((configItem) => !configItem?.hideInLegend)

.map<LegendItem | undefined>((x) => {
switch (x.type) {
case 'split-area':
Expand Down Expand Up @@ -111,7 +112,6 @@ export function useLegendItems<T extends TimestampedValue>(
* legend when there's at least two items.
*/
const isLegendRequired = forceLegend || legendItems.length + splitLegendGroups.length > 1;

return {
legendItems: isLegendRequired ? legendItems : undefined,
splitLegendGroups: splitLegendGroups.length > 0 ? splitLegendGroups : undefined,
Expand Down
Loading