mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 10:23:34 +00:00
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:
parent
4300e8f16c
commit
53cf1f19cc
@ -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
|
||||
|
||||
@ -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({
|
||||
|
||||
115
packages/core/admin/admin/src/components/MainNav/NavLink.tsx
Normal file
115
packages/core/admin/admin/src/components/MainNav/NavLink.tsx
Normal 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 };
|
||||
@ -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();
|
||||
});
|
||||
});
|
||||
@ -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}",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user