Projects done
This commit is contained in:
parent
a4299d0fc4
commit
58bd6769d0
6 changed files with 184 additions and 60 deletions
|
|
@ -168,6 +168,14 @@ const SocialLinksContainer = styled.div`
|
||||||
color: rgb(var(--white));
|
color: rgb(var(--white));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 820px) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Topbar = styled.div`
|
const Topbar = styled.div`
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { useState } from "react"
|
||||||
import { CaretLeftFill, CaretRightFill, Git } from "react-bootstrap-icons"
|
import { CaretLeftFill, CaretRightFill, Git } from "react-bootstrap-icons"
|
||||||
import projects from "@/data/projects"
|
import projects from "@/data/projects"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
import Image from "next/image"
|
||||||
|
|
||||||
const ProjectsContainer = styled.section`
|
const ProjectsContainer = styled.section`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -15,6 +16,11 @@ const ProjectsContainer = styled.section`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const ProjectsContent = styled.div`
|
const ProjectsContent = styled.div`
|
||||||
|
|
@ -27,23 +33,36 @@ const ProjectsContent = styled.div`
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const CarouselContainer = styled.div`
|
@media (max-width: 1200px) {
|
||||||
width: 100%;
|
font-size: 1rem;
|
||||||
position: relative;
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CarouselWrapper = styled.div`
|
const CarouselWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
transition: transform 0.5s ease-in-out;
|
transition: transform 0.5s ease-in-out;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const CarouselContainer = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ProjectCard = styled.div`
|
const ProjectCard = styled.div`
|
||||||
|
|
@ -61,52 +80,42 @@ const ProjectCard = styled.div`
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
@media (max-width: 1200px) {
|
||||||
font-size: 1.2rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
|
||||||
color: rgb(var(--white));
|
|
||||||
background-color: rgb(var(--blue));
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--light-blue));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 200px;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.active) {
|
&:not(.active) {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
}
|
}
|
||||||
`
|
|
||||||
|
|
||||||
const StateIndicator = styled.div`
|
@media (max-width: 1200px) {
|
||||||
position: absolute;
|
width: 100%;
|
||||||
top: -1rem;
|
height: auto;
|
||||||
right: -1rem;
|
padding: 1rem;
|
||||||
font-size: 1.5rem;
|
}
|
||||||
text-align: center;
|
|
||||||
line-height: 3rem;
|
|
||||||
background-color: rgba(var(--white));
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 3rem;
|
|
||||||
height: 3rem;
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const NavigationButton = styled.button`
|
const NavigationButton = styled.button`
|
||||||
|
|
@ -124,6 +133,10 @@ const NavigationButton = styled.button`
|
||||||
&:hover {
|
&:hover {
|
||||||
color: rgb(var(--white));
|
color: rgb(var(--white));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const PrevButton = styled(NavigationButton)`
|
const PrevButton = styled(NavigationButton)`
|
||||||
|
|
@ -139,6 +152,10 @@ const CarouselIndicator = styled.div`
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const IndicatorDot = styled.div`
|
const IndicatorDot = styled.div`
|
||||||
|
|
@ -151,6 +168,11 @@ const IndicatorDot = styled.div`
|
||||||
&.active {
|
&.active {
|
||||||
background-color: rgb(var(--white));
|
background-color: rgb(var(--white));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const TechStack = styled.div`
|
const TechStack = styled.div`
|
||||||
|
|
@ -159,12 +181,70 @@ const TechStack = styled.div`
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
font-size: 1rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
background-color: rgba(var(--white), 0.1);
|
background-color: rgba(var(--white), 0.1);
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Links = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: auto;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ViewLink = styled(Link)`
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgb(var(--white));
|
||||||
|
background-color: rgba(var(--primary), 0.8);
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const SourceLink = styled(Link)`
|
||||||
|
svg {
|
||||||
|
transition: color 0.3s;
|
||||||
|
color: rgba(var(--white), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover svg {
|
||||||
|
color: rgb(var(--white));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
svg {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const StateIndicator = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Projects = () => {
|
const Projects = () => {
|
||||||
|
|
@ -188,7 +268,7 @@ const Projects = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProjectsContainer>
|
<ProjectsContainer id="projects">
|
||||||
<ProjectsContent>
|
<ProjectsContent>
|
||||||
<h2>📂 My Projects</h2>
|
<h2>📂 My Projects</h2>
|
||||||
<p>Here are some of the projects I've worked on recently</p>
|
<p>Here are some of the projects I've worked on recently</p>
|
||||||
|
|
@ -206,12 +286,17 @@ const Projects = () => {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StateIndicator>
|
<StateIndicator title="Project State">
|
||||||
{project.state === "wip" ? "🔄" : "✅"}
|
{project.state === "wip" ? "🔄" : "✅"}
|
||||||
</StateIndicator>
|
</StateIndicator>
|
||||||
<h3>{project.title}</h3>
|
<h3>{project.title}</h3>
|
||||||
{project.image && (
|
{project.image && (
|
||||||
<img src={project.image} alt={project.title} />
|
<Image
|
||||||
|
src={project.image}
|
||||||
|
alt={project.title}
|
||||||
|
width={400}
|
||||||
|
height={200}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<p>{project.description}</p>
|
<p>{project.description}</p>
|
||||||
<TechStack>
|
<TechStack>
|
||||||
|
|
@ -219,10 +304,24 @@ const Projects = () => {
|
||||||
<span key={index}>{tech}</span>
|
<span key={index}>{tech}</span>
|
||||||
))}
|
))}
|
||||||
</TechStack>
|
</TechStack>
|
||||||
{project.href && <Link href={project.href}>View Project</Link>}
|
<Links>
|
||||||
<Link href={project.source}>
|
{project.href && (
|
||||||
<Git />
|
<ViewLink
|
||||||
</Link>
|
href={project.href}
|
||||||
|
target="_blank"
|
||||||
|
title="View Project"
|
||||||
|
>
|
||||||
|
View Project
|
||||||
|
</ViewLink>
|
||||||
|
)}
|
||||||
|
<SourceLink
|
||||||
|
href={project.source}
|
||||||
|
target="_blank"
|
||||||
|
title="View Source"
|
||||||
|
>
|
||||||
|
<Git size={30} />
|
||||||
|
</SourceLink>
|
||||||
|
</Links>
|
||||||
</ProjectCard>
|
</ProjectCard>
|
||||||
))}
|
))}
|
||||||
</CarouselWrapper>
|
</CarouselWrapper>
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ const Categories = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
|
@ -48,6 +49,7 @@ const SkillCategory = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@ const links: Link[] = [
|
||||||
href: "#skills",
|
href: "#skills",
|
||||||
text: "Skills",
|
text: "Skills",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "projects",
|
||||||
|
href: "#projects",
|
||||||
|
text: "Projects",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "contact",
|
id: "contact",
|
||||||
href: "#contact",
|
href: "#contact",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,24 @@ type Project = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const projects: Project[] = [
|
const projects: Project[] = [
|
||||||
|
{
|
||||||
|
title: "Ephemr",
|
||||||
|
description:
|
||||||
|
"A simple social network, a place to share your thoughts with the world.",
|
||||||
|
image: "/ephemr.png",
|
||||||
|
techStack: [
|
||||||
|
"Next.js",
|
||||||
|
"TypeScript",
|
||||||
|
"Styled Components",
|
||||||
|
"Socket.IO",
|
||||||
|
"Prisma",
|
||||||
|
"PostgreSQL",
|
||||||
|
"JWT",
|
||||||
|
],
|
||||||
|
href: "https://ephemr.net",
|
||||||
|
source: "https://github.com/HangerThem/ephemr",
|
||||||
|
state: "wip",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "HangerThem Portfolio",
|
title: "HangerThem Portfolio",
|
||||||
description: "This very website and my personal portfolio.",
|
description: "This very website and my personal portfolio.",
|
||||||
|
|
@ -28,16 +46,6 @@ const projects: Project[] = [
|
||||||
source: "https://github.com/HangerThem/linkboard",
|
source: "https://github.com/HangerThem/linkboard",
|
||||||
state: "done",
|
state: "done",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "Ephemr",
|
|
||||||
description:
|
|
||||||
"A simple social network, a place to share your thoughts with the world.",
|
|
||||||
image: "/ephemr.png",
|
|
||||||
techStack: ["Next.js", "TypeScript", "Styled Components", "Socket.IO"],
|
|
||||||
href: "https://ephemr.net",
|
|
||||||
source: "https://github.com/HangerThem/ephemr",
|
|
||||||
state: "wip",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "Evolution algorithm Flappy Bird",
|
title: "Evolution algorithm Flappy Bird",
|
||||||
description:
|
description:
|
||||||
|
|
@ -48,13 +56,7 @@ const projects: Project[] = [
|
||||||
source: "https://github.com/HangerThem/js-flappy-bird-ea",
|
source: "https://github.com/HangerThem/js-flappy-bird-ea",
|
||||||
state: "done",
|
state: "done",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "Peer to Peer Chat",
|
|
||||||
description: "A simple peer-to-peer chat application.",
|
|
||||||
techStack: ["Python"],
|
|
||||||
source: "https://github.com/HangerThem/python-p2p-real-time-chat",
|
|
||||||
state: "wip",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "Simple 2D physics engine",
|
title: "Simple 2D physics engine",
|
||||||
description: "A simple 2D physics engine written in JavaScript.",
|
description: "A simple 2D physics engine written in JavaScript.",
|
||||||
|
|
@ -64,6 +66,13 @@ const projects: Project[] = [
|
||||||
source: "https://hangerthem.github.io/js-2D-physic-engine/",
|
source: "https://hangerthem.github.io/js-2D-physic-engine/",
|
||||||
state: "wip",
|
state: "wip",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Peer to Peer Chat",
|
||||||
|
description: "A simple peer-to-peer chat application.",
|
||||||
|
techStack: ["Python"],
|
||||||
|
source: "https://github.com/HangerThem/python-p2p-real-time-chat",
|
||||||
|
state: "wip",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export default projects
|
export default projects
|
||||||
|
|
|
||||||
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -947,9 +947,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001584",
|
"version": "1.0.30001651",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
|
||||||
"integrity": "sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ==",
|
"integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|
@ -963,7 +963,8 @@
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "CC-BY-4.0"
|
||||||
},
|
},
|
||||||
"node_modules/canvas-confetti": {
|
"node_modules/canvas-confetti": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue