Skip to content

Commit c2b9f1c

Browse files
committed
feat: add project page
1 parent b017aa8 commit c2b9f1c

File tree

8 files changed

+130
-60
lines changed

8 files changed

+130
-60
lines changed

src/components/Tooltip.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,7 @@ export default function Tooltip({
2222
<TippyTooltip
2323
trigger='mouseenter'
2424
interactive
25-
html={
26-
<div
27-
className={clsx(
28-
className,
29-
'inline-block rounded-md bg-white p-2 text-gray-600 shadow-md dark:bg-dark dark:text-gray-200',
30-
'border dark:border-gray-600 '
31-
)}
32-
>
33-
{content}
34-
</div>
35-
}
25+
html={<div className={clsx(className)}>{content}</div>}
3626
{...rest}
3727
>
3828
{withUnderline ? (

src/components/content/Comment.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { commentFlag } from '@/constants/env';
77
export default function Comment() {
88
const { theme } = useTheme();
99

10-
return !commentFlag ? (
10+
return commentFlag ? (
1111
<Giscus
1212
key={theme}
1313
repo='Chocolate1999/nextjs-tailwind-blog'
Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,52 @@
11
import clsx from 'clsx';
22
import * as React from 'react';
33

4-
import CloudinaryImg from '@/components/images/CloudinaryImg';
54
import UnstyledLink from '@/components/links/UnstyledLink';
65
import TechIcons, { TechListType } from '@/components/TechIcons';
76

8-
import { ProjectFrontmatter } from '@/types/frontmatters';
7+
import { ProjectsType } from '@/types/frontmatters';
98

109
type ProjectCardProps = {
11-
project: ProjectFrontmatter;
10+
project: ProjectsType;
1211
} & React.ComponentPropsWithoutRef<'li'>;
1312

1413
export default function ProjectCard({ project, className }: ProjectCardProps) {
1514
return (
16-
<li
17-
className={clsx(
18-
'project-card md:w-full rounded-md',
19-
'border dark:border-gray-600',
20-
'scale-100 hover:scale-[1.02] active:scale-[0.97] motion-safe:transform-gpu',
21-
'transition duration-100',
22-
'motion-reduce:hover:scale-100',
23-
'animate-shadow',
24-
className
25-
)}
26-
>
27-
<UnstyledLink
28-
href={`/projects/${project.slug}`}
29-
className='flex h-full flex-col items-start rounded-md p-4 focus:outline-none focus-visible:ring focus-visible:ring-primary-300'
30-
>
31-
<h4>{project.title}</h4>
32-
<p className='mb-auto text-sm text-gray-700 dark:text-gray-300'>
33-
{project.description}
34-
</p>
35-
<div className='mt-2'>
36-
<TechIcons techs={project.techs.split(',') as Array<TechListType>} />
37-
</div>
15+
<ul className='mt-6 grid grid-cols-4 gap-4'>
16+
{project.child.map((projectItem) => (
17+
<li
18+
key={projectItem.title}
19+
className={clsx(
20+
'project-card md:w-full rounded-md',
21+
'border dark:border-gray-600',
22+
'scale-100 hover:scale-[1.02] active:scale-[0.97] motion-safe:transform-gpu',
23+
'transition duration-100',
24+
'motion-reduce:hover:scale-100',
25+
'animate-shadow',
26+
className
27+
)}
28+
>
29+
<UnstyledLink
30+
href={projectItem.link}
31+
className='flex h-full flex-col items-start rounded-md p-4 focus:outline-none focus-visible:ring focus-visible:ring-primary-300'
32+
>
33+
<h4>{projectItem.title}</h4>
34+
<p className='mb-auto text-sm text-gray-700 dark:text-gray-300'>
35+
{projectItem.description}
36+
</p>
37+
<div className='mt-2'>
38+
<TechIcons
39+
techs={projectItem.techs.split(',') as Array<TechListType>}
40+
/>
41+
</div>
3842

39-
<CloudinaryImg
40-
className='pointer-events-none mt-3 w-full'
41-
publicId={`theodorusclarence/${project.banner}`}
42-
alt={project.title}
43-
width={1440}
44-
height={792}
45-
preview={false}
46-
/>
47-
48-
<p className='animated-underline mt-2 inline-block font-medium'>
49-
See more →
50-
</p>
51-
</UnstyledLink>
52-
</li>
43+
<p className='animated-underline mt-2 inline-block font-medium'>
44+
See On My Github →
45+
</p>
46+
</UnstyledLink>
47+
</li>
48+
))}
49+
;
50+
</ul>
5351
);
5452
}

src/components/layout/Layout.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import * as React from 'react';
2-
import { RecoilRoot } from 'recoil';
32

43
import Footer from '@/components/layout/Footer';
54
import Header from '@/components/layout/Header';
65

76
export default function Layout({ children }: { children: React.ReactNode }) {
87
// Put Header or Footer Here
98
return (
10-
<RecoilRoot>
11-
<div className='next-container'>
12-
<Header />
13-
{children}
14-
<Footer />
15-
</div>
16-
</RecoilRoot>
9+
<div className='next-container'>
10+
<Header />
11+
{children}
12+
<Footer />
13+
</div>
1714
);
1815
}

src/pages/_app.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AppProps } from 'next/app';
22
import Router from 'next/router';
33
import nProgress from 'nprogress';
4+
import { RecoilRoot } from 'recoil';
45

56
import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
67
import 'react-tippy/dist/tippy.css';
@@ -18,7 +19,11 @@ Router.events.on('routeChangeComplete', nProgress.done);
1819
*/
1920

2021
function MyApp({ Component, pageProps }: AppProps) {
21-
return <Component {...pageProps} />;
22+
return (
23+
<RecoilRoot>
24+
<Component {...pageProps} />
25+
</RecoilRoot>
26+
);
2227
}
2328

2429
export default MyApp;

src/pages/projects.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import clsx from 'clsx';
2+
import { useRecoilValue } from 'recoil';
3+
4+
import useLoaded from '@/hooks/useLoaded';
5+
6+
import ProjectCard from '@/components/content/projects/ProjectCard';
7+
import Layout from '@/components/layout/Layout';
8+
import Seo from '@/components/Seo';
9+
10+
import { projectsAtom } from '@/store/projects';
11+
12+
export default function ProjectsPage() {
13+
const isLoaded = useLoaded();
14+
const projects = useRecoilValue(projectsAtom);
15+
16+
return (
17+
<Layout>
18+
<Seo
19+
templateTitle='Projects'
20+
description="Showcase of my projects on front-end development that I'm proud of."
21+
/>
22+
23+
<main>
24+
<section className={clsx(isLoaded && 'fade-in-start min-h-screen')}>
25+
<div className='layout mt-[60px] py-12'>
26+
<h1 className='text-5xl dark:text-gray-100' data-fade='0'>
27+
Projects
28+
</h1>
29+
<p data-fade='1' className='mt-2 text-gray-600 dark:text-gray-300'>
30+
Showcase of my works on frontend development.
31+
</p>
32+
33+
{projects.map((project, index) => (
34+
<div key={project.category}>
35+
<h1
36+
className='my-6 text-xl dark:text-gray-100'
37+
data-fade={index + 1}
38+
>
39+
{project.category}
40+
</h1>
41+
<ProjectCard project={project} />
42+
</div>
43+
))}
44+
</div>
45+
</section>
46+
</main>
47+
</Layout>
48+
);
49+
}

src/store/projects/index.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { atom } from 'recoil';
2+
3+
export const projectsAtom = atom({
4+
key: 'PROJECTS_ATOM',
5+
default: [
6+
{
7+
category: 'Next Ecosystem',
8+
child: [
9+
{
10+
title: 'nextjs-tailwind-blog',
11+
description:
12+
'The most beautiful blog in modern times, using Next.js, TypeScript, Tailwind CSS, Welcome to visit',
13+
link: 'https://github.com/Chocolate1999/nextjs-tailwind-blog',
14+
techs: 'next,tailwindcss,typescript',
15+
},
16+
],
17+
},
18+
],
19+
});

src/types/frontmatters.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ export type ProjectFrontmatter = {
5555
youtube?: string;
5656
};
5757

58+
export type projectItemType = {
59+
title: string;
60+
description: string;
61+
link: string;
62+
techs: string;
63+
};
64+
65+
export type ProjectsType = {
66+
category: string;
67+
child: Array<projectItemType>;
68+
};
69+
5870
export type ProjectType = {
5971
code: string;
6072
frontmatter: ProjectFrontmatter;

0 commit comments

Comments
 (0)