Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various ZUI chips 🥔 #2408

Open
wants to merge 14 commits into
base: undocumented/new-design-system
Choose a base branch
from
Open
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
5 changes: 3 additions & 2 deletions src/utils/types/zetkin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,11 @@ export interface ZetkinTag {
organization: Pick<ZetkinOrganization, 'id' | 'title'>;
color: string | null;
group: ZetkinTagGroup | null;
value?: string | number | null;
value_type: string | null;
value_type: 'text' | null;
}

export type ZetkinAppliedTag = ZetkinTag & { value?: string | number | null };

export interface ZetkinTagPostBody
extends Partial<Omit<ZetkinTag, 'id' | 'group' | 'organization'>> {
title: string;
Expand Down
100 changes: 100 additions & 0 deletions src/zui/components/ZUIDataChip/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Meta, StoryObj } from '@storybook/react';
import { Box, Paper, Typography } from '@mui/material';

import ZUIDataChip from './index';
import ZUIDivider from '../ZUIDivider';
import ZUIText from '../ZUIText';

const meta: Meta<typeof ZUIDataChip> = {
component: ZUIDataChip,
title: 'Components/ZUIDataChip',
};
export default meta;

type Story = StoryObj<typeof ZUIDataChip>;

export const Basic: Story = {
args: {
color: 'grey',
value: 394,
},
};

export const TwoChips: Story = {
args: {},
decorators: () => {
return (
<Box display="flex" gap={2}>
<Paper sx={{ padding: 2 }}>
<Box alignItems="center" display="flex" gap={2}>
<ZUIDataChip color="main" value={1240} />
<Typography variant="headingMd">Something</Typography>
</Box>
</Paper>
<Paper sx={{ padding: 2 }}>
<Box alignItems="center" display="flex" gap={2}>
<ZUIDataChip color="final" value={343} />
<Typography variant="headingMd">Other thing</Typography>
</Box>
</Paper>
</Box>
);
},
};

export const ThreeChips: Story = {
args: {},
decorators: () => {
return (
<Box display="flex" gap={2}>
<Box alignItems="center" display="flex" gap={1}>
<ZUIText color="secondary" variant="headingSm">
First value
</ZUIText>
<ZUIDivider flexItem orientation="vertical" />
<ZUIDataChip color="main" value={1240} />
</Box>
<Box alignItems="center" display="flex" gap={1}>
<ZUIText color="secondary" variant="headingSm">
Second value
</ZUIText>
<ZUIDivider flexItem orientation="vertical" />
<ZUIDataChip color="mid2" value={387} />
</Box>
<Box alignItems="center" display="flex" gap={1}>
<ZUIText color="secondary" variant="headingSm">
Third value
</ZUIText>
<ZUIDivider flexItem orientation="vertical" />
<ZUIDataChip color="final" value={343} />
</Box>
</Box>
);
},
};

export const FourChips: Story = {
args: {},
decorators: () => {
return (
<Box display="flex" flexDirection="column" gap={2} width="300px">
<Box alignItems="center" display="flex" gap={1}>
<ZUIDataChip color="main" value={1240} />
<ZUIText>First</ZUIText>
</Box>
<Box alignItems="center" display="flex" gap={1}>
<ZUIDataChip color="mid3" value={231} />
<ZUIText>Second</ZUIText>
</Box>
<Box alignItems="center" display="flex" gap={1}>
<ZUIDataChip color="mid1" value={34} />
<ZUIText>Third</ZUIText>
</Box>
<Box alignItems="center" display="flex" gap={1}>
<ZUIDataChip color="final" value={343} />
<ZUIText>Fourth</ZUIText>
</Box>
</Box>
);
},
};
54 changes: 54 additions & 0 deletions src/zui/components/ZUIDataChip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Box, Typography, useTheme } from '@mui/material';
import { FC } from 'react';

type ZUIDataChipProps = {
/**
* Sets the color of the chip. Defaults to 'grey'.
*
* Note!
* There are 5 purple colors available. They should be used in combos of
* 2, 3 or 4 shades, like this:
*
* - When using 2 purple chips the correct color order is: main, final
* - When using 3 purple chips the correct color order is: main, mid2, final
* - When using 4 purple chips the correct color order is: main, mid3, mid1, final
*/
color?: 'grey' | 'main' | 'mid1' | 'mid2' | 'mid3' | 'final';

/**
* The number value to be displayed in the chip.
*/
value: number;
};

const ZUIDataChip: FC<ZUIDataChipProps> = ({ color = 'grey', value }) => {
const theme = useTheme();

return (
<Box
bgcolor={
color == 'grey' ? theme.palette.grey[100] : theme.palette.data[color]
}
display="inline-flex"
sx={{
borderRadius: '2rem',
overflow: 'hidden',
padding: '0.25rem 0.75rem',
}}
>
<Typography
sx={{
color:
color == 'grey' || color == 'final'
? theme.palette.common.black
: theme.palette.common.white,
}}
variant="headingMd"
>
{value}
</Typography>
</Box>
);
};

