diff --git a/src/app/(public)/projects/page.tsx b/src/app/(public)/projects/page.tsx index b43ffb0..6fe61d4 100644 --- a/src/app/(public)/projects/page.tsx +++ b/src/app/(public)/projects/page.tsx @@ -26,7 +26,7 @@ const ProjectsPage = async () => {

Projects

-
+
{projects.map((project) => ( ))} diff --git a/src/components/organisms/projects/ProjectCard.tsx b/src/components/organisms/projects/ProjectCard.tsx index b9e120c..b066697 100644 --- a/src/components/organisms/projects/ProjectCard.tsx +++ b/src/components/organisms/projects/ProjectCard.tsx @@ -4,10 +4,11 @@ import { Button } from '@mui/material'; import Image from 'next/image'; import { useTheme } from 'next-themes'; import * as React from 'react'; -import { useState } from 'react'; +import { RefObject, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { IconContext } from 'react-icons'; -import { AiOutlineCloud } from 'react-icons/ai'; +import { AiFillGithub, AiOutlineCloud } from 'react-icons/ai'; +import { BiNews } from 'react-icons/bi'; import { DiAndroid } from 'react-icons/di'; import { FaAngular, @@ -32,11 +33,9 @@ import { SiTypescript, SiVercel, } from 'react-icons/si'; -import { TbBrandKotlin } from 'react-icons/tb'; +import { TbBrandKotlin, TbWorldShare } from 'react-icons/tb'; import ReactMarkdown from 'react-markdown'; -import clsxm from '@/lib/clsxm'; - import UnstyledLink from '@/components/links/UnstyledLink'; import { Project } from '@/types/Project'; @@ -51,95 +50,138 @@ const ProjectCard = ({ project }: ProjectCardProps) => { const { theme } = useTheme(); const [showDescription, setShowDescription] = useState(false); + const [cardHeight, setCardHeight] = useState(null); + const cardRef: RefObject = useRef(null); + + useEffect(() => { + if (cardRef.current && !cardHeight) { + // Calculate and set the initial height of the card content + setCardHeight(cardRef.current.offsetHeight); + } + + window.addEventListener('resize', () => setCardHeight(null)); + }, [cardHeight]); const toggleDescription = () => { setShowDescription(!showDescription); + + if (!showDescription) { + // If showing long description, set the card height to the long description's height + setCardHeight(cardRef.current ? cardRef.current.offsetHeight : null); + } else { + // If showing short description, set the card height back to the initial height + setCardHeight(null); + } }; const iconColor = theme === 'dark' ? 'white' : 'black'; return ( -
-
-

{project.title}

- -
- {project.shortDescription} -
+
+ {!showDescription && ( +
+

+ {project.title} +

+ +
+ {project.shortDescription} +
-
- - {project.tools.map((tool: string) => { - const IconComponent = iconMapping[tool]; - return ( - IconComponent && ( - - - - ) - ); - })} - -
+
+ + {project.tools.map((tool: string) => { + const IconComponent = toolIconMapping[tool]; + return ( + IconComponent && ( + + + + ) + ); + })} + +
+ +
+ {project.image.alternativeText +
-
- {project.image.alternativeText +
+ {project.longDescription && ( + + )} + + {!project.longDescription && ( + {t('projects.readMore')} + )} + +
+ + {Object.entries(project.links).map(([key, url]) => { + const Icon = linkIconMapping[key]; + return ( + + + + ); + })} + +
+
+ )} -
+ {showDescription && ( +
{project.longDescription && ( - - )} - - {!project.longDescription && ( - {t('projects.readMore')} +
+ {project.longDescription} +
)} -
-
- -
- {project.longDescription && ( -
- {project.longDescription} +
+
- )} -
-
-
+ )}
); }; export default ProjectCard; -const iconMapping: Record = { +const toolIconMapping: Record = { android: DiAndroid, angular: FaAngular, aws: FaAws, @@ -162,3 +204,9 @@ const iconMapping: Record = { typescript: SiTypescript, vercel: SiVercel, }; + +const linkIconMapping: Record = { + article: BiNews, + github: AiFillGithub, + publicUrl: TbWorldShare, +};