diff --git a/src/Components/Card/Card.module.css b/src/Components/Card/Card.module.css new file mode 100644 index 0000000..ad73e7f --- /dev/null +++ b/src/Components/Card/Card.module.css @@ -0,0 +1,16 @@ +.action-area { + height: 100% !important; + display: flex !important; + justify-content: flex-start !important; + align-items: flex-start !important; + flex-direction: column !important; +} + +.image { + height: 100px; + width: 100%; +} + +.description { + margin-bottom: 1rem !important; +} \ No newline at end of file diff --git a/src/Components/Card/Card.tsx b/src/Components/Card/Card.tsx new file mode 100644 index 0000000..c74fc37 --- /dev/null +++ b/src/Components/Card/Card.tsx @@ -0,0 +1,35 @@ +import { Card as MuiCard, CardActionArea, CardContent, CardMedia, Typography } from '@mui/material'; +import Contentful from 'contentful'; + +import { TagBlock } from 'Components/TagBlock'; + +import styles from './Card.module.css'; + +interface CardProps { + image?: Contentful.Asset; + title: Contentful.EntryFields.Text; + description?: Contentful.EntryFields.Text; + tags?: Contentful.TagLink[]; + onClick: () => void; +} + +export const Card = ({ onClick, image, title, description, tags }: CardProps) => { + return ( + + + {image && } + + + {title} + + {description && ( + + {description} + + )} + {tags && } + + + + ); +}; \ No newline at end of file diff --git a/src/Components/Card/index.ts b/src/Components/Card/index.ts new file mode 100644 index 0000000..0dad63d --- /dev/null +++ b/src/Components/Card/index.ts @@ -0,0 +1 @@ +export * from './Card'; \ No newline at end of file diff --git a/src/Components/index.ts b/src/Components/index.ts index 3ddfe1c..86ec3b2 100644 --- a/src/Components/index.ts +++ b/src/Components/index.ts @@ -1,4 +1,5 @@ export * from './AvailableFrom'; +export * from './Card'; export * from './CvDownloadButton'; export * from './ErrorAlert'; export * from './Grid'; diff --git a/src/Hooks/Api/index.ts b/src/Hooks/Api/index.ts index d79819a..2741741 100644 --- a/src/Hooks/Api/index.ts +++ b/src/Hooks/Api/index.ts @@ -1,4 +1,5 @@ export * from './useExperienceApi'; export * from './useJournalApi'; export * from './usePageContentApi'; +export * from './useProjectsApi'; export * from './useSkillsApi'; \ No newline at end of file diff --git a/src/Hooks/Api/useProjectsApi.ts b/src/Hooks/Api/useProjectsApi.ts new file mode 100644 index 0000000..a9b4f67 --- /dev/null +++ b/src/Hooks/Api/useProjectsApi.ts @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query'; + +import { useContentfulClient } from '../useContentfulClient'; + +import { ProjectItem } from 'Types'; + +export const useProjectsApi = () => { + const { fetchEntries } = useContentfulClient(); + + return useQuery({ + queryKey: ['useProjectsApi'], + queryFn: () => fetchEntries('project', { + order: '-sys.createdAt', + }), + staleTime: Infinity, + }); +}; \ No newline at end of file diff --git a/src/Modules/NavBar/NavBar.tsx b/src/Modules/NavBar/NavBar.tsx index 5992653..6626d32 100644 --- a/src/Modules/NavBar/NavBar.tsx +++ b/src/Modules/NavBar/NavBar.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Description,DeveloperMode,FilterAlt, Home } from '@mui/icons-material'; +import { Description,DeveloperMode,FilterAlt, Home, SettingsEthernet } from '@mui/icons-material'; import { Avatar, IconButton } from '@mui/material'; import AppBar from '@mui/material/AppBar'; import Box from '@mui/material/Box'; @@ -49,8 +49,7 @@ export const NavBar = ({ location = 'header' }: NavBarProps) => { }>Home }>Experience }>Journal - {/* Projects - History */} + }>Projects )} diff --git a/src/Modules/ProjectsGrid/ProjectsGrid.tsx b/src/Modules/ProjectsGrid/ProjectsGrid.tsx new file mode 100644 index 0000000..0e53720 --- /dev/null +++ b/src/Modules/ProjectsGrid/ProjectsGrid.tsx @@ -0,0 +1,43 @@ +import { useNavigate } from 'react-router-dom'; + +import { Card, ErrorAlert, Grid, LoadingSpinner, NoDataAlert } from 'Components'; + +import { useProjectsApi } from 'Hooks'; + +export const ProjectsGrid = () => { + const { data, isLoading, error } = useProjectsApi(); + const navigate = useNavigate(); + + const navigateProjectItem = (slug: string) => { + navigate(`/projects/${slug}`); + }; + + if (isLoading) { + return ; + } + + if (error) { + return ; + } + + if (!isLoading && !error && !data?.items?.length) { + return ; + } + + console.log(data); + + return ( + + {data?.items?.map(project => ( + navigateProjectItem(project.fields.slug)} + /> + ))} + + ); +}; \ No newline at end of file diff --git a/src/Modules/ProjectsGrid/index.ts b/src/Modules/ProjectsGrid/index.ts new file mode 100644 index 0000000..2bf28ab --- /dev/null +++ b/src/Modules/ProjectsGrid/index.ts @@ -0,0 +1 @@ +export * from './ProjectsGrid'; \ No newline at end of file diff --git a/src/Modules/index.ts b/src/Modules/index.ts index 31cdc90..d4e8ec7 100644 --- a/src/Modules/index.ts +++ b/src/Modules/index.ts @@ -5,6 +5,7 @@ export * from './Header'; export * from './JournalGrid'; export * from './NavBar'; export * from './PageContent'; +export * from './ProjectsGrid'; export * from './SideBar'; export * from './SocialLinks'; export * from './TagDrawer'; \ No newline at end of file diff --git a/src/Routes/Projects/ProjectsItemPage.tsx b/src/Routes/Projects/ProjectsItemPage.tsx new file mode 100644 index 0000000..ecb5950 --- /dev/null +++ b/src/Routes/Projects/ProjectsItemPage.tsx @@ -0,0 +1,7 @@ +export const ProjectsItemPage = () => { + return ( +
+ projects item here +
+ ); +}; \ No newline at end of file diff --git a/src/Routes/Projects/ProjectsPage.tsx b/src/Routes/Projects/ProjectsPage.tsx new file mode 100644 index 0000000..0bb2aa0 --- /dev/null +++ b/src/Routes/Projects/ProjectsPage.tsx @@ -0,0 +1,34 @@ +import { useEffect } from 'react'; +import { Helmet } from 'react-helmet-async'; +import { useLocation,useOutlet } from 'react-router-dom'; + +import { Title } from 'Components'; +import { ProjectsGrid } from 'Modules'; + +import { useUi } from 'Context/uiContext'; +import { useAnalytics } from 'Hooks/useAnalytics/useAnalytics'; + +export const ProjectsPage = () => { + const outlet = useOutlet(); + const { pageTitle } = useUi(); + const { pageView } = useAnalytics(); + const { pathname } = useLocation(); + + useEffect(() => { + if (!outlet) { + pageView(pathname); + } + }); + + return ( + <> + + Projects {pageTitle} + + + + + <ProjectsGrid /> + </> + ); +}; \ No newline at end of file diff --git a/src/Routes/Projects/index.ts b/src/Routes/Projects/index.ts new file mode 100644 index 0000000..11ed6ee --- /dev/null +++ b/src/Routes/Projects/index.ts @@ -0,0 +1,2 @@ +export * from './ProjectsItemPage'; +export * from './ProjectsPage'; \ No newline at end of file diff --git a/src/Routes/index.ts b/src/Routes/index.ts index f0640a6..bb84cb6 100644 --- a/src/Routes/index.ts +++ b/src/Routes/index.ts @@ -2,4 +2,5 @@ export * from './Error'; export * from './Experience'; export * from './Home'; export * from './Journal'; -export * from './Root'; +export * from './Projects'; +export * from './Root'; \ No newline at end of file diff --git a/src/Types/project.types.ts b/src/Types/project.types.ts index 303b861..5d5ee20 100644 --- a/src/Types/project.types.ts +++ b/src/Types/project.types.ts @@ -1,10 +1,11 @@ import Contentful from 'contentful'; export interface ProjectItem { - title: Contentful.EntryFields.Text; slug: Contentful.EntryFields.Text; + heroImage: Contentful.Asset; + title: Contentful.EntryFields.Text; + shortDescription: Contentful.EntryFields.Text; + description: Contentful.EntryFields.RichText; url: Contentful.EntryFields.Text; repo: Contentful.EntryFields.Text; - description: Contentful.EntryFields.RichText; - image: Contentful.Asset; } \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index d4611e0..a246236 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { createBrowserRouter ,RouterProvider } from 'react-router-dom'; -import { ErrorPage, ExperiencePage, JournalItemPage, JournalPage, Root } from 'Routes'; +import { ErrorPage, ExperiencePage, JournalItemPage, JournalPage, ProjectsItemPage, ProjectsPage, Root } from 'Routes'; import './index.css'; import './Themes/dracular-prism.css'; @@ -16,6 +16,9 @@ const router = createBrowserRouter([ { path: 'journal', element: <JournalPage />, children: [ { path: ':slug', element: <JournalItemPage /> } ] }, + { path: 'projects', element: <ProjectsPage />, children: [ + { path: ':slug', element: <ProjectsItemPage /> } + ] }, ] }, ]);