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

* feat(main-nav): replace DS NavLink with admin NavLink

* feat(main-nav): change icon type

* feat(main-nav): fix prettier errors

* feat(main-nav): refactor navlink code and add more test cases

* feat(main-nav): minor fixes

* feat(main-nav): fix ui errors

* feat(main-nav): fix merge issues

* feat(main-nav): fix unit test and types

* feat(main-nav): change offset values
This commit is contained in:
Simone 2024-04-29 15:37:57 +02:00 committed by GitHub
parent 4300e8f16c
commit 53cf1f19cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 171 additions and 5 deletions

View File

@ -15,7 +15,7 @@ import {
NavSections,
NavUser,
} from '@strapi/design-system';
import { SignOut, Feather, Lock } from '@strapi/icons';
import { SignOut, Feather, Lock, House } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { NavLink as RouterNavLink, useLocation } from 'react-router-dom';
import styled from 'styled-components';
@ -28,6 +28,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: 15rem;
@ -137,6 +138,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>
<House fill="neutral500" />
</NewNavLink.Icon>
</NewNavLink.Tooltip>
</NewNavLink.Link>
)}
<NavLink
as={RouterNavLink}
// @ts-expect-error the props from the passed as prop are not inferred // joined together

View File

@ -9,9 +9,9 @@ const BrandIconWrapper = styled(Box)`
img {
border-radius: ${({ theme }) => theme.borderRadius};
object-fit: contain;
height: ${24 / 16}rem;
width: ${24 / 16}rem;
margin: ${3 / 16}rem;
height: 2.4rem;
width: 2.4rem;
margin: 0.4rem;
}
`;
@ -22,7 +22,7 @@ export const NavBrand = () => {
} = useConfiguration('LeftMenu');
return (
<Box padding={3}>
<BrandIconWrapper>
<BrandIconWrapper width="3.2rem" height="3.2rem">
<img
src={menu.custom?.url || menu.default}
alt={formatMessage({

View File

@ -0,0 +1,115 @@
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" width={7} height={7}>
{children}
</Flex>
</Tooltip>
);
};
/* -------------------------------------------------------------------------------------------------
* Icon
* -----------------------------------------------------------------------------------------------*/
const IconImpl = ({ children }: { children: React.ReactNode }) => {
if (!children) {
return null;
}
return (
<Flex justifyContent="center" aria-hidden as="span" width={5} height={5}>
{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, ...props }: NavLink.BadgeProps) => {
if (!children) {
return null;
}
return (
<CustomBadge position="absolute" top="-1.2rem" right="-0.4rem" aria-label={label} {...props}>
{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 };

View File

@ -0,0 +1,38 @@
import { House, Lock } from '@strapi/icons';
import { screen, render as renderRTL } from '@tests/utils';
import { NavLink } from '../NavLink';
describe('NavLink', () => {
const Component = () => (
<NavLink.Link to="/test-link">
<NavLink.Tooltip label="test-tooltip">
<>
<NavLink.Icon>
<House data-testid="nav-link-icon" />
</NavLink.Icon>
<NavLink.Badge label="badge label">
<Lock data-testid="nav-link-badge" />
</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();
});
});

View File

@ -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}",