Skip to content

Commit

Permalink
Create ContentSidebar (#674)
Browse files Browse the repository at this point in the history
* Create Right Sidebar

* Create responsive layout for sidebars

* Remove width test from Sidebar.test.tsx

This test doesn't fit well with RTL unit testing, this test case will be
covered later by integration tests.

* Rename RightSidebar to ContentSidebar

* Add ScreenReaderOnly test

* Center SkipNavigation link
  • Loading branch information
negreirosleo authored Sep 21, 2023
1 parent 9498e08 commit ace6bce
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 66 deletions.
4 changes: 4 additions & 0 deletions frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ body {
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));

@media (max-width: 600px) {
flex-direction: column;
}
}

a {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Metadata } from 'next'
import localFont from 'next/font/local'
import { AuthProvider } from '@/app/auth/AuthProvider'
import { Sidebar } from '@/ui/Sidebar/Sidebar'
import { ContentSidebar } from '@/ui/ContentSidebar/ContentSidebar'
import { CssVarsProvider } from '@mui/joy/styles'
import { theme } from '@/ui/theme'
import { Main, SkipNavigation } from '@/ui/SkipNavigation/SkipNavigation'
Expand All @@ -28,6 +29,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Main id="main-content" tabIndex={-1}>
{children}
</Main>
<ContentSidebar>
<div style={{ color: 'black' }}>Right Sidebar</div>
</ContentSidebar>
</CssVarsProvider>
</AuthProvider>
</body>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AuthorizedPage } from '@/app/auth/AuthorizedPage'
export default function Home() {
return (
<AuthorizedPage>
<main>Testing auth</main>
<div>Testing auth</div>
</AuthorizedPage>
)
}
35 changes: 35 additions & 0 deletions frontend/src/ui/CollapseButton/CollapseButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Button from '@mui/joy/Button'
import { ChevronRight16Filled } from '@fluentui/react-icons'
import { ScreenReaderOnly } from '@/ui/ScreenReaderOnly/ScreenReaderOnly'
import { SxProps } from '@mui/joy/styles/types'

type CollapseButtonProps = {
onClick: () => void
sx: SxProps
}

export const CollapseButton = ({ onClick, sx }: CollapseButtonProps) => {
return (
<Button
size="sm"
onClick={onClick}
sx={{
borderRadius: '50%',
bgcolor: 'white',
width: 32,
height: 32,
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
position: 'absolute',
padding: 0,
zIndex: 1,
boxShadow: '0px 6px 6px #00000029',
...sx
}}
>
<ChevronRight16Filled primaryFill="black" />
<ScreenReaderOnly>Expand/collapse menu</ScreenReaderOnly>
</Button>
)
}
26 changes: 26 additions & 0 deletions frontend/src/ui/CollapseButton/__tests__/CollapseButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { render, screen, fireEvent } from '@/test-utils/test-utils'
import { CollapseButton } from '../CollapseButton'

describe('CollapseButton', () => {
it('should have an invisible screen-reader text for the collapse button', () => {
render(<CollapseButton sx={{}} onClick={() => {}} />)

const collapseButton = screen.getByRole('button')

expect(collapseButton).toHaveTextContent('Expand/collapse menu')
})

it('receives an sx to extend component style', () => {
render(<CollapseButton sx={{ top: '60px' }} onClick={() => {}} />)
const collapseButton = screen.getByRole('button')
expect(collapseButton).toHaveStyle({ top: '60px' })
})

it('calls onClick prop when clicked', () => {
const onClick = jest.fn()
render(<CollapseButton sx={{}} onClick={onClick} />)
const collapseButton = screen.getByRole('button')
fireEvent.click(collapseButton)
expect(onClick).toHaveBeenCalled()
})
})
41 changes: 41 additions & 0 deletions frontend/src/ui/ContentSidebar/ContentSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client'

import { useState } from 'react'
import Box from '@mui/joy/Box'
import { CollapseButton } from '../CollapseButton/CollapseButton'

type ContentSidebarProps = {
children: React.ReactNode
}

