Migrate to a monorepo structure (#2909)

This commit is contained in:
Charles Bochet
2023-12-10 18:10:54 +01:00
committed by GitHub
parent a70a9281eb
commit 5bdca9de6c
2304 changed files with 37152 additions and 25869 deletions

View File

@ -0,0 +1,43 @@
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
type ContactLinkProps = {
className?: string;
href: string;
children?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const StyledClickable = styled.div`
display: flex;
overflow: hidden;
white-space: nowrap;
a {
color: inherit;
overflow: hidden;
text-decoration: underline;
text-decoration-color: ${({ theme }) => theme.border.color.strong};
text-overflow: ellipsis;
&:hover {
text-decoration-color: ${({ theme }) => theme.font.color.primary};
}
}
`;
export const ContactLink = ({
className,
href,
children,
onClick,
}: ContactLinkProps) => (
<div>
<StyledClickable className={className}>
<ReactLink target="_blank" onClick={onClick} to={href}>
{children}
</ReactLink>
</StyledClickable>
</div>
);

View File

@ -0,0 +1,33 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconBrandGithub } from '@/ui/display/icon';
import packageJson from '../../../../../../package.json';
import { githubLink } from '../constants';
const StyledVersionLink = styled.a`
align-items: center;
color: ${({ theme }) => theme.font.color.light};
display: flex;
font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium};
gap: ${({ theme }) => theme.spacing(1)};
padding: 0 ${({ theme }) => theme.spacing(1)};
text-decoration: none;
:hover {
color: ${({ theme }) => theme.font.color.tertiary};
}
`;
export const GithubVersionLink = () => {
const theme = useTheme();
return (
<StyledVersionLink href={githubLink} target="_blank" rel="noreferrer">
<IconBrandGithub size={theme.icon.size.md} />
{packageJson.version}
</StyledVersionLink>
);
};

View File

@ -0,0 +1,37 @@
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
type RawLinkProps = {
className?: string;
href: string;
children?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const StyledClickable = styled.div`
display: flex;
overflow: hidden;
white-space: nowrap;
a {
color: inherit;
overflow: hidden;
text-overflow: ellipsis;
}
`;
export const RawLink = ({
className,
href,
children,
onClick,
}: RawLinkProps) => (
<div>
<StyledClickable className={className}>
<ReactLink target="_blank" onClick={onClick} to={href}>
{children}
</ReactLink>
</StyledClickable>
</div>
);

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
import { Chip, ChipSize, ChipVariant } from '@/ui/display/chip/components/Chip';
type RoundedLinkProps = {
href: string;
children?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const StyledClickable = styled.div`
overflow: hidden;
white-space: nowrap;
a {
color: inherit;
overflow: hidden;
text-decoration: none;
text-overflow: ellipsis;
}
`;
export const RoundedLink = ({ children, href, onClick }: RoundedLinkProps) => (
<div>
{children !== '' ? (
<StyledClickable>
<ReactLink target="_blank" to={href} onClick={onClick}>
<Chip
label={`${children}`}
variant={ChipVariant.Rounded}
size={ChipSize.Small}
/>
</ReactLink>
</StyledClickable>
) : (
<></>
)}
</div>
);

View File

@ -0,0 +1,64 @@
import * as React from 'react';
import styled from '@emotion/styled';
import { RoundedLink } from './RoundedLink';
export enum LinkType {
Url = 'url',
LinkedIn = 'linkedin',
Twitter = 'twitter',
}
type SocialLinkProps = {
href: string;
children?: React.ReactNode;
type?: LinkType;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const StyledRawLink = styled(RoundedLink)`
overflow: hidden;
a {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`;
export const SocialLink = ({
children,
href,
onClick,
type,
}: SocialLinkProps) => {
let displayValue = children;
if (type === 'linkedin') {
const matches = href.match(
/(?:https?:\/\/)?(?:www.)?linkedin.com\/(?:in|company)\/([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
);
if (matches && matches[1]) {
displayValue = matches[1];
} else {
displayValue = 'LinkedIn';
}
}
if (type === 'twitter') {
const matches = href.match(
/(?:https?:\/\/)?(?:www.)?twitter.com\/([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
);
if (matches && matches[1]) {
displayValue = `@${matches[1]}`;
} else {
displayValue = '@twitter';
}
}
return (
<StyledRawLink href={href} onClick={onClick}>
{displayValue}
</StyledRawLink>
);
};

View File

@ -0,0 +1,36 @@
import { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { ContactLink } from '../ContactLink';
const meta: Meta<typeof ContactLink> = {
title: 'UI/Navigation/Link/ContactLink',
component: ContactLink,
decorators: [ComponentWithRouterDecorator],
args: {
className: 'ContactLink',
href: '/test',
children: 'Contact Link',
},
};
export default meta;
type Story = StoryObj<typeof ContactLink>;
const clickJestFn = fn();
export const Email: Story = {
args: {
href: `mailto:${'email@example.com'}`,
children: 'email@example.com',
onClick: clickJestFn,
},
};
export const Phone: Story = {
args: {
children: '11111111111',
onClick: clickJestFn,
},
};

View File

@ -0,0 +1,16 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { GithubVersionLink } from '../GithubVersionLink';
const meta: Meta<typeof GithubVersionLink> = {
title: 'UI/Navigation/Link/GithubVersionLink',
component: GithubVersionLink,
decorators: [ComponentWithRouterDecorator],
};
export default meta;
type Story = StoryObj<typeof GithubVersionLink>;
export const Default: Story = {};

View File

@ -0,0 +1,36 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { RawLink } from '../RawLink';
const meta: Meta<typeof RawLink> = {
title: 'UI/Navigation/Link/RawLink',
component: RawLink,
decorators: [ComponentWithRouterDecorator],
args: {
className: 'RawLink',
href: '/test',
children: 'Raw Link',
},
};
export default meta;
type Story = StoryObj<typeof RawLink>;
const clickJestFn = fn();
export const Default: Story = {
args: {
onClick: clickJestFn,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(clickJestFn).toHaveBeenCalledTimes(0);
const link = canvas.getByRole('link');
await userEvent.click(link);
await expect(clickJestFn).toHaveBeenCalledTimes(1);
},
};

View File

@ -0,0 +1,35 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { RoundedLink } from '../RoundedLink';
const meta: Meta<typeof RoundedLink> = {
title: 'UI/Navigation/Link/RoundedLink',
component: RoundedLink,
decorators: [ComponentWithRouterDecorator],
args: {
href: '/test',
children: 'Rounded chip',
},
};
export default meta;
type Story = StoryObj<typeof RoundedLink>;
const clickJestFn = fn();
export const Default: Story = {
args: {
onClick: clickJestFn,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(clickJestFn).toHaveBeenCalledTimes(0);
const link = canvas.getByRole('link');
await userEvent.click(link);
await expect(clickJestFn).toHaveBeenCalledTimes(1);
},
};

View File

@ -0,0 +1,50 @@
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { LinkType, SocialLink } from '../SocialLink';
const meta: Meta<typeof SocialLink> = {
title: 'UI/Navigation/Link/SocialLink',
component: SocialLink,
decorators: [ComponentWithRouterDecorator],
args: {
href: '/test',
children: 'Social Link',
},
};
export default meta;
type Story = StoryObj<typeof SocialLink>;
const clickJestFn = fn();
const linkedin: LinkType = LinkType.LinkedIn;
const twitter: LinkType = LinkType.Twitter;
export const LinkedIn: Story = {
args: {
href: '/LinkedIn',
children: 'LinkedIn',
onClick: clickJestFn,
type: linkedin,
},
};
export const Twitter: Story = {
args: {
href: '/Twitter',
children: 'Twitter',
onClick: clickJestFn,
type: twitter,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(clickJestFn).toHaveBeenCalledTimes(0);
const link = canvas.getByRole('link');
await userEvent.click(link);
await expect(clickJestFn).toHaveBeenCalledTimes(1);
},
};

View File

@ -0,0 +1 @@
export const githubLink = 'https://github.com/twentyhq/twenty';