Merge pull request #12 from m-tartari/refactor/home/mobile

♻️ refactor: make mobile friendly homepage
This commit is contained in:
2024-02-18 15:46:40 +01:00
committed by GitHub
20 changed files with 216 additions and 4460 deletions
+7
View File
@@ -16,3 +16,10 @@ updates:
patterns: patterns:
- 'vitest' - 'vitest'
- '@vitest*' - '@vitest*'
typescript-eslint:
patterns:
- '@typescript-eslint*'
mui:
patterns:
- '@mui/material'
- '@mui/icon-material'
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -13,7 +13,7 @@ const Hero = (props: { scrollTarget?: React.ForwardedRef<HTMLSelectElement> }) =
minHeight: '100vh', minHeight: '100vh',
boxShadow: '0 0.25em 0.5em 0 rgba(0, 0, 0, 0.25)', boxShadow: '0 0.25em 0.5em 0 rgba(0, 0, 0, 0.25)',
backgroundImage: 'url("images/banner-blur.jpg")', backgroundImage: 'url("images/banner-blur.webp")',
backgroundPosition: 'center center', backgroundPosition: 'center center',
backgroundAttachment: 'fixed', backgroundAttachment: 'fixed',
backgroundSize: 'cover', backgroundSize: 'cover',
@@ -2,6 +2,7 @@ import React from 'react'
import { ParallaxBanner, ParallaxProvider } from 'react-scroll-parallax' import { ParallaxBanner, ParallaxProvider } from 'react-scroll-parallax'
import { Box, Grid, IconButton, Typography, useTheme } from '@mui/material' import { Box, Grid, IconButton, Typography, useTheme } from '@mui/material'
import { ExpandMore } from '@mui/icons-material' import { ExpandMore } from '@mui/icons-material'
import { useViewport } from '../../utils/viewport'
type AnchorType = 'left' | 'top' | 'right' | 'bottom' type AnchorType = 'left' | 'top' | 'right' | 'bottom'
@@ -10,6 +11,7 @@ type Props = {
title: string title: string
caption: React.ReactNode caption: React.ReactNode
children: React.ReactNode children: React.ReactNode
mobileImage?: string
ref?: React.ForwardedRef<HTMLSelectElement> ref?: React.ForwardedRef<HTMLSelectElement>
anchor?: AnchorType anchor?: AnchorType
scrollTarget?: React.ForwardedRef<HTMLSelectElement> scrollTarget?: React.ForwardedRef<HTMLSelectElement>
@@ -124,7 +126,7 @@ const Description = (props: Props) => {
} }
} }
const ProjectSpotlight = React.forwardRef<HTMLSelectElement, Props>((props, ref) => { const DesktopComponent = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
return ( return (
<section ref={ref}> <section ref={ref}>
<ParallaxProvider> <ParallaxProvider>
@@ -163,4 +165,51 @@ const ProjectSpotlight = React.forwardRef<HTMLSelectElement, Props>((props, ref)
) )
}) })
const MobileComponent = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
const theme = useTheme()
return (
<>
<Box
ref={ref}
component="img"
sx={{
width: '100%',
height: '100%',
maxHeight: '60vh',
}}
src={props.mobileImage ?? props.image}
/>
<Box
sx={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderTopStyle: 'solid',
borderTopWidth: theme.spacing(0.5),
borderTopColor: theme.palette.primary.main,
p: `${theme.spacing(7)} ${theme.spacing(5)} ${theme.spacing(5.5)} ${theme.spacing(5)}`,
}}>
<Grid container spacing={2} maxWidth="xl">
<Grid item xs={12} md={4}>
<Typography variant="h4">{props.title}</Typography>
{props.caption}
</Grid>
<Grid item component={Typography} xs={12} md={8}>
{props.children}
</Grid>
</Grid>
</Box>
</>
)
})
const ProjectSpotlight = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
const { width } = useViewport()
const theme = useTheme()
return width < theme.breakpoints.values.md ? <MobileComponent {...props} ref={ref} /> : <DesktopComponent {...props} ref={ref} />
})
export default ProjectSpotlight export default ProjectSpotlight
@@ -5,9 +5,23 @@ import { renderWithRouter as render } from 'components/utils/tests'
import MainPage from '.' import MainPage from '.'
// Tests // Tests
describe('Main page', async () => { describe('Main page', () => {
it('Should render the page correctly', async () => { it('Should render the page correctly on desktop', async () => {
// Setup await render(<MainPage />)
// Make sure the page title is correct
expect(screen.getByText('Robotics Engineer')).toBeInTheDocument()
// Make sure the project spotlights are present
expect(screen.getByText('LINFA: An Intuitive Block-Programming Interface for Reconfigurable Robots')).toBeInTheDocument()
expect(screen.getByText("Revamping HHCM's Modular: Swift Generation of Modular Robot Models")).toBeInTheDocument()
expect(screen.getByText('Automated Actuators and Robotic Modules Calibration')).toBeInTheDocument()
expect(screen.getByText('Voice Controlled Mobile Robot for Indoor Applications')).toBeInTheDocument()
})
it('Should render the page correctly on mobile', async () => {
// Set the window size to mobile (Galaxy Note 20 Android 11)
window.innerWidth = 412
window.innerHeight = 915
await render(<MainPage />) await render(<MainPage />)
// Make sure the page title is correct // Make sure the page title is correct
+101 -95
View File
@@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { Box, Typography } from '@mui/material' import { Box, Typography } from '@mui/material'
import { ViewportProvider } from 'components/utils/viewport'
import { AcademyIconLink, DescriptionIconLink, GitHubIconLink, VideoIconLink } from 'components/atoms' import { AcademyIconLink, DescriptionIconLink, GitHubIconLink, VideoIconLink } from 'components/atoms'
import { Footer, Hero, Toobar, ProjectSpotlight } from 'components/molecules' import { Footer, Hero, Toobar, ProjectSpotlight } from 'components/molecules'
@@ -15,102 +16,107 @@ const MainPage = () => {
const refWUTThesis = React.useRef<HTMLSelectElement>(null) const refWUTThesis = React.useRef<HTMLSelectElement>(null)
return ( return (
<Box aria-label="page" sx={{ flexGrow: 1 }}> <ViewportProvider>
<Toobar position="absolute" sx={{ backgroundColor: 'transparent' }} /> <Box aria-label="page" sx={{ flexGrow: 1 }}>
<Hero scrollTarget={refIITLinfa} /> <Toobar position="absolute" sx={{ backgroundColor: 'transparent' }} />
{/* 1 IIT - Linfa */} <Hero scrollTarget={refIITLinfa} />
<ProjectSpotlight {/* 1 IIT - Linfa */}
ref={refIITLinfa} <ProjectSpotlight
scrollTarget={refIITModular} ref={refIITLinfa}
anchor="bottom" scrollTarget={refIITModular}
image="images/IIT_Linfa.png" anchor="bottom"
title="LINFA: An Intuitive Block-Programming Interface for Reconfigurable Robots" image="images/IIT_Linfa.webp"
caption={ title="LINFA: An Intuitive Block-Programming Interface for Reconfigurable Robots"
<> caption={
<VideoIconLink size="small" fontSize="small" href="https://www.linkedin.com/feed/update/urn:li:activity:7034480841569284096/" /> <>
<Typography component="span" variant="caption"> <VideoIconLink size="small" fontSize="small" href="https://www.linkedin.com/feed/update/urn:li:activity:7034480841569284096/" />
Software Engineer @ IIT <Typography component="span" variant="caption">
</Typography> Software Engineer @ IIT
</> </Typography>
}> </>
This project aims to simplify the control, monitoring, and programming of reconfigurable robots through an intuitive block-programming }>
interface. It includes a front-end web app, built with TypeScript and React, allowing users to effortlessly change robot operating modes and This project aims to simplify the control, monitoring, and programming of reconfigurable robots through an intuitive block-programming
settings, monitor the robot's state, and assemble programs by dragging and dropping code blocks representing various robot capabilities. interface. It includes a front-end web app, built with TypeScript and React, allowing users to effortlessly change robot operating modes and
Additionally, back-end services, developed with TypeScript and Python, translate these programs into formats compatible with the underlying settings, monitor the robot's state, and assemble programs by dragging and dropping code blocks representing various robot capabilities.
systems and manage mission execution. The project emphasizes extensibility, enabling users with Python experience to integrate custom blocks Additionally, back-end services, developed with TypeScript and Python, translate these programs into formats compatible with the underlying
and capabilities. Automated CI/CD pipelines further streamline integration and deployment processes. systems and manage mission execution. The project emphasizes extensibility, enabling users with Python experience to integrate custom blocks
</ProjectSpotlight> and capabilities. Automated CI/CD pipelines further streamline integration and deployment processes.
{/* 2 IIT - Modular */} </ProjectSpotlight>
<ProjectSpotlight {/* 2 IIT - Modular */}
ref={refIITModular} <ProjectSpotlight
scrollTarget={refIITCalibration} ref={refIITModular}
anchor="right" scrollTarget={refIITCalibration}
// anchor="left" anchor="right"
image="images/IIT_Modular.png" // anchor="left"
title="Revamping HHCM's Modular: Swift Generation of Modular Robot Models" image="images/IIT_Modular.png"
caption={ mobileImage="images/IIT_Modular_Mobile.webp"
<> title="Revamping HHCM's Modular: Swift Generation of Modular Robot Models"
<GitHubIconLink size="small" fontSize="small" href="https://github.com/ADVRHumanoids/motor_calibration" /> caption={
<Typography component="span" variant="caption"> <>
Software Engineer @ IIT <GitHubIconLink size="small" fontSize="small" href="https://github.com/ADVRHumanoids/motor_calibration" />
</Typography> <Typography component="span" variant="caption">
</> Software Engineer @ IIT
}> </Typography>
This project focused on overhauling HHCM's Modular, enhancing its graphical interface, API, and deployment pipeline. Modular serves as a web </>
application for the swift generation of modular robot models, with an offline approach (Building Mode) enabling users to set up robots in a }>
virtual environment by selecting and assembling reconfigurable modules, immediately visualized in 3D. Additionally, an online approach This project focused on overhauling HHCM's Modular, enhancing its graphical interface, API, and deployment pipeline. Modular serves as a web
(Discovery Mode) allows users to query the EtherCAT master for network topology, recognizing and displaying robots built from physical modules application for the swift generation of modular robot models, with an offline approach (Building Mode) enabling users to set up robots in a
in 3D. The system seamlessly produces URDF, SRDF, and a full ROS package that can then be utilized for simulating and controlling the robot. virtual environment by selecting and assembling reconfigurable modules, immediately visualized in 3D. Additionally, an online approach
</ProjectSpotlight> (Discovery Mode) allows users to query the EtherCAT master for network topology, recognizing and displaying robots built from physical
{/* 3 IIT - Motor Calibration */} modules in 3D. The system seamlessly produces URDF, SRDF, and a full ROS package that can then be utilized for simulating and controlling
<ProjectSpotlight the robot.
ref={refIITCalibration} </ProjectSpotlight>
scrollTarget={refWUTThesis} {/* 3 IIT - Motor Calibration */}
anchor="left" <ProjectSpotlight
image="images/IIT_Modules.jpg" ref={refIITCalibration}
title="Automated Actuators and Robotic Modules Calibration" scrollTarget={refWUTThesis}
caption={ anchor="left"
<> image="images/IIT_Modules.webp"
<GitHubIconLink size="small" fontSize="small" href="https://github.com/ADVRHumanoids/motor_calibration" /> title="Automated Actuators and Robotic Modules Calibration"
<Typography component="span" variant="caption"> caption={
Embedded Engineer @ IIT <>
</Typography> <GitHubIconLink size="small" fontSize="small" href="https://github.com/ADVRHumanoids/motor_calibration" />
</> <Typography component="span" variant="caption">
}> Embedded Engineer @ IIT
This project focused on automating the calibration of EtherCAT actuators and robotic modules, aiming for a fully automated procedure for newly </Typography>
assembled actuators. The process involved testing the PDO, conducting phase angle calibration, torque sensor calibration, ripple and </>
position-dependent torque offset calibration, inertia and friction identification, and frequency response calibration. The goal was to }>
optimize motor performance and collect necessary data for accurate characterization, with results stored centrally and presented in a This project focused on automating the calibration of EtherCAT actuators and robotic modules, aiming for a fully automated procedure for
comprehensive PDF report. newly assembled actuators. The process involved testing the PDO, conducting phase angle calibration, torque sensor calibration, ripple and
</ProjectSpotlight> position-dependent torque offset calibration, inertia and friction identification, and frequency response calibration. The goal was to
{/* 4 WUT - Master Thesis */} optimize motor performance and collect necessary data for accurate characterization, with results stored centrally and presented in a
<ProjectSpotlight comprehensive PDF report.
ref={refWUTThesis} </ProjectSpotlight>
anchor="bottom" {/* 4 WUT - Master Thesis */}
image="images/thesis.jpg" <ProjectSpotlight
title="Voice Controlled Mobile Robot for Indoor Applications" ref={refWUTThesis}
caption={ anchor="bottom"
<> image="images/thesis.jpg"
<AcademyIconLink size="small" fontSize="small" href="https://doi.org/10.1007/978-3-030-58380-4_7" /> mobileImage="images/thesis.webp"
title="Voice Controlled Mobile Robot for Indoor Applications"
caption={
<>
<AcademyIconLink size="small" fontSize="small" href="https://doi.org/10.1007/978-3-030-58380-4_7" />
<DescriptionIconLink <DescriptionIconLink
size="small" size="small"
fontSize="small" fontSize="small"
href="https://drive.google.com/file/d/1wBfvAzy9N8uChNxNj9Kd_hcvI0Qq3uQj/view?usp=sharing" href="https://drive.google.com/file/d/1wBfvAzy9N8uChNxNj9Kd_hcvI0Qq3uQj/view?usp=sharing"
/> />
<Typography component="span" variant="caption" color="text.secondary"> <Typography component="span" variant="caption" color="text.secondary">
Master Thesis @ WUT Master Thesis @ WUT
</Typography> </Typography>
</> </>
}> }>
This thesis proposes a design for a small mobile robot controlled by voice. Firstly a preliminary analysis of the state of art of human-robot This thesis proposes a design for a small mobile robot controlled by voice. Firstly a preliminary analysis of the state of art of
interaction has been conducted. Then, an analysis of the equipment selected took place, and, later, appropriate methodologies for voice human-robot interaction has been conducted. Then, an analysis of the equipment selected took place, and, later, appropriate methodologies
recognition and user detection have been evaluated for this specific case. Finally, an overview of the complete software architecture of the for voice recognition and user detection have been evaluated for this specific case. Finally, an overview of the complete software
system was given with three possible structures and their comparison. The results obtained show both the feasibility of using low power boards architecture of the system was given with three possible structures and their comparison. The results obtained show both the feasibility of
and some of their limitations. using low power boards and some of their limitations.
</ProjectSpotlight> </ProjectSpotlight>
<Footer /> <Footer />
</Box> </Box>
</ViewportProvider>
) )
} }
@@ -0,0 +1,21 @@
import React from 'react'
import viewportContext from './viewportContext'
const ViewportProvider = (props: { children: React.ReactNode }) => {
const [width, setWidth] = React.useState(window.innerWidth)
const [height, setHeight] = React.useState(window.innerHeight)
const handleWindowResize = () => {
setWidth(window.innerWidth)
setHeight(window.innerHeight)
}
React.useEffect(() => {
window.addEventListener('resize', handleWindowResize)
return () => window.removeEventListener('resize', handleWindowResize)
}, [])
return <viewportContext.Provider value={{ width, height }}>{props.children}</viewportContext.Provider>
}
export default ViewportProvider
+3
View File
@@ -0,0 +1,3 @@
export { default as viewportContext } from './viewportContext'
export { default as ViewportProvider } from './ViewportProvider'
export { default as useViewport } from './useViewport'
@@ -0,0 +1,10 @@
import React from 'react'
import viewportContext from './viewportContext'
const useViewport = () => {
const { width, height } = React.useContext(viewportContext)
return { width, height }
}
export default useViewport
@@ -0,0 +1,6 @@
import React from 'react'
type Viewport = { width: number; height: number }
const viewportContext = React.createContext<Viewport>({ width: window.innerWidth, height: window.innerHeight })
export default viewportContext