diff --git a/src/components/atoms/IconButton/IconButton.ts b/src/components/atoms/IconButton/IconButton.ts
deleted file mode 100644
index 982c1c3..0000000
--- a/src/components/atoms/IconButton/IconButton.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { IconButton as MuiIconButton, styled } from '@mui/material'
-
-const IconButton = styled(MuiIconButton)(({ theme }) => ({
- ':hover': {
- backgroundColor: 'transparent',
- color: theme.palette.primary.main,
- },
-}))
-export default IconButton
diff --git a/src/components/atoms/IconButton/index.ts b/src/components/atoms/IconButton/index.ts
deleted file mode 100644
index 9de6d2c..0000000
--- a/src/components/atoms/IconButton/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './IconButton'
diff --git a/src/components/atoms/IconLinks/IconLinks.test.tsx b/src/components/atoms/IconLinks/IconLinks.test.tsx
index 5bfb814..efef427 100644
--- a/src/components/atoms/IconLinks/IconLinks.test.tsx
+++ b/src/components/atoms/IconLinks/IconLinks.test.tsx
@@ -1,9 +1,8 @@
// IconLinks.test.tsx
import { render, screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
-import * as IconLinks from '.'
+import * as IconLinks from './index.js'
const labels: { [key: string]: string } = {
DescriptionIconLink: 'Doc-button',
@@ -18,8 +17,6 @@ const labels: { [key: string]: string } = {
vi.stubGlobal('open', vi.fn())
describe('IconLinks', () => {
- const open = vi.spyOn(window, 'open')
-
const defaultProps = {
href: 'https://test.com',
fontSize: 'large' as const,
@@ -28,20 +25,10 @@ describe('IconLinks', () => {
describe.each(Object.entries(IconLinks))('%s', (name, Icon) => {
test('renders correctly and without crashing', async () => {
render()
- await userEvent.click(screen.getByLabelText(labels[name]))
- expect(open).toHaveBeenCalledTimes(1)
- expect(open).toHaveBeenLastCalledWith(defaultProps.href, '_blank')
- })
-
- test('stops propagation when the icon button is clicked', async () => {
- const onClick = vi.fn()
- render(
-
-
-
- )
- await userEvent.click(screen.getByLabelText(labels[name]))
- expect(onClick).not.toHaveBeenCalled()
+ const link = screen.getByLabelText(labels[name])
+ expect(link).toHaveAttribute('href', defaultProps.href)
+ expect(link).toHaveAttribute('target', '_blank')
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer')
})
test("renders the badge when 'index' is provided", () => {
diff --git a/src/components/atoms/IconLinks/index.ts b/src/components/atoms/IconLinks/index.ts
deleted file mode 100644
index 5e3a24e..0000000
--- a/src/components/atoms/IconLinks/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './IconLinks'
diff --git a/src/components/atoms/IconLinks/IconLinks.tsx b/src/components/atoms/IconLinks/index.tsx
similarity index 63%
rename from src/components/atoms/IconLinks/IconLinks.tsx
rename to src/components/atoms/IconLinks/index.tsx
index 2994577..627e92e 100644
--- a/src/components/atoms/IconLinks/IconLinks.tsx
+++ b/src/components/atoms/IconLinks/index.tsx
@@ -1,10 +1,7 @@
import { Email, LinkedIn, GitHub, Description, OndemandVideo, School, OpenInNew, OpenInBrowser } from '@mui/icons-material'
-import { Badge, IconButtonProps, SvgIcon } from '@mui/material'
+import { Badge, Link, LinkProps, SvgIcon } from '@mui/material'
-import IconButton from '../IconButton'
-
-interface IconLinkProps extends IconButtonProps {
- href: string
+interface IconLinkProps extends LinkProps {
fontSize?: 'small' | 'large' | 'medium' | 'inherit'
index?: number
}
@@ -13,25 +10,46 @@ interface IconWrapperProps extends IconLinkProps {
Icon: typeof SvgIcon
}
-const IconWrapper = ({ index, href: to, fontSize, Icon, ...props }: IconWrapperProps) => {
+const IconWrapper: React.FC = ({ index, fontSize, Icon, sx, ...props }) => {
if (typeof index === 'undefined') {
return (
- {
- e.stopPropagation()
- window.open(to, '_blank')
- }}
+ ({
+ color: 'inherit',
+ ':hover': {
+ backgroundColor: 'transparent',
+ color: theme.palette.primary.main,
+ },
+ ...sx,
+ })}
{...props}>
-
+
)
}
return (
- window.open(to, '_blank')} {...props}>
+ ({
+ color: 'inherit',
+ ':hover': {
+ backgroundColor: 'transparent',
+ color: theme.palette.primary.main,
+ },
+ ...sx,
+ })}
+ {...props}>
-
+
)
}
diff --git a/src/components/atoms/Publication/Publication.test.tsx b/src/components/atoms/Publication/Publication.test.tsx
index 99de24c..53b7deb 100644
--- a/src/components/atoms/Publication/Publication.test.tsx
+++ b/src/components/atoms/Publication/Publication.test.tsx
@@ -1,11 +1,9 @@
import { render, screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
import { Box } from '@mui/material'
-import Publication from '.'
+import Publication from './index.js'
vi.stubGlobal('open', vi.fn())
-const open = vi.spyOn(window, 'open')
describe('Publication component', () => {
const defaultProps = {
@@ -13,10 +11,10 @@ describe('Publication component', () => {
authors: 'Test Author',
title: 'Test Title',
location: 'Test Location',
- link: 'https://test.com',
+ href: 'https://test.com',
}
test('renders without crashing and displays the correct year, authors, title, and location', () => {
- render()
+ render()
expect(screen.getByText(defaultProps.year)).toBeInTheDocument()
expect(screen.getByText(defaultProps.title)).toBeInTheDocument()
expect(screen.getByText(defaultProps.authors, { exact: false })).toBeInTheDocument()
@@ -26,8 +24,10 @@ describe('Publication component', () => {
test('opens the correct link when the link button is clicked', async () => {
render()
- await userEvent.click(screen.getByRole('button'))
- expect(open).toHaveBeenCalledWith(defaultProps.link, '_blank')
+ const link = screen.getByRole('link')
+ expect(link).toHaveAttribute('href', defaultProps.href)
+ expect(link).toHaveAttribute('target', '_blank')
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer')
})
test('renders correctly with a custom base component', () => {
diff --git a/src/components/atoms/Publication/Publication.tsx b/src/components/atoms/Publication/Publication.tsx
deleted file mode 100644
index d02dafa..0000000
--- a/src/components/atoms/Publication/Publication.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react'
-import { Box, SxProps, Theme, Typography, TypographyProps } from '@mui/material'
-import { ExternalIconLink } from '..'
-
-type AwardEntryProps = {
- year: string | number
- title: string
- authors: React.ReactNode
- location: string
- link?: string
- titleProps?: TypographyProps
- Component?: React.ElementType
- sx?: SxProps
-}
-
-const Publication = ({ Component = Box, ...props }: AwardEntryProps) => {
- return (
-
-
-
- {props.year}
-
-
- {props.authors},{' '}
-
- {props.title}
-
- , In: {props.location}
- {typeof props.link !== 'undefined' && }
-
-
-
- )
-}
-
-export default Publication
diff --git a/src/components/atoms/Publication/index.tsx b/src/components/atoms/Publication/index.tsx
index 869b92d..baa3742 100644
--- a/src/components/atoms/Publication/index.tsx
+++ b/src/components/atoms/Publication/index.tsx
@@ -1 +1,37 @@
-export { default } from './Publication'
+import React from 'react'
+import { Box, SxProps, Theme, Typography, TypographyProps } from '@mui/material'
+
+import { ExternalIconLink } from 'components/atoms/IconLinks/index.js'
+
+type AwardEntryProps = {
+ year: string | number
+ title: string
+ authors: React.ReactNode
+ location: string
+ href?: string
+ titleProps?: TypographyProps
+ Component?: React.ElementType
+ sx?: SxProps
+}
+
+const Publication = ({ Component = Box, ...props }: AwardEntryProps) => {
+ return (
+
+
+
+ {props.year}
+
+
+ {props.authors},{' '}
+
+ {props.title}
+
+ , In: {props.location}
+ {typeof props.href !== 'undefined' && }
+
+
+
+ )
+}
+
+export default Publication
diff --git a/src/components/atoms/index.ts b/src/components/atoms/index.ts
index b984195..39badb5 100644
--- a/src/components/atoms/index.ts
+++ b/src/components/atoms/index.ts
@@ -2,5 +2,4 @@ export { default as Award } from './Award'
export { default as Extracurricular } from './Extracurricular'
export { default as Publication } from './Publication'
-export { default as IconLinks } from './IconButton'
export * from './IconLinks'
diff --git a/src/components/molecules/Footer/Footer.tsx b/src/components/molecules/Footer/Footer.tsx
index 308e2df..cbbf388 100644
--- a/src/components/molecules/Footer/Footer.tsx
+++ b/src/components/molecules/Footer/Footer.tsx
@@ -6,10 +6,10 @@ const Footer = () => {
const year = new Date().getFullYear()
return (
-
-
-
-
+
+
+
+
© {year} Michele Tartari. All rights reserved.
diff --git a/src/components/molecules/Hero/Hero.tsx b/src/components/molecules/Hero/Hero.tsx
index daf1578..31c1161 100644
--- a/src/components/molecules/Hero/Hero.tsx
+++ b/src/components/molecules/Hero/Hero.tsx
@@ -44,28 +44,14 @@ const Hero = (props: { scrollTarget?: React.ForwardedRef }) =
},
})}>
- {/*
- Michele Tartari
- Robotics Engineer
- */}
-
- Robotics Engineer
-
-
+ Robotics Engineer
+
See some of my works below. Send a message to get in touch.
-
-
-
-
+
+
+
+
}) =
{props.scrollTarget && (
(props.scrollTarget as React.MutableRefObject).current?.scrollIntoView()}
- sx={{ display: { xs: 'none', md: 'block' }, position: 'absolute', p: 1, bottom: 3 }}>
+ onClick={() => (props.scrollTarget as React.RefObject).current?.scrollIntoView()}
+ sx={{ position: 'absolute', p: 1, bottom: 2, left: '50%', transform: 'translate(-50%, 0)' }}>
)}
diff --git a/src/components/molecules/Project/Project.tsx b/src/components/molecules/Project/Project.tsx
index d673ec4..ae11c41 100644
--- a/src/components/molecules/Project/Project.tsx
+++ b/src/components/molecules/Project/Project.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { Accordion, AccordionDetails, AccordionSummary, Typography } from '@mui/material'
+import { Accordion, AccordionDetails, AccordionSummary, Stack, Typography } from '@mui/material'
import { ExpandMore as ExpandIcon } from '@mui/icons-material'
interface ProjectProps {
@@ -54,7 +54,9 @@ const Project = (props: ProjectProps) => {
{props.title}
- {props.subtitle}
+
+ {props.subtitle}
+
{props.children}
diff --git a/src/components/molecules/ProjectSpotlight/ProjectSpotlight.tsx b/src/components/molecules/ProjectSpotlight/ProjectSpotlight.tsx
index 89c69f7..05d2d3c 100644
--- a/src/components/molecules/ProjectSpotlight/ProjectSpotlight.tsx
+++ b/src/components/molecules/ProjectSpotlight/ProjectSpotlight.tsx
@@ -153,7 +153,7 @@ const DesktopComponent = React.forwardRef((props, ref)
{props.scrollTarget && (
(props.scrollTarget as React.MutableRefObject).current?.scrollIntoView()}
+ onClick={() => (props.scrollTarget as React.RefObject).current?.scrollIntoView()}
sx={{ position: 'absolute', p: 1, bottom: 2, left: '50%', transform: 'translate(-50%, 0)' }}>
diff --git a/src/components/pages/ContactPage/ContactPage.test.tsx b/src/components/pages/ContactPage/ContactPage.test.tsx
index 41b806d..e1f381d 100644
--- a/src/components/pages/ContactPage/ContactPage.test.tsx
+++ b/src/components/pages/ContactPage/ContactPage.test.tsx
@@ -1,41 +1,37 @@
import { screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
-import { renderWithRouter as render } from 'components/utils/tests'
-
-import ContactPage from '.'
+import { renderWithRouter as render } from 'components/utils/tests/index.js'
+import ContactPage from './index.js'
vi.stubGlobal('open', vi.fn())
describe('ContactPage', () => {
- const open = vi.spyOn(window, 'open')
-
test('renders without crashing and displays the correct contact methods', () => {
render()
expect(screen.getAllByText('Contacts')).toHaveLength(2) // Page title and the Appbar drawer link
- expect(screen.getByLabelText('Email button')).toBeInTheDocument()
- expect(screen.getByLabelText('LinkedIn button')).toBeInTheDocument()
- expect(screen.getByLabelText('GitHub button')).toBeInTheDocument()
+ expect(screen.getByLabelText('Email link')).toBeInTheDocument()
+ expect(screen.getByLabelText('LinkedIn link')).toBeInTheDocument()
+ expect(screen.getByLabelText('GitHub link')).toBeInTheDocument()
})
- test('opens the correct link when the email button is clicked', async () => {
+ test.each([
+ {
+ label: 'Email link',
+ href: 'mailto:info@m-tartari.eu',
+ },
+ // {
+ // label: 'LinkedIn link',
+ // href: 'https://www.linkedin.com/in/m-tartari/',
+ // },
+ // {
+ // label: 'GitHub link',
+ // href: 'https://www.github.com/m-tartari/',
+ // },
+ ])('leads to the right place when the $label is clicked', ({ label, href }) => {
render()
-
- await userEvent.click(screen.getByLabelText('Email button'))
- expect(open).toHaveBeenCalledWith('mailto:info@m-tartari.eu', '_blank')
- })
-
- test('opens the correct link when the LinkedIn button is clicked', async () => {
- render()
-
- await userEvent.click(screen.getByLabelText('LinkedIn button'))
- expect(open).toHaveBeenCalledWith('https://www.linkedin.com/in/m-tartari/', '_blank')
- })
-
- test('opens the correct link when the GitHub button is clicked', async () => {
- render()
-
- await userEvent.click(screen.getByLabelText('GitHub button'))
- expect(open).toHaveBeenCalledWith('https://www.github.com/m-tartari/', '_blank')
+ const link = screen.getByLabelText(label)
+ expect(link).toHaveAttribute('href', href)
+ expect(link).toHaveAttribute('target', '_blank')
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer')
})
})
diff --git a/src/components/pages/ContactPage/ContactPage.tsx b/src/components/pages/ContactPage/ContactPage.tsx
index a626e34..6dcbf0b 100644
--- a/src/components/pages/ContactPage/ContactPage.tsx
+++ b/src/components/pages/ContactPage/ContactPage.tsx
@@ -1,20 +1,41 @@
-import { List, ListItem, ListItemButton as MuiListItemButton, Typography, styled } from '@mui/material'
-import { Drafts as DraftsIcon, LinkedIn as LinkedInIcon, GitHub as GitHubIcon } from '@mui/icons-material'
+import { Link, List, ListItem, Stack, Typography } from '@mui/material'
+import DraftsIcon from '@mui/icons-material/Drafts'
+import LinkedInIcon from '@mui/icons-material/LinkedIn'
+import GitHubIcon from '@mui/icons-material/GitHub'
import { Page } from 'components/templates'
-const ListItemButton = styled(MuiListItemButton)(({ theme }) => ({
- h6: {
- color: theme.palette.text.secondary,
- },
- ':hover': {
- backgroundColor: 'transparent',
- color: theme.palette.primary.main,
- h6: {
- color: theme.palette.primary.dark,
- },
- },
-}))
+interface ListItemProps {
+ children?: React.ReactNode
+ href?: string
+}
+const ListItemLink: React.FC = ({ children, ...props }) => (
+
+ ({
+ color: 'inherit',
+
+ h6: {
+ color: theme.palette.text.secondary,
+ },
+ ':hover': {
+ backgroundColor: 'transparent',
+ color: theme.palette.primary.main,
+ h6: {
+ color: theme.palette.primary.dark,
+ },
+ },
+ })}>
+
+ {children}
+
+
+
+)
const ContactPage = () => {
return (
@@ -23,32 +44,26 @@ const ContactPage = () => {
Feel free to contact me using any of the following:
-
- window.open('mailto:info@m-tartari.eu', '_blank')}>
-
-
- info
-
- @m-tartari.eu
-
-
-
-
- window.open('https://www.linkedin.com/in/m-tartari/', '_blank')}>
-
-
- m-tartari
-
-
-
-
- window.open('https://www.github.com/m-tartari/', '_blank')}>
-
-
- m-tartari
-
-
-
+
+
+
+ info
+
+ @m-tartari.eu
+
+
+
+
+
+ m-tartari
+
+
+
+
+
+ m-tartari
+
+
)
diff --git a/src/components/pages/CurriculumPage/CurriculumPage.tsx b/src/components/pages/CurriculumPage/CurriculumPage.tsx
index 7aa5e5b..dafb63d 100644
--- a/src/components/pages/CurriculumPage/CurriculumPage.tsx
+++ b/src/components/pages/CurriculumPage/CurriculumPage.tsx
@@ -29,7 +29,12 @@ const Curriculum = () => {
Co-founded{' '}
-
+
MindHub Ferrara
, the first programming school for children in Ferrara, under the{' '}
@@ -132,9 +137,9 @@ const Curriculum = () => {
{/* id="WUT" */}
-
+
Credential ID: EZ34GWQLRHEG
-
+
@@ -414,7 +419,7 @@ const Curriculum = () => {
}
location="ROMANSY 23 - Robot Design, Dynamics and Control. CISM International Centre for Mechanical Sciences (Courses and Lectures), vol
601. Springer, Cham."
- link="https://doi.org/10.1007/978-3-030-58380-4_7"
+ href="https://doi.org/10.1007/978-3-030-58380-4_7"
/>
diff --git a/src/components/pages/MainPage/MainPage.tsx b/src/components/pages/MainPage/MainPage.tsx
index 7950659..c53d1a9 100644
--- a/src/components/pages/MainPage/MainPage.tsx
+++ b/src/components/pages/MainPage/MainPage.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { Box, Typography } from '@mui/material'
+import { Box, Stack, Typography } from '@mui/material'
import { ViewportProvider } from 'components/utils/viewport'
import { AcademyIconLink, DescriptionIconLink, ExternalAppIconLink, GitHubIconLink, VideoIconLink } from 'components/atoms'
@@ -28,12 +28,10 @@ const MainPage = () => {
image="images/IIT_Linfa.webp"
title="LINFA: An Intuitive Block-Programming Interface for Reconfigurable Robots"
caption={
- <>
-
-
- Software Engineer @ IIT
-
- >
+
+
+ Software Engineer @ IIT
+
}>
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
@@ -52,13 +50,11 @@ const MainPage = () => {
mobileImage="images/IIT_Modular_Mobile.webp"
title="Revamping HHCM's Modular: Swift Generation of Modular Robot Models"
caption={
- <>
-
-
-
- Software Engineer @ IIT
-
- >
+
+
+
+ Software Engineer @ IIT
+
}>
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
@@ -75,12 +71,10 @@ const MainPage = () => {
image="images/IIT_Modules.webp"
title="Automated Actuators and Robotic Modules Calibration"
caption={
- <>
-
-
- Embedded Engineer @ IIT
-
- >
+
+
+ Embedded Engineer @ IIT
+
}>
This project focused on automating the calibration of EtherCAT actuators and robotic modules, aiming for a fully automated procedure for
newly assembled actuators. The process involved testing the PDO, conducting phase angle calibration, torque sensor calibration, ripple and
@@ -96,18 +90,11 @@ const MainPage = () => {
mobileImage="images/thesis.webp"
title="Voice Controlled Mobile Robot for Indoor Applications"
caption={
- <>
-
-
-
-
- Master Thesis @ WUT
-
- >
+
+
+
+ Master Thesis @ WUT
+
}>
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 interaction has been conducted. Then, an analysis of the equipment selected took place, and, later, appropriate methodologies
diff --git a/src/components/pages/ProjectsPage/ProjectsPage.test.tsx b/src/components/pages/ProjectsPage/ProjectsPage.test.tsx
index a0922aa..8fed1d8 100644
--- a/src/components/pages/ProjectsPage/ProjectsPage.test.tsx
+++ b/src/components/pages/ProjectsPage/ProjectsPage.test.tsx
@@ -1,12 +1,9 @@
import { screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
-
-import { renderWithRouter as render } from 'components/utils/tests'
+import { renderWithRouter as render } from 'components/utils/tests/index.js'
import ProjectsPage from '.'
vi.stubGlobal('open', vi.fn())
-const open = vi.spyOn(window, 'open')
describe('ProjectsPage component', () => {
test('renders without crashing and displays the correct project titles', () => {
render()
@@ -25,8 +22,10 @@ describe('ProjectsPage component', () => {
test('opens the correct links when the link buttons are clicked', async () => {
render()
- // test one of the many links
- await userEvent.click(screen.getByLabelText('Video-button'))
- expect(open).toHaveBeenLastCalledWith('https://www.linkedin.com/feed/update/urn:li:activity:7034480841569284096/', '_blank')
+ // inspect one of the many links
+ const link = screen.getByLabelText('Video-button')
+ expect(link).toHaveAttribute('href', 'https://www.linkedin.com/feed/update/urn:li:activity:7034480841569284096/')
+ expect(link).toHaveAttribute('target', '_blank')
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer')
})
})
diff --git a/src/components/pages/ProjectsPage/ProjectsPage.tsx b/src/components/pages/ProjectsPage/ProjectsPage.tsx
index 6c3475c..a5f410d 100644
--- a/src/components/pages/ProjectsPage/ProjectsPage.tsx
+++ b/src/components/pages/ProjectsPage/ProjectsPage.tsx
@@ -22,13 +22,13 @@ const ProjectsPage = () => {
Software Engineer @ IIT
{/* */}
-
+
Software Engineer @ IIT
>
@@ -49,9 +49,9 @@ const ProjectsPage = () => {
Software Engineer @ IIT
-
-
-
+
+
+
Software Engineer @ IIT
>
@@ -70,14 +70,14 @@ const ProjectsPage = () => {
Master Thesis @ WUT
-
+
-
+
Master Thesis @ WUT
>
@@ -93,15 +93,12 @@ const ProjectsPage = () => {
-
-
- >
+
}>
The aim of this project was to prove the possibility to design an autonomous mobile robot whose task was to recharge electric cars in a
@@ -112,11 +109,11 @@ const ProjectsPage = () => {
title="Mobile Robot Self-Localization"
subtitle={
<>
-
+
>
@@ -130,16 +127,11 @@ const ProjectsPage = () => {
title="Onychophora-Inspired Firefighting Robot"
subtitle={
<>
-
+
>
@@ -155,13 +147,13 @@ const ProjectsPage = () => {
<>
{/* */}
{
+ <>
+
+
+ >
}>
This project concerns the design and optimization of a 3RRR planar parallel manipulator using MATLAB and CATIA
@@ -189,7 +189,7 @@ const ProjectsPage = () => {
title="Simple Swarm"
subtitle={
<>
-
+
>
}>
@@ -201,7 +201,7 @@ const ProjectsPage = () => {
subtitle={
<>
{
subtitle={
<>
{
Embedded Engineer @ IIT
-
-
+
+
Embedded Engineer @ IIT
>
@@ -268,12 +263,12 @@ const ProjectsPage = () => {
Bachelor Thesis @ TONGJI
-
+
Bachelor Thesis @ TONGJI
>
@@ -290,12 +285,12 @@ const ProjectsPage = () => {
Bachelor Thesis @ UNIBO
-
+
Bachelor Thesis @ UNIBO
>
@@ -308,14 +303,9 @@ const ProjectsPage = () => {
title="Control of a Nonlinear System"
subtitle={
<>
-
+
{
title="Multi-Body System's Kinematic Analysis"
subtitle={
<>
-
+
{
+
}>
Several Signal processing projects developed using MATLAB.
+
}>
Several real-time systems' projects developed using C++ and OIL, and run using Trampoline RTOS on a Teensy board.
@@ -373,7 +358,7 @@ const ProjectsPage = () => {
+
}>
A collection of pdf and CAD models to create late XIV century furniture and medieval camp equipment. These objects are being realized by{' '}
@@ -386,7 +371,7 @@ const ProjectsPage = () => {
+
}>
Publishes all photos from a{' '}