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

feat(main-nav): Main Nav refactoring, add the Home icon #20176

Merged
merged 13 commits into from Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion packages/core/admin/admin/src/components/LeftMenu.tsx
Expand Up @@ -11,7 +11,7 @@ import {
NavSections,
NavUser,
} from '@strapi/design-system/v2';
import { Exit, Write, Lock } from '@strapi/icons';
import { Exit, Write, Lock, House } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { NavLink as RouterNavLink, useLocation } from 'react-router-dom';
import styled from 'styled-components';
Expand All @@ -24,6 +24,7 @@ import { usePersistentState } from '../hooks/usePersistentState';
import { getDisplayName } from '../utils/users';

import { NavBrand as NewNavBrand } from './MainNav/NavBrand';
import { NavLink as NewNavLink } from './MainNav/NavLink';

const LinkUserWrapper = styled(Box)`
width: ${150 / 16}rem;
Expand Down Expand Up @@ -135,6 +136,17 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }: LeftMenuProps) =
<Divider />

<NavSections>
{condensed && (
<NewNavLink.Link to="/" onClick={() => handleClickOnLink('/')}>
<NewNavLink.Tooltip
label={formatMessage({ id: 'global.home', defaultMessage: 'Home' })}
>
<NewNavLink.Icon>
<Icon as={House} color="neutral500" />
simotae14 marked this conversation as resolved.
Show resolved Hide resolved
</NewNavLink.Icon>
</NewNavLink.Tooltip>
</NewNavLink.Link>
)}
<NavLink
as={RouterNavLink}
// @ts-expect-error the props from the passed as prop are not inferred // joined together
Expand Down
125 changes: 125 additions & 0 deletions packages/core/admin/admin/src/components/MainNav/NavLink.tsx
simotae14 marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,125 @@
import * as React from 'react';

import { Tooltip, Flex, Badge } from '@strapi/design-system';
import { NavLink as RouterLink, LinkProps } from 'react-router-dom';
import styled from 'styled-components';

/* -------------------------------------------------------------------------------------------------
* Link
* -----------------------------------------------------------------------------------------------*/
const MainNavLinkWrapper = styled(RouterLink)`
text-decoration: none;
display: block;
border-radius: ${({ theme }) => theme.borderRadius};
background: ${({ theme }) => theme.colors.neutral0};
color: ${({ theme }) => theme.colors.neutral600};
position: relative;

&:hover,
&.active {
background: ${({ theme }) => theme.colors.neutral100};
}

&:hover {
svg path {
fill: ${({ theme }) => theme.colors.neutral600};
}
color: ${({ theme }) => theme.colors.neutral700};
}

&.active {
svg path {
fill: ${({ theme }) => theme.colors.primary600};
}

color: ${({ theme }) => theme.colors.primary600};
font-weight: 500;
}
`;

const LinkImpl = ({ children, ...props }: LinkProps) => {
return <MainNavLinkWrapper {...props}>{children}</MainNavLinkWrapper>;
};

/* -------------------------------------------------------------------------------------------------
* Tooltip
* -----------------------------------------------------------------------------------------------*/
const TooltipImpl = ({ children, label, position = 'right' }: NavLink.TooltipProps) => {
return (
<Tooltip position={position} label={label}>
<Flex justifyContent="center">{children}</Flex>
</Tooltip>
);
};

/* -------------------------------------------------------------------------------------------------
* Icon
* -----------------------------------------------------------------------------------------------*/
const IconImpl = ({ children }: { children: React.ReactNode }) => {
return (
simotae14 marked this conversation as resolved.
Show resolved Hide resolved
<Flex
paddingTop={`${8 / 16}rem`}
paddingBottom={`${8 / 16}rem`}
paddingLeft={`${12 / 16}rem`}
paddingRight={`${12 / 16}rem`}
justifyContent="center"
aria-hidden
as="span"
>
{children}
</Flex>
);
};

/* -------------------------------------------------------------------------------------------------
* Badge
* -----------------------------------------------------------------------------------------------*/
const CustomBadge = styled(Badge)`
/* override default badge styles to change the border radius of the Base element in the Design System */
border-radius: ${({ theme }) => theme.spaces[10]};
`;

const BadgeImpl = ({ children, label }: NavLink.BadgeProps) => {
if (!children) {
return null;
}
return (
<CustomBadge
position="absolute"
top="-12px"
right="-4px"
simotae14 marked this conversation as resolved.
Show resolved Hide resolved
aria-label={label}
background="primary600"
textColor="neutral0"
>
{children}
</CustomBadge>
);
};

/* -------------------------------------------------------------------------------------------------
* EXPORTS
* -----------------------------------------------------------------------------------------------*/

const NavLink = {
Link: LinkImpl,
Tooltip: TooltipImpl,
Icon: IconImpl,
Badge: BadgeImpl,
};

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NavLink {
export interface BadgeProps {
children: React.ReactNode;
label: string;
}

export interface TooltipProps {
position?: 'top' | 'bottom' | 'left' | 'right';
label?: string;
children: React.ReactNode;
}
}

export { NavLink };
@@ -0,0 +1,39 @@
import { Icon } from '@strapi/design-system';
import { House, Lock } from '@strapi/icons';
import { screen, render as renderRTL } from '@tests/utils';

import { NavLink } from '../NavLink';

describe('NavLink', () => {
simotae14 marked this conversation as resolved.
Show resolved Hide resolved
const Component = () => (
<NavLink.Link to="/test-link">
<NavLink.Tooltip label="test-tooltip">
<>
<NavLink.Icon>
<Icon as={House} data-testid="nav-link-icon" />
</NavLink.Icon>
<NavLink.Badge label="badge label">
<Icon data-testid="nav-link-badge" as={Lock} />
</NavLink.Badge>
</>
</NavLink.Tooltip>
</NavLink.Link>
);

const render = () => renderRTL(<Component />);

it('shows the NavLink with link to destination', async () => {
render();
const link = screen.getByRole('link');
expect(link).toBeInTheDocument();
expect(link).toHaveAttribute('href', '/test-link');
});
it('shows the home icon in the link', async () => {
render();
expect(screen.getByTestId('nav-link-icon')).toBeInTheDocument();
});
it('shows the badge next to the link', async () => {
render();
expect(screen.getByTestId('nav-link-badge')).toBeInTheDocument();
});
});
1 change: 1 addition & 0 deletions packages/core/admin/admin/src/translations/en.json
Expand Up @@ -685,6 +685,7 @@
"global.change-password": "Change password",
"global.close": "Close",
"global.content-manager": "Content Manager",
"global.home": "Home",
"global.continue": "Continue",
"global.delete": "Delete",
"global.delete-target": "Delete {target}",
Expand Down