export const ContentSidebar = ({ children }: ContentSidebarProps) => {
const [expanded, setExpanded] = useState(false)

return (
<Box
sx={{
height: { xs: expanded ? '60px' : '320px', sm: '100vh' },
width: { xs: '100vw', sm: expanded ? '60px' : '320px' },
transition: { xs: 'height 0.6s', sm: 'width 0.6s' },
position: 'relative',
bgcolor: 'white',
border: '1px solid #D2D2D4'
}}
>
<CollapseButton
sx={{
left: { xs: '0px', sm: '-16px' },
right: { xs: '0px', sm: 'unset' },
top: { xs: '-16px', sm: '61px' },
margin: '0 auto',
transform: { xs: 'rotateZ(90deg)', sm: 'rotateZ(180deg)' },
...(expanded && {
transform: { xs: 'rotateZ(-90deg)', sm: 'rotateZ(0deg)' }
})
}}
onClick={() => setExpanded((prevState) => !prevState)}
/>
{children}
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render, screen } from '@/test-utils/test-utils'
import { ScreenReaderOnly } from '../ScreenReaderOnly'

describe('ScreenReaderOnly', () => {
it('renders the component with children', () => {
render(<ScreenReaderOnly>Test text</ScreenReaderOnly>)

expect(screen.getByText('Test text')).toBeInTheDocument()
})
})
18 changes: 10 additions & 8 deletions frontend/src/ui/Sidebar/DarkModeSwitch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SwitchComponentProps = {
}

const TrackText = ({ icon: Icon, children, sx }: SwitchComponentProps) => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: '24px', ...sx }}>
<Box sx={{ display: { xs: 'none', sm: 'flex' }, alignItems: 'center', gap: '24px', ...sx }}>
<Icon color="#00396d" />
<Typography sx={{ color: '#b3cfe9' }}>{children}</Typography>
</Box>
Expand All @@ -36,7 +36,9 @@ const SwitchThumb = ({ icon: Icon, children }: SwitchComponentProps) => (
}}
>
<Icon color="#b3cfe9" />
<Typography sx={{ color: '#F0F3F7' }}>{children}</Typography>
<Typography sx={{ display: { xs: 'none', sm: 'block' }, color: '#F0F3F7' }}>
{children}
</Typography>
</Box>
)

Expand Down Expand Up @@ -69,12 +71,6 @@ export const DarkModeSwitch = ({ sx }: DarkModeSwitchProps) => {
}
}}
sx={{
'--Switch-thumbWidth': '148px',
'--Switch-thumbSize': '30px',
'--Switch-trackWidth': '260px',
'--Switch-thumbRadius': '20px',
'--Switch-trackHeight': '40px',
'--Switch-trackRadius': '25px',
'--Switch-thumbBackground': '#00396d',
'--Switch-trackBackground': '#030D1A',
'&:hover': {
Expand All @@ -87,6 +83,12 @@ export const DarkModeSwitch = ({ sx }: DarkModeSwitchProps) => {
'--Switch-trackBackground': '#030D1A'
}
},
'--Switch-thumbWidth': { xs: '40px', sm: '148px' },
'--Switch-thumbSize': { xs: '20px', sm: '30px' },
'--Switch-trackWidth': { xs: '60px', sm: '260px' },
'--Switch-thumbRadius': { xs: '', sm: '20px' },
'--Switch-trackHeight': { xs: '', sm: '40px' },
'--Switch-trackRadius': { xs: '', sm: '25px' },
...sx
}}
/>
Expand Down
79 changes: 45 additions & 34 deletions frontend/src/ui/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,60 @@

import { useState } from 'react'
import Stack from '@mui/joy/Stack'
import Button from '@mui/joy/Button'
import Typography from '@mui/joy/Typography'
import Box from '@mui/joy/Box'
import Image from 'next/image'
import {
ChevronRight16Filled,
TaskListSquareAdd24Filled,
Beach24Filled,
DataArea24Filled,
DataPie24Filled
} from '@fluentui/react-icons'
import smallLogo from '@/assets/images/small_logo.png'
import fullLogo from '@/assets/images/full_logo.png'
import { styled } from '@mui/joy/styles'
import Link from 'next/link'
import { DarkModeSwitch } from './DarkModeSwitch'
import { ScreenReaderOnly } from '@/ui/ScreenReaderOnly/ScreenReaderOnly'
import { CollapseButton } from '../CollapseButton/CollapseButton'
import { SxProps } from '@mui/joy/styles/types'

