✨ feat(molecules): add ProjectSpotlight
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import React from 'react'
|
||||
import { ParallaxBanner, ParallaxProvider } from 'react-scroll-parallax'
|
||||
import { Box, Grid, IconButton, Typography, useTheme } from '@mui/material'
|
||||
import { ExpandMore } from '@mui/icons-material'
|
||||
|
||||
type AnchorType = 'left' | 'top' | 'right' | 'bottom'
|
||||
|
||||
type Props = {
|
||||
image: string
|
||||
title: string
|
||||
caption: React.ReactNode
|
||||
children: React.ReactNode
|
||||
ref?: React.ForwardedRef<HTMLSelectElement>
|
||||
anchor?: AnchorType
|
||||
scrollTarget?: React.ForwardedRef<HTMLSelectElement>
|
||||
}
|
||||
|
||||
const Description = (props: Props) => {
|
||||
const theme = useTheme()
|
||||
|
||||
switch (props.anchor) {
|
||||
case 'bottom':
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
position: 'absolute',
|
||||
bgcolor: 'background.default',
|
||||
opacity: 0.9,
|
||||
bottom: '0',
|
||||
|
||||
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>
|
||||
)
|
||||
case 'top':
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
position: 'absolute',
|
||||
bgcolor: 'background.default',
|
||||
opacity: 0.9,
|
||||
top: '0',
|
||||
ml: 'auto',
|
||||
borderBottomWidth: theme.spacing(0.5),
|
||||
// borderTopWidth: '0.35em',
|
||||
borderBottomStyle: 'solid',
|
||||
borderBottomColor: theme.palette.primary.main,
|
||||
p: `${theme.spacing(5)} ${theme.spacing(5)} ${theme.spacing(3)} ${theme.spacing(5)}`,
|
||||
// p: '5.1em 3.1em 3.1em 3.1em',
|
||||
}}>
|
||||
<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>
|
||||
)
|
||||
case 'right':
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: '102%',
|
||||
width: '28em',
|
||||
position: 'absolute',
|
||||
bgcolor: 'background.default',
|
||||
opacity: 0.9,
|
||||
right: '0',
|
||||
borderLeftWidth: theme.spacing(0.5),
|
||||
// borderLeftWidth: '0.35em',
|
||||
borderLeftStyle: 'solid',
|
||||
borderLeftColor: theme.palette.primary.main,
|
||||
p: `${theme.spacing(3)} ${theme.spacing(5)} ${theme.spacing(5)} ${theme.spacing(5)}`,
|
||||
// p: '5.1em 3.1em 3.1em 3.1em',
|
||||
}}>
|
||||
<Typography variant="h4">{props.title}</Typography>
|
||||
{props.caption}
|
||||
<Typography mt={3}>{props.children}</Typography>
|
||||
</Box>
|
||||
)
|
||||
case 'left':
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: '102%',
|
||||
width: '28em',
|
||||
position: 'absolute',
|
||||
bgcolor: 'background.default',
|
||||
opacity: 0.9,
|
||||
left: '0',
|
||||
borderRightWidth: theme.spacing(0.5),
|
||||
// borderLeftWidth: '0.35em',
|
||||
borderRightStyle: 'solid',
|
||||
borderRightColor: theme.palette.primary.main,
|
||||
p: `${theme.spacing(3)} ${theme.spacing(5)} ${theme.spacing(5)} ${theme.spacing(5)}`,
|
||||
// p: '5.1em 3.1em 3.1em 3.1em',
|
||||
}}>
|
||||
<Typography variant="h4">{props.title}</Typography>
|
||||
{props.caption}
|
||||
<Typography mt={3}>{props.children}</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const ProjectSpotlight = React.forwardRef<HTMLSelectElement, Props>((props, ref) => {
|
||||
const executeScroll = () => {
|
||||
if (typeof props.scrollTarget !== 'undefined') {
|
||||
const target = props.scrollTarget as React.MutableRefObject<HTMLSelectElement | null>
|
||||
target.current?.scrollIntoView()
|
||||
}
|
||||
}
|
||||
// run this function from an event handler or an effect to execute scroll
|
||||
|
||||
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',
|
||||
|
||||
height: '100vh',
|
||||
overflow: 'hidden',
|
||||
}}>
|
||||
<Description {...props} />
|
||||
{props.scrollTarget && (
|
||||
<IconButton
|
||||
size="large"
|
||||
onClick={executeScroll}
|
||||
sx={{ position: 'absolute', p: 1, bottom: 2, left: '50%', transform: 'translate(-50%, 0)' }}>
|
||||
<ExpandMore fontSize="large" />
|
||||
</IconButton>
|
||||
)}
|
||||
</ParallaxBanner>
|
||||
</ParallaxProvider>
|
||||
</section>
|
||||
)
|
||||
})
|
||||
|
||||
export default ProjectSpotlight
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './ProjectSpotlight'
|
||||
@@ -2,4 +2,5 @@ export { default as Toobar } from './Toobar'
|
||||
export { default as Footer } from './Footer'
|
||||
|
||||
export { default as CurriculumItem } from './CurriculumItem'
|
||||
export { default as ProjectSpotlight } from './ProjectSpotlight'
|
||||
export { default as Project } from './Project'
|
||||
|
||||
Reference in New Issue
Block a user