export default ZUIDataChip;
50 changes: 50 additions & 0 deletions src/zui/components/ZUIProgressChip/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Meta, StoryObj } from '@storybook/react';

import ZUIProgressChip from './index';

const meta: Meta<typeof ZUIProgressChip> = {
component: ZUIProgressChip,
title: 'Components/ZUIProgressChip',
};
export default meta;

type Story = StoryObj<typeof ZUIProgressChip>;

export const TwoSmall: Story = {
args: {
values: [243, 2934],
},
};

export const ThreeSmall: Story = {
args: {
values: [243, 2934, 3948],
},
};

export const FourSmall: Story = {
args: {
values: [1, 2934, 34, 349],
},
};

export const TwoMedium: Story = {
args: {
size: 'medium',
values: [243, 2934],
},
};

export const ThreeMedium: Story = {
args: {
size: 'medium',
values: [243, 2934, 3948],
},
};

export const FourMedium: Story = {
args: {
size: 'medium',
values: [1, 2934, 34, 349],
},
};
63 changes: 63 additions & 0 deletions src/zui/components/ZUIProgressChip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Box, Typography, useTheme } from '@mui/material';
import { FC } from 'react';

import { ZUIMedium, ZUISmall } from '../types';

type ZUIProgressChipProps = {
/**
* The size of the component. Defaults to 'small'.
*/
size?: ZUISmall | ZUIMedium;

/**
* Values to be displayed in each of the sections of the chip.
* An array of 2, 3 or 4 numbers.
*/
values:
| [number, number]
| [number, number, number]
| [number, number, number, number];
Comment on lines +12 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice solution!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stolen from logic by @river-bbc :D

};

const ZUIProgressChip: FC<ZUIProgressChipProps> = ({
size = 'small',
values,
}) => {
const theme = useTheme();

const colors = [theme.palette.data.main, theme.palette.data.final];

//Add middle colors to the colors array
if (values.length == 3) {
colors.splice(1, 0, theme.palette.data.mid2);
} else if (values.length == 4) {
colors.splice(1, 0, theme.palette.data.mid3, theme.palette.data.mid1);
}

return (
<Box display="inline-flex" sx={{ borderRadius: '2em', overflow: 'hidden' }}>
{values.map((value, index) => (
<Box
key={`${value}-${index}`}
bgcolor={colors[index]}
color={
index == values.length - 1
? theme.palette.common.black
: theme.palette.common.white
}
sx={{
borderLeft:
index > 0 ? `0.063rem solid ${theme.palette.common.white}` : '',
paddingLeft: index == 0 ? '0.625rem' : '0.375rem',
paddingRight: index == values.length - 1 ? '0.625rem' : '0.375rem',
paddingY: size == 'small' ? '0.188rem' : '0.438rem',
}}
>
<Typography variant="labelSmMedium">{value}</Typography>
</Box>
))}
</Box>
);
};

export default ZUIProgressChip;
18 changes: 18 additions & 0 deletions src/zui/components/ZUITagChip/getTagContrastColor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getContrastColor } from 'utils/colorUtils';
import { funSwatches } from 'zui/theme/palette';

export default function getTagContrastColor(color: string) {
let contrastColor = '';

Object.values(funSwatches).forEach((funSwatch) => {
if (color == funSwatch.dark.color) {
contrastColor = funSwatch.dark.contrast;
} else if (color == funSwatch.medium.color) {
contrastColor = funSwatch.medium.contrast;
} else if (color == funSwatch.light.color) {
contrastColor == funSwatch.light.contrast;
}
});

return contrastColor || getContrastColor(color);
}
85 changes: 85 additions & 0 deletions src/zui/components/ZUITagChip/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Meta, StoryObj } from '@storybook/react';

import ZUITagChip from './index';

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

type Story = StoryObj<typeof ZUITagChip>;

export const Basic: Story = {
args: {
tag: {
color: null,
description: 'People who organize',
group: null,
hidden: false,
id: 1,
organization: {
id: 1,
title: 'My Organization',
},
title: 'Organizer',
value_type: null,
},
},
};

export const ValueTag: Story = {
args: {
tag: {
color: '#187F81',
description: 'The amount this person gets paid',
group: null,
hidden: false,
id: 1,
organization: {
id: 1,
title: 'My Organization',
},
title: 'Salary',
value: '23000',
value_type: 'text',
},
},
};

export const BasicWithAction: Story = {
args: {
...Basic.args,
onClick: () => null,
},
render: Basic.render,
};

export const ValueTagWithAction: Story = {
args: {
...ValueTag.args,
onClick: () => null,
},
};

export const DeletableBasic: Story = {
args: {
...Basic.args,
onDelete: () => null,
},
};

export const DeletableValueTag: Story = {
args: {
...ValueTag.args,
onDelete: () => null,
},
};

export const Disabled: Story = {
args: {
...Basic.args,
disabled: true,
onClick: () => null,
onDelete: () => null,
},
};
Loading
Loading