export const Sidebar = () => {
const [expanded, setExpanded] = useState(false)

return (
<Box
sx={{
height: '100vh',
width: expanded ? 336 : 73,
transition: 'width 0.6s',
height: { xs: expanded ? '73px' : '280px', sm: '100vh' },
width: { xs: '100vw', sm: expanded ? 336 : 73 },
transition: { xs: 'height 0.6s', sm: 'width 0.6s' },
position: 'relative',
bgcolor: '#001C37',
padding: '22px 16px 18px'
}}
component="aside"
>
<Button
size="sm"
onClick={() => setExpanded((prevState) => !prevState)}
<CollapseButton
sx={{
borderRadius: '50%',
bgcolor: 'white',
width: 32,
height: 32,
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
position: 'absolute',
right: '-16px',
top: '61px',
padding: 0,
zIndex: 1,
boxShadow: '0px 6px 6px #00000029',
right: { xs: '0px', sm: '-16px' },
left: { xs: '0px', sm: 'unset' },
top: { xs: 'unset', sm: '61px' },
bottom: { xs: '-16px', sm: 'unset' },
margin: '0 auto',
transform: { xs: 'rotateZ(-90deg)', sm: 'rotateZ(0deg)' },
...(expanded && {
transform: 'rotateY(180deg)'
transform: { xs: 'rotateZ(90deg)', sm: 'rotateZ(180deg)' }
})
}}
>
<ChevronRight16Filled primaryFill="black" />
<ScreenReaderOnly>Expand/collapse menu</ScreenReaderOnly>
</Button>
<Stack sx={{ overflow: 'hidden', height: '100%' }} component="nav">
<Logo height={32} src={expanded ? fullLogo : smallLogo} alt="Igalia Logo" />
onClick={() => setExpanded((prevState) => !prevState)}
/>
<Box sx={navGridStyle} component="nav">
<Logo height={32} src={fullLogo} alt="Igalia Logo" />
<Stack
sx={{
svg: { minWidth: '32px' },
whiteSpace: 'nowrap',
padding: '0 4px',
listStyleType: 'none'
listStyleType: 'none',
gridArea: 'nav'
}}
component="ul"
spacing={2}
Expand Down Expand Up @@ -100,25 +88,48 @@ export const Sidebar = () => {
<DarkModeSwitch
sx={{
mt: 'auto',
alignSelf: 'flex-start',
justifySelf: { xs: 'flex-end', sm: 'flex-start' },
transition: 'transform 0.6s',
transformOrigin: '20px',
mr: '4px',
gridArea: 'switch',
...(!expanded && {
transform: 'rotate(-90deg)'
transform: { sm: 'rotate(-90deg)' }
})
}}
/>
</Stack>
</Box>
</Box>
)
}

const Logo = styled(Image)`
margin-bottom: 50px;
grid-area: 'logo';
padding: 0 4px;
`

const NavLink = styled(Link)`
display: flex;
gap: 30px;
align-items: center;
`

const navGridStyle: SxProps = {
overflow: 'hidden',
height: '100%',
display: 'grid',
gridTemplateAreas: {
xs: `
'logo switch'
'nav nav'`,
sm: `
'logo'
'nav'
'switch'
`
},
gridTemplateRows: '32px 1fr',
gridTemplateColumns: '50%',
rowGap: '20px'
}
22 changes: 1 addition & 21 deletions frontend/src/ui/Sidebar/__tests__/Sidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Sidebar } from '../Sidebar'
import { render, screen, fireEvent } from '@/test-utils/test-utils'
import { render, screen } from '@/test-utils/test-utils'

describe('Sidebar', () => {
it('renders the Igalia logo', () => {
Expand All @@ -22,24 +22,4 @@ describe('Sidebar', () => {

expect(screen.getByRole('checkbox')).toBeInTheDocument()
})

it('expand and collapses', () => {
render(<Sidebar />)

const expandButton = screen.getByRole('button')

expect(screen.getByRole('complementary')).toHaveStyle({ width: '73px' })
fireEvent.click(expandButton)
expect(screen.getByRole('complementary')).toHaveStyle({ width: '336px' })
fireEvent.click(expandButton)
expect(screen.getByRole('complementary')).toHaveStyle({ width: '73px' })
})

it('should have an invisible screen-reader text for the collapse button', () => {
render(<Sidebar />)

const expandButton = screen.getByRole('button')

expect(expandButton).toHaveTextContent('Expand/collapse menu')
})
})
10 changes: 8 additions & 2 deletions frontend/src/ui/SkipNavigation/SkipNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ export const SkipNavigation = styled('a')`
z-index: 1;
&:focus {
right: 5px;
left: 0;
right: 0;
top: 5px;
left: unset;
margin: 0 auto;
width: fit-content;
}
`

export const Main = styled('main')`
width: 100%;
height: 100%;
padding: 30px 0;
&:focus {
outline: none;
}
Expand Down

0 comments on commit ace6bce

Please sign in to comment.