Migrate to twenty-ui - navigation/link (#7837)

This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-7535](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-7535).

 --- 

### Description.  

Migrate link components to `twenty-ui` \
\
Fixes #7535

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: gitstart-twenty <140154534+gitstart-twenty@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-app[bot]
2024-10-22 17:36:26 +02:00
committed by GitHub
parent 02c34d547f
commit 430644448a
71 changed files with 262 additions and 154 deletions

View File

@ -1,8 +1,8 @@
import { MouseEvent } from 'react';
import { ContactLink } from '@/ui/navigation/link/components/ContactLink';
import { isDefined } from '~/utils/isDefined';
import { ContactLink } from 'twenty-ui';
import { EllipsisDisplay } from './EllipsisDisplay';
const validateEmail = (email: string) => {

View File

@ -1,9 +1,8 @@
import { useMemo } from 'react';
import { THEME_COMMON } from 'twenty-ui';
import { RoundedLink, THEME_COMMON } from 'twenty-ui';
import { FieldEmailsValue } from '@/object-record/record-field/types/FieldMetadata';
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import styled from '@emotion/styled';
import { isDefined } from '~/utils/isDefined';

View File

@ -1,10 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import {
LinkType,
SocialLink,
} from '@/ui/navigation/link/components/SocialLink';
import { LinkType, RoundedLink, SocialLink } from 'twenty-ui';
type LinkDisplayProps = {
value?: { url: string; label?: string };

View File

@ -1,14 +1,9 @@
import { useMemo } from 'react';
import { styled } from '@linaria/react';
import { THEME_COMMON } from 'twenty-ui';
import { useMemo } from 'react';
import { LinkType, RoundedLink, SocialLink, THEME_COMMON } from 'twenty-ui';
import { FieldLinksValue } from '@/object-record/record-field/types/FieldMetadata';
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import {
LinkType,
SocialLink,
} from '@/ui/navigation/link/components/SocialLink';
import { checkUrlType } from '~/utils/checkUrlType';
import { isDefined } from '~/utils/isDefined';
import { getAbsoluteUrl } from '~/utils/url/getAbsoluteUrl';

View File

@ -1,7 +1,7 @@
import { parsePhoneNumber, PhoneNumber } from 'libphonenumber-js';
import { MouseEvent } from 'react';
import { ContactLink } from 'twenty-ui';
import { ContactLink } from '@/ui/navigation/link/components/ContactLink';
import { isDefined } from '~/utils/isDefined';
type PhoneDisplayProps = {

View File

@ -1,10 +1,9 @@
import styled from '@emotion/styled';
import { useMemo } from 'react';
import { THEME_COMMON } from 'twenty-ui';
import { RoundedLink, THEME_COMMON } from 'twenty-ui';
import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import { parsePhoneNumber } from 'libphonenumber-js';
import { isDefined } from '~/utils/isDefined';

View File

@ -1,13 +1,9 @@
import { MouseEvent } from 'react';
import styled from '@emotion/styled';
import { MouseEvent } from 'react';
import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import {
LinkType,
SocialLink,
} from '@/ui/navigation/link/components/SocialLink';
import { checkUrlType } from '~/utils/checkUrlType';
import { LinkType, RoundedLink, SocialLink } from 'twenty-ui';
import { EllipsisDisplay } from './EllipsisDisplay';
const StyledRawLink = styled(RoundedLink)`

View File

@ -1,6 +1,6 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React, { MouseEvent, useMemo, useRef, useState } from 'react';
import { MouseEvent, useMemo, useRef, useState } from 'react';
import { IconChevronDown, IconComponent } from 'twenty-ui';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@ -10,8 +10,8 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { SelectHotkeyScope } from '../types/SelectHotkeyScope';
import { isDefined } from '~/utils/isDefined';
import { SelectHotkeyScope } from '../types/SelectHotkeyScope';
export type SelectOption<Value extends string | number | null> = {
value: Value;

View File

@ -1,88 +0,0 @@
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { VisibilityHiddenInput } from 'twenty-ui';
export type ToggleSize = 'small' | 'medium';
type ContainerProps = {
isOn: boolean;
color?: string;
toggleSize: ToggleSize;
'data-disabled'?: boolean;
};
const StyledContainer = styled.label<ContainerProps>`
align-items: center;
background-color: ${({ theme, isOn, color }) =>
isOn ? (color ?? theme.color.blue) : theme.background.transparent.medium};
border-radius: 10px;
cursor: pointer;
display: flex;
height: ${({ toggleSize }) => (toggleSize === 'small' ? 16 : 20)}px;
transition: background-color 0.3s ease;
width: ${({ toggleSize }) => (toggleSize === 'small' ? 24 : 32)}px;
opacity: ${({ 'data-disabled': disabled }) => (disabled ? 0.5 : 1)};
pointer-events: ${({ 'data-disabled': disabled }) =>
disabled ? 'none' : 'auto'};
`;
const StyledCircle = styled(motion.span)<{
size: ToggleSize;
}>`
display: block;
background-color: ${({ theme }) => theme.background.primary};
border-radius: 50%;
height: ${({ size }) => (size === 'small' ? 12 : 16)}px;
width: ${({ size }) => (size === 'small' ? 12 : 16)}px;
`;
export type ToggleProps = {
id?: string;
value?: boolean;
onChange?: (value: boolean, e?: React.MouseEvent<HTMLDivElement>) => void;
color?: string;
toggleSize?: ToggleSize;
className?: string;
disabled?: boolean;
};
export const Toggle = ({
id,
value = false,
onChange,
color,
toggleSize = 'medium',
className,
disabled,
}: ToggleProps) => {
const circleVariants = {
on: { x: toggleSize === 'small' ? 10 : 14 },
off: { x: 2 },
};
return (
<StyledContainer
isOn={value}
color={color}
toggleSize={toggleSize}
className={className}
data-disabled={disabled}
>
<VisibilityHiddenInput
id={id}
type="checkbox"
checked={value}
disabled={disabled}
onChange={(event) => {
onChange?.(event.target.checked);
}}
/>
<StyledCircle
animate={value ? 'on' : 'off'}
variants={circleVariants}
size={toggleSize}
/>
</StyledContainer>
);
};

View File

@ -1,10 +1,9 @@
import { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
import { useState } from 'react';
import { ComponentDecorator, IconPlus } from 'twenty-ui';
import { Select, SelectProps } from '../Select';
import { IconPlus } from 'packages/twenty-ui';
type RenderProps = SelectProps<string | number | null>;

View File

@ -1,7 +1,6 @@
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
import { IconExternalLink } from 'twenty-ui';
import { IconExternalLink, UndecoratedLink } from 'twenty-ui';
export const RightDrawerTopBarExpandButton = ({ to }: { to: string }) => {
const { closeRightDrawer } = useRightDrawer();

View File

@ -1,31 +0,0 @@
import React from 'react';
import styled from '@emotion/styled';
const StyledButtonLink = 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};
cursor: pointer;
}
`;
export const ActionLink = (props: React.ComponentProps<'a'>) => {
return (
<StyledButtonLink
href={props.href}
onClick={props.onClick}
target={props.target}
rel={props.rel}
>
{props.children}
</StyledButtonLink>
);
};

View File

@ -1,68 +0,0 @@
import { Toggle } from '@/ui/input/components/Toggle';
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
import styled from '@emotion/styled';
import { useId } from 'react';
import { useRecoilState } from 'recoil';
import { IconTool, MAIN_COLORS } from 'twenty-ui';
const StyledContainer = styled.div`
align-items: center;
display: flex;
width: 100%;
gap: ${({ theme }) => theme.spacing(2)};
position: relative;
`;
const StyledLabel = styled.label`
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium};
padding: ${({ theme }) => theme.spacing(1)};
`;
const StyledIconContainer = styled.div`
border-right: 1px solid ${MAIN_COLORS.yellow};
height: 16px;
position: absolute;
left: ${({ theme }) => theme.spacing(-5)};
`;
const StyledToggleContainer = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
`;
const StyledIconTool = styled(IconTool)`
margin-right: ${({ theme }) => theme.spacing(0.5)};
`;
export const AdvancedSettingsToggle = () => {
const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilState(
isAdvancedModeEnabledState,
);
const inputId = useId();
const onChange = (newValue: boolean) => {
setIsAdvancedModeEnabled(newValue);
};
return (
<StyledContainer>
<StyledIconContainer>
<StyledIconTool size={12} color={MAIN_COLORS.yellow} />
</StyledIconContainer>
<StyledToggleContainer>
<StyledLabel htmlFor={inputId}>Advanced:</StyledLabel>
<Toggle
id={inputId}
onChange={onChange}
color={MAIN_COLORS.yellow}
value={isAdvancedModeEnabled}
/>
</StyledToggleContainer>
</StyledContainer>
);
};

View File

@ -1,47 +0,0 @@
import * as React from 'react';
import { Theme, withTheme } from '@emotion/react';
import { styled } from '@linaria/react';
const StyledClickableLink = withTheme(styled.a<{
theme: Theme;
maxWidth?: number;
}>`
color: inherit;
overflow: hidden;
text-decoration: underline;
text-decoration-color: ${({ theme }) => theme.border.color.strong};
text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
max-width: ${({ maxWidth }) => maxWidth ?? '100%'};
&:hover {
text-decoration-color: ${({ theme }) => theme.font.color.primary};
}
`);
type ContactLinkProps = {
href: string;
children?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
maxWidth?: number;
};
export const ContactLink = ({
href,
children,
onClick,
maxWidth,
}: ContactLinkProps) => (
<StyledClickableLink
maxWidth={maxWidth}
target="_blank"
onClick={onClick}
href={href}
>
{children}
</StyledClickableLink>
);

View File

@ -1,18 +0,0 @@
import { useTheme } from '@emotion/react';
import { IconBrandGithub } from 'twenty-ui';
import { ActionLink } from '@/ui/navigation/link/components/ActionLink';
import packageJson from '../../../../../../package.json';
import { GITHUB_LINK } from '../constants/GithubLink';
export const GithubVersionLink = () => {
const theme = useTheme();
return (
<ActionLink href={GITHUB_LINK} target="_blank" rel="noreferrer">
<IconBrandGithub size={theme.icon.size.md} />
{packageJson.version}
</ActionLink>
);
};

View File

@ -1,37 +0,0 @@
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

@ -1,96 +0,0 @@
import { styled } from '@linaria/react';
import { isNonEmptyString } from '@sniptt/guards';
import { MouseEvent, useContext } from 'react';
import { FONT_COMMON, THEME_COMMON, ThemeContext } from 'twenty-ui';
type RoundedLinkProps = {
href: string;
label?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const fontSizeMd = FONT_COMMON.size.md;
const spacing1 = THEME_COMMON.spacing(1);
const spacing2 = THEME_COMMON.spacing(2);
const spacingMultiplicator = THEME_COMMON.spacingMultiplicator;
const StyledLink = styled.a<{
color: string;
background: string;
backgroundHover: string;
backgroundActive: string;
border: string;
}>`
align-items: center;
background-color: ${({ background }) => background};
border: 1px solid ${({ border }) => border};
border-radius: 50px;
color: ${({ color }) => color};
cursor: pointer;
display: inline-flex;
font-weight: ${fontSizeMd};
gap: ${spacing1};
height: 10px;
justify-content: center;
max-width: calc(100% - ${spacingMultiplicator} * 2px);
min-width: fit-content;
overflow: hidden;
padding: ${spacing1} ${spacing2};
text-decoration: none;
text-overflow: ellipsis;
user-select: none;
white-space: nowrap;
&:hover {
background-color: ${({ backgroundHover }) => backgroundHover};
}
&:active {
background-color: ${({ backgroundActive }) => backgroundActive};
}
`;
export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => {
const { theme } = useContext(ThemeContext);
const background = theme.background.transparent.lighter;
const backgroundHover = theme.background.transparent.light;
const backgroundActive = theme.background.transparent.medium;
const border = theme.border.color.strong;
const color = theme.font.color.primary;
if (!isNonEmptyString(label)) {
return <></>;
}
const handleClick = (event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
onClick?.(event);
};
return (
<StyledLink
href={href}
target="_blank"
rel="noreferrer"
onClick={handleClick}
color={color}
background={background}
backgroundHover={backgroundHover}
backgroundActive={backgroundActive}
border={border}
>
{label}
</StyledLink>
);
};

View File

@ -1,25 +0,0 @@
import * as React from 'react';
import { getDisplayValueByUrlType } from '~/utils/getDisplayValueByUrlType';
import { RoundedLink } from './RoundedLink';
export enum LinkType {
Url = 'url',
LinkedIn = 'linkedin',
Twitter = 'twitter',
}
type SocialLinkProps = {
label: string;
href: string;
type: LinkType;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
export const SocialLink = ({ label, href, onClick, type }: SocialLinkProps) => {
const displayValue =
getDisplayValueByUrlType({ type: type, href: href }) ?? label;
return <RoundedLink href={href} onClick={onClick} label={displayValue} />;
};

View File

@ -1,42 +0,0 @@
import styled from '@emotion/styled';
import React from 'react';
import { Link, LinkProps } from 'react-router-dom';
type StyledLinkProps = LinkProps & {
fullWidth?: boolean;
};
const StyledUndecoratedLink = styled(
// eslint-disable-next-line react/jsx-props-no-spreading
({ fullWidth: _, ...props }: StyledLinkProps) => <Link {...props} />,
)<StyledLinkProps>`
text-decoration: none;
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
`;
type UndecoratedLinkProps = {
to: string | number;
children: React.ReactNode;
replace?: boolean;
onClick?: React.MouseEventHandler<HTMLAnchorElement>;
fullWidth?: boolean;
};
export const UndecoratedLink = ({
children,
to,
replace = false,
onClick,
fullWidth = false,
}: UndecoratedLinkProps) => {
return (
<StyledUndecoratedLink
to={to as string}
replace={replace}
onClick={onClick}
fullWidth={fullWidth}
>
{children}
</StyledUndecoratedLink>
);
};

View File

@ -1,27 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { ActionLink } from '@/ui/navigation/link/components/ActionLink';
const meta: Meta<typeof ActionLink> = {
title: 'UI/navigation/link/ActionLink',
component: ActionLink,
};
export default meta;
type Story = StoryObj<typeof ActionLink>;
export const Default: Story = {
args: {
children: 'Need to reset your password?',
onClick: () => alert('Action link clicked'),
target: undefined,
rel: undefined,
},
argTypes: {
href: { control: false },
target: { type: 'string' },
rel: { type: 'string' },
},
decorators: [ComponentDecorator],
};

View File

@ -1,35 +0,0 @@
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: {
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

@ -1,16 +0,0 @@
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

@ -1,36 +0,0 @@
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

@ -1,35 +0,0 @@
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',
label: '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

@ -1,50 +0,0 @@
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',
label: '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',
label: 'LinkedIn',
onClick: clickJestFn,
type: linkedin,
},
};
export const Twitter: Story = {
args: {
href: '/Twitter',
label: '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

@ -1,32 +0,0 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/test';
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
const meta: Meta<typeof UndecoratedLink> = {
title: 'UI/navigation/link/UndecoratedLink',
component: UndecoratedLink,
decorators: [ComponentWithRouterDecorator],
};
export default meta;
type Story = StoryObj<typeof UndecoratedLink>;
export const Default: Story = {
args: {
children: 'Go Home',
to: '/home',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const link = canvas.getByText('Go Home');
await userEvent.click(link);
const href = link.getAttribute('href');
expect(href).toBe('/home');
},
};

View File

@ -1 +0,0 @@
export const CAL_LINK = 'https://cal.com/team/twenty/talk-to-us';

View File

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

View File

@ -1,6 +1,4 @@
import { IconComponent } from 'twenty-ui';
import { Toggle, ToggleSize } from '@/ui/input/components/Toggle';
import { IconComponent, Toggle, ToggleSize } from 'twenty-ui';
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
import {

View File

@ -1,9 +1,8 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { IconX } from 'twenty-ui';
import { IconX, UndecoratedLink } from 'twenty-ui';
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';

View File

@ -1,5 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import {
GithubVersionLink,
IconAt,
IconBell,
IconBuildingSkyscraper,
@ -18,18 +19,17 @@ import {
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { GithubVersionLink } from '@/ui/navigation/link/components/GithubVersionLink';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { CurrentWorkspaceMemberFavorites } from '@/favorites/components/CurrentWorkspaceMemberFavorites';
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
import jsonPage from '../../../../../../../package.json';
import { NavigationDrawer } from '../NavigationDrawer';
import { NavigationDrawerItem } from '../NavigationDrawerItem';
import { NavigationDrawerItemGroup } from '../NavigationDrawerItemGroup';
import { NavigationDrawerSection } from '../NavigationDrawerSection';
import { NavigationDrawerSectionTitle } from '../NavigationDrawerSectionTitle';
const meta: Meta<typeof NavigationDrawer> = {
title: 'UI/Navigation/NavigationDrawer/NavigationDrawer',
component: NavigationDrawer,
@ -148,6 +148,6 @@ export const Settings: Story = {
</NavigationDrawerSection>
</>
),
footer: <GithubVersionLink />,
footer: <GithubVersionLink version={jsonPage.version} />,
},
};