♻️ refactor(print): make print-friendly pages

affected by mui/material-ui#46434
This commit is contained in:
2025-07-03 09:51:07 +02:00
parent cfa31a99a3
commit 76575ead15
6 changed files with 157 additions and 118 deletions
@@ -62,6 +62,9 @@ const CookieConsent = () => {
mb: theme.spacing(1),
p: theme.spacing(3),
zIndex: 9999,
'@media print': {
display: 'none',
},
})}>
<Box>
<SectionSubheader id="cookie-consent-dialog-title" component="h2" variant="h6">
@@ -32,10 +32,16 @@ const CurriculumItem = (props: CurriculumEntryProps) => {
// '& .MuiAccordionSummary-expandIconWrapper .MuiSvgIcon-root': { color: 'primary.dark' }, // use summary hover icon color
},
'&.Mui-expanded': {
bgcolor: 'background.paper', // use summary hover background
borderBottom: '1px solid',
borderTop: '1px solid',
bgcolor: 'background.paper', // use summary hover background
elevation: 1,
'@media print': {
bgcolor: 'background.default',
borderBottom: 0,
borderTop: 0,
elevation: 0,
},
// '& .MuiAccordionSummary-expandIconWrapper .MuiSvgIcon-root': { color: 'primary.dark' }, // use summary hover icon color
},
}}>
@@ -48,6 +54,9 @@ const CurriculumItem = (props: CurriculumEntryProps) => {
},
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
transform: 'rotate(0deg)',
'@media print': {
transform: 'rotate(-90deg)',
},
},
'& .MuiAccordionSummary-content': {
marginLeft: 2,
+11 -1
View File
@@ -14,7 +14,17 @@ type FooterProps = {
const Footer: React.FC<FooterProps> = ({ showCookieConsent = true }) => {
const year = new Date().getFullYear()
return (
<Box sx={{ bgcolor: 'background.paper', p: 6, display: 'flex', alignItems: 'center', flexDirection: 'column' }} component="footer">
<Box
id="footer"
component="footer"
sx={{
bgcolor: 'background.paper',
py: 6,
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
'@media print': { py: 3 },
}}>
<Stack direction="row" gap={2}>
<LinkedInIconLink fontSize="large" href="https://www.linkedin.com/in/m-tartari/" />
<GitHubIconLink fontSize="large" href="https://www.github.com/m-tartari/" />
@@ -1,6 +1,6 @@
import React from 'react'
import { ParallaxBanner, ParallaxProvider } from 'react-scroll-parallax'
import { Box, Grid, IconButton, Typography, useTheme } from '@mui/material'
import { Box, Grid, IconButton, Typography } from '@mui/material'
import { ExpandMore } from '@mui/icons-material'
import { useViewport } from 'components/utils/viewport/index.js'
@@ -125,79 +125,91 @@ const Description = (props: Props) => {
}
}
const DesktopComponent = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
return (
<section ref={ref}>
<ParallaxProvider>
<ParallaxBanner
layers={[
{
// translateY: [0, 30],
// scale: [1, 0.5, 'easeOutCubic'],
// shouldAlwaysCompleteAnimation: true,
image: props.image,
expanded: false,
speed: -20,
},
]}
style={{
// width: '150%',
// marginLeft: '-25%',
minHeight: '100vh',
position: 'relative',
const ProjectSpotlight = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
const { width } = useViewport()
height: '100vh',
overflow: 'hidden',
}}>
<Description {...props} />
{props.scrollTarget && (
<IconButton
size="large"
onClick={() => (props.scrollTarget as React.RefObject<HTMLSelectElement | null>).current?.scrollIntoView()}
sx={{ position: 'absolute', p: 1, bottom: 2, left: '50%', transform: 'translate(-50%, 0)' }}>
<ExpandMore fontSize="large" />
</IconButton>
)}
</ParallaxBanner>
</ParallaxProvider>
</section>
)
})
const MobileComponent = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
return (
<Box component="section">
<Box
ref={ref}
component="img"
sx={{
width: '100%',
height: '100%',
maxHeight: '60vh',
}}
src={props.mobileImage ?? props.image}
/>
<Box ref={ref}>
<Box
component="section"
sx={theme => ({
mt: theme.spacing(-1.05),
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)}`,
display: width < theme.breakpoints.values.md ? 'none' : 'inline',
'@media print': { display: 'none' },
})}>
<Typography variant="h4">{props.title}</Typography>
{props.caption}
<Typography pt={1}>{props.children}</Typography>
<ParallaxProvider>
<ParallaxBanner
layers={[
{
// translateY: [0, 30],
// scale: [1, 0.5, 'easeOutCubic'],
// shouldAlwaysCompleteAnimation: true,
image: props.image,
expanded: false,
speed: -20,
},
]}
style={{
// width: '150%',
// marginLeft: '-25%',
minHeight: '100vh',
position: 'relative',
height: '100vh',
overflow: 'hidden',
}}>
<Description {...props} />
{props.scrollTarget && (
<IconButton
size="large"
onClick={() => (props.scrollTarget as React.RefObject<HTMLSelectElement | null>).current?.scrollIntoView()}
sx={{ position: 'absolute', p: 1, bottom: 2, left: '50%', transform: 'translate(-50%, 0)' }}>
<ExpandMore fontSize="large" />
</IconButton>
)}
</ParallaxBanner>
</ParallaxProvider>
</Box>
<Box
component="section"
sx={theme => ({
display: width >= theme.breakpoints.values.md ? 'none' : 'inline',
'@media print': {
display: 'inline',
height: '100%',
},
})}>
<Box
component="img"
sx={{
width: '100%',
height: '100%',
maxHeight: '60vh',
'@media print': {
maxHeight: '100%',
'-webkit-print-color-adjust': 'exact !important',
'print-color-adjust': 'exact !important',
},
}}
src={props.mobileImage ?? props.image}
/>
<Box
sx={theme => ({
mt: theme.spacing(-1.05),
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)}`,
'@media print': {
backgroundColor: 'background.default',
},
})}>
<Typography variant="h4">{props.title}</Typography>
{props.caption}
<Typography pt={1}>{props.children}</Typography>
</Box>
</Box>
</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
+47 -48
View File
@@ -15,22 +15,30 @@ import {
Stack,
Toolbar,
Typography,
TypographyProps,
styled,
useScrollTrigger,
useTheme,
} from '@mui/material'
import MenuIcon from '@mui/icons-material/Menu'
const AppBarButton = styled(Button<typeof RouterLink>)(({ theme }) => ({
textTransform: 'none',
color: theme.palette.mode === 'dark' ? 'inherit' : 'text.secondary',
':hover': {
backgroundColor: 'transparent',
...(theme.palette.mode === 'dark' && {
const TypographyLink = styled(Typography)(({ theme }) => ({
role: 'link',
textDecoration: 'none',
...(theme.palette.mode === 'dark' && {
color: 'inherit',
':hover': {
color: theme.palette.primary.main,
}),
},
},
}),
...(theme.palette.mode === 'light' && {
color: theme.palette.text.primary,
':hover': {
color: theme.palette.primary.dark,
},
}),
}))
const AppBarLink = (props: TypographyProps & { to: string }) => <TypographyLink component={RouterLink} variant="h6" {...props} />
const DrawerButton = styled(ListItemButton<typeof RouterLink>)(({ theme }) => ({
textTransform: 'none',
color: 'inherit',
@@ -102,6 +110,7 @@ const CustomToolbar: React.FC<CustomToolbarProps> = ({ drawerWidth = 240, window
{...props}
sx={{
backgroundColor: trigger ? 'background.paper' : 'transparent',
'@media print': { backgroundColor: 'background.default' },
...(theme.palette.mode === 'light' && {
backgroundColor: 'hsla(0, 0%, 100%, 0.75)',
backdropFilter: 'blur(8px)',
@@ -115,6 +124,7 @@ const CustomToolbar: React.FC<CustomToolbarProps> = ({ drawerWidth = 240, window
<Toolbar
sx={{
display: 'flex',
alignItems: 'center',
// maxWidth: '100%',
// [theme.breakpoints.up('md')]: { width: theme => theme.breakpoints.values.lg, mx: 'auto' },
}}>
@@ -123,58 +133,47 @@ const CustomToolbar: React.FC<CustomToolbarProps> = ({ drawerWidth = 240, window
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { md: 'none' }, position: 'absolute', backgroundColor: 'primary' }}>
sx={{
mr: 2,
display: { md: 'none' },
position: 'absolute',
backgroundColor: 'primary',
'@media print': { display: 'none' },
}}>
<MenuIcon />
</IconButton>
<AppBarButton
component={RouterLink}
<AppBarLink
to="/"
disableRipple
sx={theme => ({
color: theme.palette.text.primary,
[theme.breakpoints.down('md')]: { mx: 'auto' },
[theme.breakpoints.up('md')]: { mr: 'auto' },
})}>
<Typography variant="h6">Michele Tartari</Typography>
</AppBarButton>
<Stack component="div" direction="row" spacing={2} sx={{ display: { xs: 'none', md: 'flex' } }}>
<AppBarButton component={RouterLink} to="/" disableRipple>
<Typography variant="h6">Home</Typography>
</AppBarButton>
<AppBarButton component={RouterLink} to="/projects" disableRipple>
<Typography variant="h6">Projects</Typography>
</AppBarButton>
<AppBarButton component={RouterLink} to="/curriculum" disableRipple>
<Typography variant="h6">Curriculum</Typography>
</AppBarButton>
<Button
component={RouterLink}
to="/contacts"
color="primary"
variant="contained"
sx={{
textTransform: 'none',
}}>
Michele Tartari
</AppBarLink>
<Stack component="div" direction="row" spacing={2} sx={{ display: { xs: 'none', md: 'flex', alignItems: 'center' } }}>
<AppBarLink to="/">Home</AppBarLink>
<AppBarLink to="/projects">Projects</AppBarLink>
<AppBarLink to="/curriculum">Curriculum</AppBarLink>
<Button component={RouterLink} to="/contacts" color="primary" variant="contained" sx={{ textTransform: 'none' }}>
<Typography variant="h6">Hire me</Typography>
</Button>
</Stack>
</Toolbar>
</AppBar>
<nav>
<Drawer
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
}}>
{drawer}
</Drawer>
</nav>
<Drawer
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
}}>
{drawer}
</Drawer>
</>
)
}
+8 -2
View File
@@ -19,11 +19,17 @@ const Page: React.FC<PageProps> = ({ title, children, showCookieConsent, ...prop
}, [title])
return (
<Box sx={{ flexGrow: 1 }} aria-label="page">
<Box
aria-label="page"
sx={{
'@media print': { backgroundColor: 'background.default' },
flexGrow: 1,
}}>
<Toolbar />
{title && (
<>
<Typography
id="page-title"
variant="h1"
aria-label="page-title"
textAlign="center"
@@ -53,8 +59,8 @@ const Page: React.FC<PageProps> = ({ title, children, showCookieConsent, ...prop
</>
)}
<Container
id="page-content"
component="main"
maxWidth={false}
sx={{
mt: { xs: 8, md: 12 },
mb: 4,