Skip to content

Commit

Permalink
Merge pull request #2185 from zetkin/issue-2166/zui-progress-bar
Browse files Browse the repository at this point in the history
Issue 2166/zui bar diagram
  • Loading branch information
ziggabyte committed Sep 30, 2024
2 parents 2099cac + f916ca9 commit fd307c3
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
52 changes: 52 additions & 0 deletions src/zui/ZUIBarDiagram/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Meta, StoryObj } from '@storybook/react';

import ZUIBarDiagram from './index';

const meta: Meta<typeof ZUIBarDiagram> = {
component: ZUIBarDiagram,
};
export default meta;

type Story = StoryObj<typeof ZUIBarDiagram>;

export const Primary: Story = {
args: {
size: 'medium',
values: [25],
},
};

export const ThreeSegments: Story = {
args: {
size: 'medium',
values: [25, 25],
},
};

export const FourSegments: Story = {
args: {
size: 'medium',
values: [33, 33, 10],
},
};

export const ExtraSmall: Story = {
args: {
size: 'extraSmall',
values: [33, 33, 10],
},
};

export const Small: Story = {
args: {
size: 'small',
values: [33, 33, 10],
},
};

export const Large: Story = {
args: {
size: 'large',
values: [33, 33, 10],
},
};
70 changes: 70 additions & 0 deletions src/zui/ZUIBarDiagram/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Box } from '@mui/material';

type Sizes = 'extraSmall' | 'small' | 'medium' | 'large';

const sizes: Record<Sizes, number> = {
extraSmall: 5,
large: 30,
medium: 20,
small: 10,
};

const colors = ['#7800dc', '#9d46e6', '#c189ef', '#e4ccf8'];

interface ZUIBarDiagramProps {
/**
* Width of segments as an array of numbers whose total is < 100.
* The final segment width is the remainder.
*/
values: [number] | [number, number] | [number, number, number];
size: Sizes;
}

/**
* Renders a horizontal stacked bar. Define the percentage width of
* different segments, up to 100. The final segment width is the
* remainder of 100 minus the previous segment widths.
*/
const ZUIBarDiagram = ({ values, size }: ZUIBarDiagramProps) => {
const progressSum = values.reduce((sum, val) => {
return sum + val;
});

if (progressSum > 100) {
throw new Error('Progress > 100');
}
if (values.some((value) => value < 0)) {
throw new Error('Values can not be negative');
}

const height = sizes[size];

return (
<Box
borderRadius={height / 2}
display="flex"
gap={size === 'large' ? 0.75 : 0.5}
overflow="hidden"
width="100%"
>
{values.map((segmentWidth, index) => {
if (!segmentWidth) {
return null;
}
return (
<Box
key={index}
bgcolor={colors[index]}
height={height}
width={`${segmentWidth}%`}
/>
);
})}
{progressSum < 100 && (
<Box bgcolor={colors.at(-1)} flexGrow={1} height={height} />
)}
</Box>
);
};

export default ZUIBarDiagram;

0 comments on commit fd307c3

Please sign in to comment.