Stackbits
Components > Projects Section

Projects Section

The ProjectsSection component is a versatile and dynamic React component designed to showcase a collection of projects in a visually appealing manner. It efficiently displays project details such as titles, taglines, descriptions, and links, including hosted and GitHub links, with an engaging layout. This component is perfect for developers looking to enhance their portfolio or project showcase with a modern, responsive design that highlights key project features and encourages user interaction.

Preview

Follow below steps 👇🏻

Install dependencies

1
npm i framer-motion lucide-react

Component

Create a file project-section.tsx in your components folder and paste this code

1
'use client';
2
3
import { AnimatePresence, motion } from 'framer-motion';
4
import { Github, Globe, MoveUpRight } from 'lucide-react';
5
import Image from 'next/image';
6
import Link from 'next/link';
7
import { ReactNode, useEffect, useState } from 'react';
8
9
type ProjectType = {
10
id: number;
11
hostedLink?: string;
12
githubLink?: string;
13
title: string;
14
tagLine: string;
15
description: string[];
16
src: string;
17
highlightColor?: string;
18
};
19
20
const LinkButton = ({
21
href,
22
text,
23
icon,
24
color = 'green'
25
}: {
26
href: string;
27
text: string;
28
icon: ReactNode;
29
color: string;
30
}) => {
31
const [hovering, setHovering] = useState(false);
32
33
return (
34
<Link href={href} target="_blank" rel="noopener noreferrer">
35
<AnimatePresence mode="wait">
36
<a
37
onMouseEnter={() => setHovering(true)}
38
onMouseLeave={() => setHovering(false)}
39
href={href}
40
target="_blank"
41
className="flex items-center gap-1.5 leading-none text-black rounded-full transition-all duration-200 cursor-pointer p-1 text-xs"
42
style={{
43
color: color
44
}}
45
>
46
{!hovering && (
47
<motion.div
48
key={href}
49
initial={{
50
opacity: 0,
51
x: -14
52
}}
53
animate={{
54
opacity: 1,
55
x: 0
56
}}
57
exit={{
58
opacity: 0,
59
x: -14
60
}}
61
transition={{
62
duration: 0.2
63
}}
64
>
65
{icon}
66
</motion.div>
67
)}
68
69
<motion.div
70
key={'children' + href}
71
layout
72
transition={{
73
duration: 0.2
74
}}
75
>
76
{text}
77
</motion.div>
78
79
{hovering && (
80
<motion.div
81
key={'right-arrow' + href}
82
initial={{
83
opacity: 0,
84
x: 14
85
}}
86
animate={{
87
opacity: 1,
88
x: 0
89
}}
90
exit={{
91
opacity: 0,
92
x: -14
93
}}
94
transition={{
95
duration: 0.2
96
}}
97
className="hidden sm:block"
98
>
99
<MoveUpRight size={16} />
100
</motion.div>
101
)}
102
</a>
103
</AnimatePresence>
104
</Link>
105
);
106
};
107
108
const ProjectCard = ({ project }: { project: ProjectType }) => {
109
const [isSmallScreen, setIsSmallScreen] = useState(false);
110
const [loading, setLoading] = useState(true);
111
112
useEffect(() => {
113
const handleResize = () => {
114
setIsSmallScreen(window.innerWidth < 640);
115
};
116
handleResize();
117
window.addEventListener('resize', handleResize);
118
setLoading(false);
119
return () => window.removeEventListener('resize', handleResize);
120
}, []);
121
122
return (
123
!loading && (
124
<div className="border-b-[1px] border-white/20 w-full relative group">
125
<motion.div
126
style={{
127
height: isSmallScreen ? 'auto' : '148px'
128
}}
129
initial={{ height: isSmallScreen ? 'auto' : '148px' }}
130
whileHover={{ height: 'auto' }}
131
transition={{ duration: 0.3, ease: 'easeInOut' }}
132
className="overflow-hidden flex flex-col"
133
>
134
<div
135
style={{
136
height: '48px'
137
}}
138
className="shrink-0"
139
/>
140
<div className="flex sm:flex-row flex-col items-start justify-between">
141
<div className="flex flex-col items-start justify-between w-full sm:w-[calc(100%-320px)]">
142
<div className="flex flex-col items-start justify-start">
143
<p className="font-bold text-white">{project.title}</p>
144
<p>{project.tagLine}</p>
145
</div>
146
<div className="flex items-center gap-5 mt-2">
147
{project.hostedLink && (
148
<LinkButton
149
color="#0084ff"
150
href={project.hostedLink}
151
text="Live"
152
icon={<Globe size={16} />}
153
/>
154
)}
155
{project.githubLink && (
156
<LinkButton
157
color="#2dba4e"
158
href={project.githubLink}
159
text="Github"
160
icon={<Github size={16} />}
161
/>
162
)}
163
</div>
164
</div>
165
<div
166
className="relative w-full sm:w-[300px] aspect-video sm:rotate-6 group-hover:rotate-0 transition-all duration-300 sm:mt-0 mt-4 overflow-hidden"
167
style={{
168
boxShadow: `0px 0px 40px 1px ${project.highlightColor}7A`
169
}}
170
>
171
<Image src={project.src || ''} alt={project.title} fill className="object-cover" />
172
</div>
173
</div>
174
<div className="flex flex-col items-start justify-start gap-4 text-justify mt-4">
175
{project.description.map((description) => {
176
return <p key={description}>{description}</p>;
177
})}
178
</div>
179
<div
180
style={{
181
height: '48px'
182
}}
183
/>
184
</motion.div>
185
</div>
186
)
187
);
188
};
189
190
const ProjectsSection = ({ projects }: { projects: ProjectType[] }) => {
191
return (
192
<div className="flex flex-col items-start justify-start">
193
<div className="flex flex-col items-start justify-start w-full mt-4">
194
{projects.map((project) => {
195
return <ProjectCard key={project.id + project.title} project={project} />;
196
})}
197
</div>
198
</div>
199
);
200
};
201
202
export default ProjectsSection;

