66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
'use client'
|
|
|
|
import { LazyMotion, domAnimation, m, useReducedMotion } from 'framer-motion'
|
|
import type ImageType from '@/types/image'
|
|
import type ProjectType from '@/types/project'
|
|
import ProjectImage from '../ProjectImage'
|
|
import { getAnimationProps, moveInBottom } from '../Transitions'
|
|
import ProjectLinks from './Links'
|
|
import ProjectTechstack from './Techstack'
|
|
import styles from './index.module.css'
|
|
|
|
const containerVariants = {
|
|
enter: {
|
|
transition: {
|
|
staggerChildren: 0.2
|
|
}
|
|
}
|
|
}
|
|
|
|
export default function Project({
|
|
project
|
|
}: {
|
|
project: Partial<ProjectType>
|
|
}) {
|
|
const { title, descriptionHtml, images, links, techstack } = project
|
|
const shouldReduceMotion = useReducedMotion()
|
|
const animationProps = getAnimationProps(shouldReduceMotion || false)
|
|
|
|
return (
|
|
<article className={styles.project}>
|
|
<LazyMotion features={domAnimation}>
|
|
<m.header
|
|
variants={containerVariants}
|
|
{...animationProps}
|
|
className={styles.intro}
|
|
>
|
|
<m.h1 variants={moveInBottom} className={styles.headerTitle}>
|
|
{title}
|
|
</m.h1>
|
|
|
|
<m.div
|
|
variants={moveInBottom}
|
|
className={styles.description}
|
|
dangerouslySetInnerHTML={{ __html: descriptionHtml ?? '' }}
|
|
/>
|
|
</m.header>
|
|
</LazyMotion>
|
|
|
|
{images?.map((image: ImageType, i: number) => (
|
|
<ProjectImage
|
|
className={styles.fullContainer}
|
|
image={image}
|
|
alt={`Showcase image no. ${i + 1} for ${title}`}
|
|
key={i}
|
|
sizes="100vw"
|
|
/>
|
|
))}
|
|
|
|
<footer className={styles.meta}>
|
|
{links && <ProjectLinks links={links} />}
|
|
{techstack && <ProjectTechstack techstack={techstack} />}
|
|
</footer>
|
|
</article>
|
|
)
|
|
}
|