Skip to content

Commit

Permalink
feat: create iconMapper and assemble Projects page
Browse files Browse the repository at this point in the history
  • Loading branch information
martapanc committed Sep 12, 2023
1 parent 758be7c commit 60d6937
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 50 deletions.
20 changes: 19 additions & 1 deletion src/app/(public)/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import * as React from 'react';

import ProjectCard from '@/components/organisms/projects/ProjectCard';

import { queryProjects } from '@/queries/projects';

export const metadata = {
title: 'Projects | MartaCodes.it',
description: 'Projects page',
};

const queryData = async () => {
const projects = await queryProjects();

return {
projects,
};
};

const ProjectsPage = async () => {
const { projects } = await queryData();

return (
<main className='min-h-main'>
<section>
<div className='layout relative flex flex-col py-12'>
<h1 className='mb-5'>Projects</h1>

<div className='grid grid-cols-1 gap-5 md:grid-cols-3 md:gap-6'></div>
<div className='grid grid-cols-1 gap-6 md:grid-cols-2 md:gap-5 xl:grid-cols-3'>
{projects.map((project) => (
<ProjectCard key={project.id} project={project} />
))}
</div>
</div>
</section>
</main>
Expand Down
117 changes: 91 additions & 26 deletions src/components/organisms/projects/ProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
'use client';

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 { useTranslation } from 'react-i18next';
import { IconContext } from 'react-icons';
import { AiOutlineCloud } from 'react-icons/ai';
import { DiAndroid } from 'react-icons/di';
import {
FaAngular,
FaAws,
FaBootstrap,
FaCss3Alt,
FaHtml5,
FaJava,
FaPhp,
FaRaspberryPi,
} from 'react-icons/fa';
import { RxCross1 } from 'react-icons/rx';
import {
SiCsharp,
SiDotnet,
SiFirebase,
SiIeee,
SiJavascript,
SiNextdotjs,
SiPython,
SiReact,
SiTypescript,
SiVercel,
} from 'react-icons/si';
import { TbBrandKotlin } from 'react-icons/tb';
import ReactMarkdown from 'react-markdown';

import clsxm from '@/lib/clsxm';

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

import { Project, ToolIcon } from '@/types/Project';
import { Project } from '@/types/Project';

export interface ProjectCardProps {
project: Project;
Expand All @@ -32,37 +59,44 @@ const ProjectCard = ({ project }: ProjectCardProps) => {
const iconColor = theme === 'dark' ? 'white' : 'black';

return (
<div className='rounded p-4 shadow-md dark:bg-slate-900 dark:drop-shadow-md min-w-fit max-w-xs'>
<div className='rounded p-4 shadow-md dark:bg-slate-900 dark:drop-shadow-md md:w-full xl:h-[25rem] xl:w-[22rem] items-center'>
<div
className={clsxm('mt-4 transition-all duration-500', {
'max-h-0 opacity-0': showDescription,
'max-h-full opacity-100': !showDescription,
})}
className={clsxm(
'flex flex-col h-full my-1 transition-all duration-500 overflow-y-hidden',
{
'max-h-0 opacity-0': showDescription,
'max-h-full opacity-100': !showDescription,
},
)}
>
<h3>{project.title}</h3>
<h3 className='mb-2'>{project.title}</h3>

<div className='text-justify font-light text-sm mb-3'>
<div className='text-justify font-light text-sm mb-auto'>
<ReactMarkdown>{project.shortDescription}</ReactMarkdown>
</div>

<div className='flex flex-row mb-3'>
<IconContext.Provider value={{ color: iconColor, size: '24px' }}>
{project.tools.map((toolIcon: ToolIcon) => (
<span key={toolIcon.title} className='me-1'>
<toolIcon.icon />
</span>
))}
{project.tools.map((tool: string) => {
const IconComponent = iconMapping[tool];
return (
IconComponent && (
<span key={tool} className='me-1'>
<IconComponent />
</span>
)
);
})}
</IconContext.Provider>
</div>

<div className='w-full'>
<div className='w-full mb-3'>
<Image
className='object-cover'
className='w-full h-auto'
src={project.image.url}
alt={project.image.alternativeText || 'Project Image'}
width={0}
height={0}
style={{ width: '100%', height: 'auto' }}
width={320}
height={180}
/>
</div>

Expand All @@ -80,15 +114,22 @@ const ProjectCard = ({ project }: ProjectCardProps) => {
</div>

<div
className={clsxm('mt-4 transition-all duration-500', {
'max-h-0 opacity-0': !showDescription,
'max-h-full opacity-100': showDescription,
})}
className={clsxm(
'flex flex-col h-[95%] justify-between mt-4 transition-all duration-500 overflow-y-scroll',
{
'max-h-0 opacity-0': !showDescription,
'max-h-full opacity-100': showDescription,
},
)}
>
<div>{project.longDescription}</div>
<div>
<Button onClick={toggleDescription}>
<RxCross1 />
{project.longDescription && (
<div className='mb-2'>
<ReactMarkdown>{project.longDescription}</ReactMarkdown>
</div>
)}
<div className='flex w-full justify-end'>
<Button className='button' onClick={toggleDescription}>
<RxCross1 size='16px' />
</Button>
</div>
</div>
Expand All @@ -97,3 +138,27 @@ const ProjectCard = ({ project }: ProjectCardProps) => {
};

export default ProjectCard;

const iconMapping: Record<string, React.ComponentType> = {
android: DiAndroid,
angular: FaAngular,
aws: FaAws,
bootstrap: FaBootstrap,
cloud: AiOutlineCloud,
css: FaCss3Alt,
csharp: SiCsharp,
dotnet: SiDotnet,
firebase: SiFirebase,
html: FaHtml5,
ieee: SiIeee,
java: FaJava,
javascript: SiJavascript,
kotlin: TbBrandKotlin,
nextjs: SiNextdotjs,
php: FaPhp,
python: SiPython,
raspberrypi: FaRaspberryPi,
react: SiReact,
typescript: SiTypescript,
vercel: SiVercel,
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import { Meta } from '@storybook/react';
import {
SiNextdotjs,
SiReact,
SiStrapi,
SiTailwindcss,
SiTypescript,
SiVercel,
} from 'react-icons/si';

import ProjectCard, {
ProjectCardProps,
Expand Down Expand Up @@ -34,14 +26,7 @@ const project: Project = {
shortDescription: 'This very website :)',
longDescription:
"Built with ReactJS and later migrated to Typescript, it's also a chance to play around with my web development skills and experiment with front-end technologies.",
tools: [
{ title: 'nextjs', icon: SiNextdotjs },
{ title: 'react', icon: SiReact },
{ title: 'typescript', icon: SiTypescript },
{ title: 'tailwind', icon: SiTailwindcss },
{ title: 'strapi', icon: SiStrapi },
{ title: 'vercel', icon: SiVercel },
],
tools: ['nextjs', 'react', 'typescript', 'tailwind', 'strapi', 'vercel'],
date: '2023-08-01',
tags: ['react', 'webdev', 'frontend', 'personal', 'typescript'],
links: {
Expand Down
60 changes: 60 additions & 0 deletions src/queries/projects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { gql } from '@apollo/client';

import { flattenToArray } from '@/lib/graphqlUtils';

import apolloClient from '../../apollo/apollo-client';

import { Project, RawProject } from '@/types/Project';

export async function queryProjects() {
const { data } = await apolloClient.query({ query: projectsQuery });

const result: RawProject[] = flattenToArray<RawProject>(data.projects);
const projects: Project[] = [];

result.map((entry) => {
const project: Project = {
id: entry.id,
title: entry.title,
image: entry.image,
shortDescription: entry.shortDescription,
longDescription: entry.longDescription,
tools: entry.tools.split(','),
date: entry.date,
tags: entry.tags.split(','),
links: entry.links,
};
projects.push(project);
});

return projects;
}

const projectsQuery = gql`
query {
projects(locale: "en", sort: "date:desc") {
data {
id
attributes {
title
image {
data {
id
attributes {
name
url
alternativeText
}
}
}
shortDescription
longDescription
date
tools
tags
links
}
}
}
}
`;
19 changes: 12 additions & 7 deletions src/types/Project.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { IconType } from 'react-icons';

import { Icon } from '@/types/Icon';

export interface ToolIcon {
icon: IconType;
export interface Project {
id: string;
title: string;
image: Icon;
shortDescription: string;
longDescription?: string;
tools: string[];
date: string;
tags: string[];
links: object;
}

export interface Project {
export interface RawProject {
id: string;
title: string;
image: Icon;
shortDescription: string;
longDescription?: string;
tools: ToolIcon[];
tools: string;
date: string;
tags: string[];
tags: string;
links: object;
}

0 comments on commit 60d6937

Please sign in to comment.