Usage

1
<ProjectsSection
2
projects={[
3
{
4
id: 1,
5
title: 'Stackbits',
6
tagLine: 'Ready to use snippets for your next project',
7
hostedLink: 'https://stackbits.dev',
8
src: 'https://images.unsplash.com/photo-1588200908342-23b585c03e26?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
9
description: [
10
'StackBits is a robust component library that accelerates web development by providing reusable frontend and backend code snippets. It offers ready-to-use components for React, Next.js, JavaScript, and Tailwind CSS, along with backend utilities like authentication flows and API handlers, eliminating boilerplate code and enhancing efficiency.'
11
],
12
highlightColor: '#7701FF'
13
},
14
{
15
id: 2,
16
hostedLink: 'https://readmechef.com',
17
title: 'ReadMeChef',
18
tagLine:
19
'What if I told you that you could create a perfect README in just one step?',
20
src: 'https://images.unsplash.com/photo-1608742213509-815b97c30b36?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
21
description: [
22
'ReadMeChef is an AI-powered tool that generates high-quality, professional README files instantly without any manual input. It offers intelligent content suggestions, customizable templates, and seamless Markdown formatting, ensuring clear and engaging documentation for any project, whether new or existing.'
23
],
24
highlightColor: '#00ff00'
25
},
26
{
27
id: 2,
28
hostedLink: 'https://peeklink.stackbits.dev',
29
title: 'peeklink',
30
tagLine: 'Perfect your social media presence before your share.',
31
githubLink: 'https://github.com/samitkapoor/peeklink',
32
src: 'https://images.unsplash.com/photo-1578091879915-33ee869e2cd7?q=80&w=3702&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
33
highlightColor: '#D2D2D2',
34
description: [
35
'Peeklink is a tool designed for builders to preview how their project links will appear when shared on social media platforms. It provides a comprehensive report highlighting any missing OpenGraph tags, ensuring that your links are optimized for the best possible presentation and engagement.'
36
]
37
}
38
]}
39
/>

⭐️ Got a question or feedback?
Feel free to reach out!