Skip to content

Commit

Permalink
feat: slide longer description up on "read more" click
Browse files Browse the repository at this point in the history
  • Loading branch information
martapanc committed Sep 12, 2023
1 parent ead1bba commit d18d336
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 135 deletions.
22 changes: 0 additions & 22 deletions public/contacts/page.tsx

This file was deleted.

6 changes: 2 additions & 4 deletions src/app/(public)/contacts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ export const metadata = {
description: 'Contacts page',
};

const ProjectsPage = async () => {
const ContactsPage = async () => {
return (
<main className='min-h-main'>
<section>
<div className='layout relative flex flex-col py-12'>
<h1 className='mb-5'>Contacts</h1>

<div className='grid grid-cols-1 gap-5 md:grid-cols-3 md:gap-6'></div>
</div>
</section>
</main>
);
};

export default ProjectsPage;
export default ContactsPage;
6 changes: 2 additions & 4 deletions src/app/(public)/cv/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ export const metadata = {
description: 'CV page',
};

const ProjectsPage = async () => {
const CVPage = async () => {
return (
<main className='min-h-main'>
<section>
<div className='layout relative flex flex-col py-12'>
<h1 className='mb-5'>CV</h1>

<div className='grid grid-cols-1 gap-5 md:grid-cols-3 md:gap-6'></div>
</div>
</section>
</main>
);
};

export default ProjectsPage;
export default CVPage;
6 changes: 2 additions & 4 deletions src/app/(public)/uses/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ export const metadata = {
description: 'Uses page',
};

const ProjectsPage = async () => {
const UsesPage = async () => {
return (
<main className='min-h-main'>
<section>
<div className='layout relative flex flex-col py-12'>
<h1 className='mb-5'>Uses</h1>

<div className='grid grid-cols-1 gap-5 md:grid-cols-3 md:gap-6'></div>
</div>
</section>
</main>
);
};

export default ProjectsPage;
export default UsesPage;
201 changes: 100 additions & 101 deletions src/components/organisms/projects/ProjectCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ import {
import { TbBrandKotlin, TbWorldShare } from 'react-icons/tb';
import ReactMarkdown from 'react-markdown';

import './projectCard.css';

import clsxm from '@/lib/clsxm';

import UnstyledLink from '@/components/links/UnstyledLink';

import { Project } from '@/types/Project';
Expand All @@ -49,132 +53,127 @@ const ProjectCard = ({ project }: ProjectCardProps) => {

const { theme } = useTheme();

const [showDescription, setShowDescription] = useState(false);
const [cardHeight, setCardHeight] = useState<number | null>(null);
const [cardHeight, setCardHeight] = useState('100%');
const cardRef: RefObject<HTMLDivElement> = useRef(null);

const [activeDiv, setActiveDiv] = useState('first');
const toggleDiv = () => {
setActiveDiv(activeDiv === 'first' ? 'second' : 'first');
};

useEffect(() => {
if (cardRef.current && !cardHeight) {
if (cardRef.current) {
// 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);
setCardHeight(cardRef.current.clientHeight + 'px');
}
};
}, []);

const iconColor = theme === 'dark' ? 'white' : 'black';

return (
<div
ref={cardRef}
className='rounded p-4 shadow-md dark:bg-slate-900 dark:drop-shadow-md'
style={
showDescription ? { height: `${cardHeight}px` } : { height: `100%` }
}
className='rounded p-4 shadow-md bg-slate-50 dark:bg-slate-900 dark:drop-shadow-md'
style={{ height: cardHeight }}
>
{!showDescription && (
<div className='flex flex-col my-1 h-full'>
<h3 className='mb-2' aria-label='Project title'>
{project.title}
</h3>
<div
className={clsxm(
'flex flex-col my-1',
activeDiv === 'first' ? 'show' : 'hide',
)}
>
<h3 className='mb-2' aria-label='Project title'>
{project.title}
</h3>

<div
className='text-justify md:font-light md:text-sm mb-auto'
aria-label='Project short description'
>
<ReactMarkdown>{project.shortDescription}</ReactMarkdown>
</div>

<div
className='text-justify md:font-light md:text-sm mb-auto'
aria-label='Project short description'
>
<ReactMarkdown>{project.shortDescription}</ReactMarkdown>
</div>
<div
className='flex flex-row mb-3 justify-start'
aria-label='Project tools'
>
<IconContext.Provider value={{ color: iconColor, size: '24px' }}>
{project.tools.map((tool: string) => {
const IconComponent = toolIconMapping[tool];
return (
IconComponent && (
<span key={tool} className='me-1' aria-label={tool}>
<IconComponent />
</span>
)
);
})}
</IconContext.Provider>
</div>

<div className='flex flex-row mb-3' aria-label='Project tools'>
<div className='w-full mb-3' aria-label='Project image'>
<Image
className='w-full h-auto'
src={project.image.url}
alt={project.image.alternativeText || 'Project Image'}
width={320}
height={180}
/>
</div>

<div className='flex flex-row justify-between' aria-label='Read More'>
<div className='flex flex-row p-2'>
<IconContext.Provider value={{ color: iconColor, size: '24px' }}>
{project.tools.map((tool: string) => {
const IconComponent = toolIconMapping[tool];
{Object.entries(project.links).map(([key, url]) => {
const Icon = linkIconMapping[key];
return (
IconComponent && (
<span key={tool} className='me-1' aria-label={tool}>
<IconComponent />
</span>
)
<UnstyledLink
className='me-1'
key={key}
href={url}
aria-label={`${key}-link`}
>
<Icon />
</UnstyledLink>
);
})}
</IconContext.Provider>
</div>

<div className='w-full mb-3' aria-label='Project image'>
<Image
className='w-full h-auto'
src={project.image.url}
alt={project.image.alternativeText || 'Project Image'}
width={320}
height={180}
/>
</div>

<div className='flex flex-row justify-between' aria-label='Read More'>
{project.longDescription && (
<Button onClick={toggleDescription}>
{t('projects.readMore')}
</Button>
)}

{!project.longDescription && (
<UnstyledLink href=''>{t('projects.readMore')}</UnstyledLink>
)}

<div className='flex flex-row p-2'>
<IconContext.Provider value={{ color: iconColor, size: '24px' }}>
{Object.entries(project.links).map(([key, url]) => {
const Icon = linkIconMapping[key];
return (
<UnstyledLink
className='me-1'
key={key}
href={url}
aria-label={`${key}-link`}
>
<Icon />
</UnstyledLink>
);
})}
</IconContext.Provider>
</div>
</div>
</div>
)}

{showDescription && (
<div className='flex flex-col justify-between my-1 overflow-y-scroll h-full'>
{project.longDescription && (
<div
className='mb-2 text-lg md:text-base'
aria-label='Project full description'
>
<ReactMarkdown>{project.longDescription}</ReactMarkdown>
</div>
<Button onClick={toggleDiv}>{t('projects.readMore')}</Button>
)}
<div className='flex w-full justify-end'>
<Button
className='button py-2'
onClick={toggleDescription}
aria-label='Close'
>
<RxCross1 size='16px' />
</Button>

{!project.longDescription && (
<UnstyledLink href=''>{t('projects.readMore')}</UnstyledLink>
)}
</div>
</div>

<div
className={clsxm(
'flex flex-col justify-between py-1 overflow-y-scroll',
activeDiv === 'second' ? 'show' : 'hide',
)}
>
{project.longDescription && (
<div
className='mb-2 text-lg md:text-base'
aria-label='Project full description'
>
<ReactMarkdown>{project.longDescription}</ReactMarkdown>
</div>
)}
<div className='flex w-full justify-end'>
<Button
className='button py-2'
onClick={toggleDiv}
aria-label='Close'
>
<RxCross1 size='16px' />
</Button>
</div>
)}
</div>
</div>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/components/organisms/projects/projectCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.show {
height: 100%;
opacity: 1;
transition: all 0.4s ease-in-out;
}

.hide {
height: 0;
opacity: 0;
overflow: hidden;
transition: all 0.4s ease-in-out;
}

0 comments on commit d18d336

Please sign in to comment.