Implement new UI

This commit is contained in:
Charles Bochet
2023-04-09 16:43:43 +02:00
parent 58d8d7c090
commit f25f80c199
69 changed files with 473 additions and 1121 deletions

View File

@ -1,40 +1,44 @@
import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
type OwnProps = {
label: string;
to: string;
active?: boolean;
icon: IconProp;
};
type StyledItemProps = {
active?: boolean;
};
const StyledItem = styled.button`
const StyledItem = styled.button<StyledItemProps>`
display: flex;
height: 60px;
background: inherit;
align-items: center;
padding-left: 10px;
padding-right: 10px;
margin-left: 10px;
margin-right: 10px;
font-size: 16px;
margin-bottom: -2px;
border: none;
font-size: 12px;
cursor: pointer;
color: ${(props: StyledItemProps) => (props.active ? 'black' : '#2e3138')};
font-weight: ${(props: StyledItemProps) =>
props.active ? 'bold' : 'inherit'};
border: 0;
border-bottom: ${(props: StyledItemProps) =>
props.active ? '2px solid black' : '2px solid #eaecee'};
&:hover {
border-bottom: 2px solid #2e3138;
background: ${(props) => (props.active ? 'rgba(0, 0, 0, 0.04)' : 'inherit')};
padding-top: 4px;
padding-bottom: 4px;
padding-left: 4px;
font-family: 'Inter';
color: ${(props) =>
props.active ? props.theme.text100 : props.theme.text60};
border-radius: 4px;
:hover {
background: rgba(0, 0, 0, 0.04);
color: ${(props) => props.theme.text100};
}
`;
function NavItem({ label, to, active }: OwnProps) {
const StyledItemLabel = styled.div`
display: flex;
margin-left: 8px;
`;
function NavItem({ label, icon, to, active }: OwnProps) {
const navigate = useNavigate();
return (
@ -45,7 +49,8 @@ function NavItem({ label, to, active }: OwnProps) {
active={active}
aria-selected={active}
>
{label}
<FontAwesomeIcon icon={icon} />
<StyledItemLabel>{label}</StyledItemLabel>
</StyledItem>
);
}

View File

@ -0,0 +1,22 @@
import styled from '@emotion/styled';
type OwnProps = {
label: string;
};
const StyledTitle = styled.div`
display: flex;
text-transform: uppercase;
color: ${(props) => props.theme.text30};
font-size: 12px;
font-weight: 600;
padding-top: 4px;
padding-bottom: 4px;
padding-left: 4px;
`;
function NavTitle({ label }: OwnProps) {
return <StyledTitle>{label}</StyledTitle>;
}
export default NavTitle;

View File

@ -1,64 +1,62 @@
import styled from '@emotion/styled';
import { useMatch, useResolvedPath } from 'react-router-dom';
import { User } from '../../interfaces/user.interface';
import { Workspace } from '../../interfaces/workspace.interface';
import NavItem from './NavItem';
import ProfileContainer from './ProfileContainer';
import NavTitle from './NavTitle';
import WorkspaceContainer from './WorkspaceContainer';
import { faUser } from '@fortawesome/free-regular-svg-icons';
import { faBuilding } from '@fortawesome/free-regular-svg-icons';
const NavbarContainer = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
padding-left: 12px;
height: 58px;
border-bottom: 2px solid #eaecee;
flex-direction: column;
background: ${(props) => props.theme.noisyBackground};
min-width: 220px;
padding: 8px;
`;
const NavItemsContainer = styled.div`
display: flex;
flex-direction: row;
flex-direction: column;
margin-top: 40px;
`;
type OwnProps = {
user?: User;
workspace?: Workspace;
};
function Navbar({ user }: OwnProps) {
function Navbar({ workspace }: OwnProps) {
return (
<>
<NavbarContainer>
{workspace && <WorkspaceContainer workspace={workspace} />}
<NavItemsContainer>
<NavTitle label="Workspace" />
<NavItem
label="Inbox"
to="/"
label="People"
to="/people"
icon={faUser}
active={
!!useMatch({
path: useResolvedPath('/').pathname,
path: useResolvedPath('/people').pathname,
end: true,
})
}
/>
<NavItem
label="Contacts"
to="/contacts"
label="Companies"
to="/companies"
icon={faBuilding}
active={
!!useMatch({
path: useResolvedPath('/contacts').pathname,
end: true,
})
}
/>
<NavItem
label="Insights"
to="/insights"
active={
!!useMatch({
path: useResolvedPath('/insights').pathname,
path: useResolvedPath('/companies').pathname,
end: true,
})
}
/>
</NavItemsContainer>
<ProfileContainer user={user} />
</NavbarContainer>
</>
);

View File

@ -1,63 +0,0 @@
import styled from '@emotion/styled';
import { User } from '../../interfaces/user.interface';
type OwnProps = {
user?: User;
};
const StyledContainer = styled.button`
display: flex;
height: 60px;
background: inherit;
align-items: center;
padding-left: 10px;
padding-right: 10px;
margin-left: 10px;
margin-right: 10px;
font-size: 14px;
margin-bottom: -2px;
cursor: pointer;
border: 0;
`;
const StyledInfoContainer = styled.div`
display: flex;
flex-direction: column;
`;
const StyledEmail = styled.div`
display: flex;
`;
const StyledAvatar = styled.div`
display: flex;
width: 40px;
height: 40px;
border-radius: 40px;
background: black;
font-size: 20px;
color: white;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 16px;
flex-shrink: 0;
`;
function ProfileContainer({ user }: OwnProps) {
return (
<StyledContainer>
<StyledAvatar>
{user?.first_name
.split(' ')
.map((n) => n[0])
.join('')}
</StyledAvatar>
<StyledInfoContainer>
<StyledEmail>{user?.email}</StyledEmail>
</StyledInfoContainer>
</StyledContainer>
);
}
export default ProfileContainer;

View File

@ -0,0 +1,51 @@
import styled from '@emotion/styled';
import { Workspace } from '../../interfaces/workspace.interface';
type OwnProps = {
workspace: Workspace;
};
const StyledContainer = styled.button`
display: inline-flex;
width: min-content;
height: 34px;
align-items: center;
cursor: pointer;
border: 0;
background: inherit;
border: 1px solid ${(props) => props.theme.primaryBorder};
border-radius: 4px;
padding: 8px;
margin-left: 4px;
`;
type StyledLogoProps = {
logo: string;
};
const StyledLogo = styled.div<StyledLogoProps>`
background: url(${(props) => props.logo});
background-size: cover;
width: 16px;
height: 16px;
border-radius: 2px;
`;
const StyledName = styled.div`
margin-left: 4px;
font-family: 'Inter';
font-weight: 500;
font-size: 14px;
font-color: ${(props) => props.theme.text0};
`;
function ProfileContainer({ workspace }: OwnProps) {
return (
<StyledContainer>
<StyledLogo logo={workspace.logo}></StyledLogo>
<StyledName>{workspace?.name}</StyledName>
</StyledContainer>
);
}
export default ProfileContainer;

View File

@ -1,6 +1,9 @@
import { MemoryRouter } from 'react-router-dom';
import { faUser } from '@fortawesome/free-regular-svg-icons';
import { ThemeProvider } from '@emotion/react';
import NavItem from '../../../layout/navbar/NavItem';
import { lightTheme } from '../../styles/themes';
export default {
title: 'NavItem',
@ -8,13 +11,17 @@ export default {
};
export const NavItemDefault = () => (
<MemoryRouter>
<NavItem label="Test" to="/test" />
</MemoryRouter>
<ThemeProvider theme={lightTheme}>
<MemoryRouter>
<NavItem label="Test" to="/test" icon={faUser} />
</MemoryRouter>
</ThemeProvider>
);
export const NavItemActive = () => (
<MemoryRouter initialEntries={['/test']}>
<NavItem label="Test" to="/test" active={true} />
</MemoryRouter>
<ThemeProvider theme={lightTheme}>
<MemoryRouter initialEntries={['/test']}>
<NavItem label="Test" to="/test" active={true} icon={faUser} />
</MemoryRouter>
</ThemeProvider>
);

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,16 @@
import { render } from '@testing-library/react';
import { NavbarOnInsights } from '../__stories__/Navbar.stories';
import { NavbarOnCompanies } from '../__stories__/Navbar.stories';
it('Checks the NavItem renders', () => {
const { getByRole } = render(<NavbarOnInsights />);
const { getByRole } = render(<NavbarOnCompanies />);
expect(getByRole('button', { name: 'Insights' })).toHaveAttribute(
expect(getByRole('button', { name: 'Companies' })).toHaveAttribute(
'aria-selected',
'true',
);
expect(getByRole('button', { name: 'Inbox' })).toHaveAttribute(
expect(getByRole('button', { name: 'People' })).toHaveAttribute(
'aria-selected',
'false',
);