Migrate to twenty-ui - display (#8004)
This PR was created by [GitStart](https://gitstart.com/) to address the requirements from this ticket: [TWNTY-6871](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-6871). --- ### Description Migrate: - Info display component - Status display component - SeparatorLineText display component ### Demo ###### SeparatorLineText In Storybook  Info Component on Storybook  Status Component on Storybook  ###### Fixes twentyhq/private-issues#95 --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
e44d525e83
commit
b09ecfbb8c
@ -1,92 +0,0 @@
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, IconInfoCircle } from 'twenty-ui';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
|
||||
export type InfoAccent = 'blue' | 'danger';
|
||||
export type InfoProps = {
|
||||
accent?: InfoAccent;
|
||||
text: string;
|
||||
buttonTitle?: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
to?: AppPath;
|
||||
};
|
||||
|
||||
const StyledTextContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledIconInfoCircle = styled(IconInfoCircle)`
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const StyledInfo = styled.div<Pick<InfoProps, 'accent'>>`
|
||||
align-items: center;
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
display: flex;
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
justify-content: space-between;
|
||||
max-width: 512px;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
${({ theme, accent }) => {
|
||||
switch (accent) {
|
||||
case 'blue':
|
||||
return css`
|
||||
background: ${theme.color.blueAccent20};
|
||||
color: ${theme.color.blue50};
|
||||
`;
|
||||
case 'danger':
|
||||
return css`
|
||||
background: ${theme.color.red10};
|
||||
color: ${theme.color.red};
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
text-decoration: none;
|
||||
`;
|
||||
|
||||
export const Info = ({
|
||||
accent = 'blue',
|
||||
text,
|
||||
buttonTitle,
|
||||
onClick,
|
||||
to,
|
||||
}: InfoProps) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<StyledInfo accent={accent}>
|
||||
<StyledTextContainer>
|
||||
<StyledIconInfoCircle size={theme.icon.size.md} />
|
||||
{text}
|
||||
</StyledTextContainer>
|
||||
{buttonTitle && to && (
|
||||
<StyledLink to={to}>
|
||||
<Button
|
||||
title={buttonTitle}
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
accent={accent}
|
||||
/>
|
||||
</StyledLink>
|
||||
)}
|
||||
{buttonTitle && onClick && !to && (
|
||||
<Button
|
||||
title={buttonTitle}
|
||||
onClick={onClick}
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
accent={accent}
|
||||
/>
|
||||
)}
|
||||
</StyledInfo>
|
||||
);
|
||||
};
|
||||
@ -1,43 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { CatalogDecorator, CatalogStory, ComponentDecorator } from 'twenty-ui';
|
||||
|
||||
import { Info, InfoAccent } from '@/ui/display/info/components/Info';
|
||||
|
||||
const meta: Meta<typeof Info> = {
|
||||
title: 'UI/Display/Info',
|
||||
component: Info,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Info>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
accent: 'blue',
|
||||
text: 'An info component',
|
||||
buttonTitle: 'Update',
|
||||
},
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof Info> = {
|
||||
args: {
|
||||
text: 'An info component',
|
||||
buttonTitle: 'Update',
|
||||
},
|
||||
argTypes: {
|
||||
accent: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
name: 'accents',
|
||||
values: ['blue', 'danger'] satisfies InfoAccent[],
|
||||
props: (accent: InfoAccent) => ({ accent }),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
decorators: [CatalogDecorator],
|
||||
};
|
||||
@ -1,70 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { Loader, ThemeColor, themeColorSchema } from 'twenty-ui';
|
||||
|
||||
const StyledStatus = styled.h3<{
|
||||
color: ThemeColor;
|
||||
weight: 'regular' | 'medium';
|
||||
isLoaderVisible: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
background: ${({ color, theme }) => theme.tag.background[color]};
|
||||
border-radius: ${({ theme }) => theme.border.radius.pill};
|
||||
color: ${({ color, theme }) => theme.tag.text[color]};
|
||||
display: inline-flex;
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-style: normal;
|
||||
font-weight: ${({ theme, weight }) => theme.font.weight[weight]};
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
height: ${({ theme }) => theme.spacing(5)};
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0
|
||||
${({ theme, isLoaderVisible }) =>
|
||||
isLoaderVisible ? theme.spacing(1) : theme.spacing(2)}
|
||||
0 ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
&:before {
|
||||
background-color: ${({ color, theme }) => theme.tag.text[color]};
|
||||
border-radius: ${({ theme }) => theme.border.radius.rounded};
|
||||
content: '';
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
height: ${({ theme }) => theme.spacing(1)};
|
||||
width: ${({ theme }) => theme.spacing(1)};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledContent = styled.span`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
type StatusProps = {
|
||||
className?: string;
|
||||
color: ThemeColor;
|
||||
isLoaderVisible?: boolean;
|
||||
text: string;
|
||||
onClick?: () => void;
|
||||
weight?: 'regular' | 'medium';
|
||||
};
|
||||
|
||||
export const Status = ({
|
||||
className,
|
||||
color,
|
||||
isLoaderVisible = false,
|
||||
text,
|
||||
onClick,
|
||||
weight = 'regular',
|
||||
}: StatusProps) => (
|
||||
<StyledStatus
|
||||
className={className}
|
||||
color={themeColorSchema.catch('gray').parse(color)}
|
||||
onClick={onClick}
|
||||
weight={weight}
|
||||
isLoaderVisible={isLoaderVisible}
|
||||
>
|
||||
<StyledContent>{text}</StyledContent>
|
||||
{isLoaderVisible ? <Loader color={color} /> : null}
|
||||
</StyledStatus>
|
||||
);
|
||||
@ -1,68 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, fn, userEvent, within } from '@storybook/test';
|
||||
import {
|
||||
CatalogDecorator,
|
||||
CatalogStory,
|
||||
ComponentDecorator,
|
||||
MAIN_COLOR_NAMES,
|
||||
ThemeColor,
|
||||
} from 'twenty-ui';
|
||||
|
||||
import { Status } from '../Status';
|
||||
|
||||
const meta: Meta<typeof Status> = {
|
||||
title: 'UI/Display/Status/Status',
|
||||
component: Status,
|
||||
args: {
|
||||
text: 'Urgent',
|
||||
weight: 'medium',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Status>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
color: 'red',
|
||||
onClick: fn(),
|
||||
},
|
||||
decorators: [ComponentDecorator],
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const status = canvas.getByRole('heading', { level: 3 });
|
||||
|
||||
await userEvent.click(status);
|
||||
expect(args.onClick).toHaveBeenCalled();
|
||||
},
|
||||
};
|
||||
|
||||
export const WithLongText: Story = {
|
||||
decorators: [ComponentDecorator],
|
||||
args: {
|
||||
color: 'green',
|
||||
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
},
|
||||
parameters: {
|
||||
container: { width: 100 },
|
||||
},
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof Status> = {
|
||||
argTypes: {
|
||||
color: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
name: 'colors',
|
||||
values: MAIN_COLOR_NAMES,
|
||||
props: (color: ThemeColor) => ({ color }),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
decorators: [CatalogDecorator],
|
||||
};
|
||||
@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
color: ${({ theme }) => theme.font.color.extraLight};
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
background: ${({ theme }) => theme.background.transparent.light};
|
||||
}
|
||||
|
||||
&:before {
|
||||
margin: 0 ${({ theme }) => theme.spacing(4)} 0 0;
|
||||
}
|
||||
&:after {
|
||||
margin: 0 0 0 ${({ theme }) => theme.spacing(4)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const SeparatorLineText = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return <StyledContainer>{children}</StyledContainer>;
|
||||
};
|
||||
@ -1,16 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { ComponentDecorator } from 'twenty-ui';
|
||||
|
||||
import { SeparatorLineText } from '../SeparatorLineText';
|
||||
|
||||
const meta: Meta<typeof SeparatorLineText> = {
|
||||
title: 'UI/Display/Text/SeparatorLineText',
|
||||
component: SeparatorLineText,
|
||||
args: { children: 'Or' },
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof SeparatorLineText>;
|
||||
|
||||
export const Default: Story = {};
|
||||
@ -1,18 +1,18 @@
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { useSSO } from '@/auth/sign-in-up/hooks/useSSO';
|
||||
import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import {
|
||||
SignInUpStep,
|
||||
signInUpStepState,
|
||||
} from '@/auth/states/signInUpStepState';
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { useGenerateJwtMutation } from '~/generated/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { sleep } from '~/utils/sleep';
|
||||
import { useSSO } from '@/auth/sign-in-up/hooks/useSSO';
|
||||
import {
|
||||
SignInUpStep,
|
||||
signInUpStepState,
|
||||
} from '@/auth/states/signInUpStepState';
|
||||
import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO';
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
|
||||
export const useWorkspaceSwitching = () => {
|
||||
const setTokenPair = useSetRecoilState(tokenPairState);
|
||||
|
||||
Reference in New Issue
Block a user