refactor: move Checkmark, Avatar, Chip and Tooltip to twenty-ui (#4946)

Split from https://github.com/twentyhq/twenty/pull/4518

Part of #4766
This commit is contained in:
Thaïs
2024-04-15 12:05:06 +02:00
committed by GitHub
parent acc2092b95
commit b6d0b8a895
93 changed files with 225 additions and 189 deletions

View File

@ -0,0 +1,160 @@
import { ComponentProps, JSX } from 'react';
import styled from '@emotion/styled';
import { isNumber, isString } from '@sniptt/guards';
import { Decorator } from '@storybook/react';
const StyledColumnTitle = styled.h1`
font-size: ${({ theme }) => theme.font.size.lg};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowsTitle = styled.h2`
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
width: 100px;
`;
const StyledRowTitle = styled.h3`
color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
width: 100px;
`;
const StyledElementTitle = styled.span`
color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-bottom: ${({ theme }) => theme.spacing(1)};
text-align: center;
text-transform: uppercase;
`;
const StyledContainer = styled.div`
display: flex;
flex-direction: row;
`;
const StyledColumnContainer = styled.div`
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowContainer = styled.div`
display: flex;
flex: 1;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledElementContainer = styled.div<{ width: number }>`
display: flex;
${({ width }) => width && `min-width: ${width}px;`}
`;
const StyledCellContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
const emptyDimension = {
name: '',
values: [undefined],
props: () => ({}),
} as CatalogDimension;
const isStringOrNumber = (term: unknown): term is string | number =>
isString(term) || isNumber(term);
export type CatalogDimension<
ComponentType extends React.ElementType = () => JSX.Element,
> = {
name: string;
values: any[];
props: (value: any) => Partial<ComponentProps<ComponentType>>;
labels?: (value: any) => string;
};
export type CatalogOptions = {
elementContainer?: {
width?: number;
};
};
export const CatalogDecorator: Decorator = (Story, context) => {
const {
catalog: { dimensions, options },
} = context.parameters;
const [
dimension1,
dimension2 = emptyDimension,
dimension3 = emptyDimension,
dimension4 = emptyDimension,
] = dimensions as CatalogDimension[];
return (
<StyledContainer>
{dimension4.values.map((value4: any) => (
<StyledColumnContainer key={value4}>
<StyledColumnTitle>
{dimension4.labels?.(value4) ??
(isStringOrNumber(value4) ? value4 : '')}
</StyledColumnTitle>
{dimension3.values.map((value3: any) => (
<StyledRowsContainer key={value3}>
<StyledRowsTitle>
{dimension3.labels?.(value3) ??
(isStringOrNumber(value3) ? value3 : '')}
</StyledRowsTitle>
{dimension2.values.map((value2: any) => (
<StyledRowContainer key={value2}>
<StyledRowTitle>
{dimension2.labels?.(value2) ??
(isStringOrNumber(value2) ? value2 : '')}
</StyledRowTitle>
{dimension1.values.map((value1: any) => {
return (
<StyledCellContainer key={value1} id={value1}>
<StyledElementTitle>
{dimension1.labels?.(value1) ??
(isStringOrNumber(value1) ? value1 : '')}
</StyledElementTitle>
<StyledElementContainer
width={options?.elementContainer?.width}
>
<Story
args={{
...context.args,
...dimension1.props(value1),
...dimension2.props(value2),
...dimension3.props(value3),
...dimension4.props(value4),
}}
/>
</StyledElementContainer>
</StyledCellContainer>
);
})}
</StyledRowContainer>
))}
</StyledRowsContainer>
))}
</StyledColumnContainer>
))}
</StyledContainer>
);
};

View File

@ -0,0 +1,8 @@
import { MemoryRouter } from 'react-router-dom';
import { Decorator } from '@storybook/react';
export const RouterDecorator: Decorator = (Story) => (
<MemoryRouter>
<Story />
</MemoryRouter>
);

View File

@ -1,2 +1,6 @@
export * from './ComponentStorybookLayout';
export * from './decorators/CatalogDecorator';
export * from './decorators/ComponentDecorator';
export * from './decorators/RouterDecorator';
export * from './mocks/avatarUrlMock';
export * from './types/CatalogStory';

View File

@ -0,0 +1,2 @@
export const AVATAR_URL_MOCK =
'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAYABgAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAABSgAwAEAAAAAQAAABQAAAAA/8AAEQgAFAAUAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMACwgICggHCwoJCg0MCw0RHBIRDw8RIhkaFBwpJCsqKCQnJy0yQDctMD0wJyc4TDk9Q0VISUgrNk9VTkZUQEdIRf/bAEMBDA0NEQ8RIRISIUUuJy5FRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRf/dAAQAAv/aAAwDAQACEQMRAD8Ava1q728otYY98joSCTgZrnbXWdTtrhrfVZXWLafmcAEkdgR/hVltQku9Q8+OIEBcGOT+ID0PY1ka1KH2u8ToqnPLbmIqG7u6LtbQ7RXBRec4Uck9eKXcPWsKDWVnhWSL5kYcFelSf2m3901POh8jP//QoyIAnTuKpXsY82NsksUyWPU5q/L9z8RVK++/F/uCsVsaEURwgA4HtT9x9TUcf3KfUGh//9k=';

View File

@ -0,0 +1,24 @@
import { ElementType } from 'react';
import { StoryObj } from '@storybook/react';
import {
CatalogDimension,
CatalogOptions,
} from '../decorators/CatalogDecorator';
export type CatalogStory<
StoryType extends StoryObj<ComponentType>,
ComponentType extends ElementType,
> = {
args?: StoryType['args'];
argTypes?: StoryType['argTypes'];
play?: StoryType['play'];
render?: StoryType['render'];
parameters: StoryType['parameters'] & {
catalog: {
dimensions: CatalogDimension<ComponentType>[];
options?: CatalogOptions;
};
};
decorators: StoryType['decorators'];
};