feat: add technology and interest icons in About section
This commit is contained in:
3
bun.lock
3
bun.lock
@ -11,6 +11,7 @@
|
||||
"next": "15.1.7",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-intersection-observer": "^9.15.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -641,6 +642,8 @@
|
||||
|
||||
"react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="],
|
||||
|
||||
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
||||
|
||||
"react-intersection-observer": ["react-intersection-observer@9.15.1", "", { "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["react-dom"] }, "sha512-vGrqYEVWXfH+AGu241uzfUpNK4HAdhCkSAyFdkMb9VWWXs6mxzBLpWCxEy9YcnDNY2g9eO6z7qUtTBdA9hc8pA=="],
|
||||
|
||||
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||
|
@ -16,6 +16,7 @@
|
||||
"next": "15.1.7",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-intersection-observer": "^9.15.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,6 +1,35 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import { FadeIn } from '../ui/FadeIn';
|
||||
import { FaGithub, FaLinkedin } from 'react-icons/fa';
|
||||
import { SiPhp, SiJavascript, SiMysql, SiReact, SiNextdotjs, SiTypescript } from 'react-icons/si';
|
||||
import { MdWeb, MdArchitecture, MdDesignServices, MdSpeed } from 'react-icons/md';
|
||||
|
||||
interface Tech {
|
||||
name: string;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
interface Interest {
|
||||
name: string;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
const technologies: Tech[] = [
|
||||
{ name: 'PHP', icon: <SiPhp /> },
|
||||
{ name: 'JavaScript', icon: <SiJavascript /> },
|
||||
{ name: 'TypeScript', icon: <SiTypescript /> },
|
||||
{ name: 'React', icon: <SiReact /> },
|
||||
{ name: 'Next.js', icon: <SiNextdotjs /> },
|
||||
{ name: 'MySQL', icon: <SiMysql /> }
|
||||
];
|
||||
|
||||
const interests: Interest[] = [
|
||||
{ name: 'Web Development', icon: <MdWeb /> },
|
||||
{ name: 'System Architecture', icon: <MdArchitecture /> },
|
||||
{ name: 'UI/UX Design', icon: <MdDesignServices /> },
|
||||
{ name: 'Performance Optimization', icon: <MdSpeed /> }
|
||||
];
|
||||
|
||||
export const About = () => {
|
||||
return (
|
||||
@ -8,7 +37,9 @@ export const About = () => {
|
||||
<div className="max-w-screen-xl mx-auto">
|
||||
<FadeIn>
|
||||
<div className="flex items-baseline gap-4 mb-12 sm:mb-24">
|
||||
<h2 className="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">About</h2>
|
||||
<h2 className="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">
|
||||
About
|
||||
</h2>
|
||||
<div className="h-px flex-grow bg-white/10 relative top-[-4px]"></div>
|
||||
</div>
|
||||
</FadeIn>
|
||||
@ -29,8 +60,12 @@ export const About = () => {
|
||||
</FadeIn>
|
||||
<FadeIn delay={0.1}>
|
||||
<div className="space-y-2 text-center md:text-left">
|
||||
<h3 className="font-['DM_Sans'] text-xl sm:text-2xl font-medium theme-primary">Jan-Marlon Leibl</h3>
|
||||
<p className="font-['Instrument_Sans'] theme-text-70 text-base sm:text-lg">Fullstack Developer</p>
|
||||
<h3 className="font-['DM_Sans'] text-xl sm:text-2xl font-medium theme-primary">
|
||||
Jan-Marlon Leibl
|
||||
</h3>
|
||||
<p className="font-['Instrument_Sans'] theme-text-70 text-base sm:text-lg">
|
||||
Fullstack Developer
|
||||
</p>
|
||||
</div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
@ -49,17 +84,19 @@ export const About = () => {
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-10 sm:gap-16">
|
||||
<div className="space-y-6 sm:space-y-8">
|
||||
<div className="flex items-baseline gap-4">
|
||||
<h3 className="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">Technologies</h3>
|
||||
<h3 className="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
|
||||
Technologies
|
||||
</h3>
|
||||
<div className="h-px flex-grow theme-border"></div>
|
||||
</div>
|
||||
<ul className="space-y-4 sm:space-y-5">
|
||||
{['PHP', 'JavaScript', 'MySQL', 'React'].map((tech) => (
|
||||
{technologies.map((tech) => (
|
||||
<li
|
||||
key={tech}
|
||||
className="text-base sm:text-lg group flex items-center gap-3 theme-text-70 hover:theme-text-90 transition-colors cursor-default"
|
||||
key={tech.name}
|
||||
className="text-base sm:text-lg group flex items-center gap-3 theme-text-70 hover:theme-text-90 transition-colors cursor-default bg-white/[0.02] px-3 py-2 rounded-md"
|
||||
>
|
||||
<span className="w-2 h-2 rounded-full theme-text-40 group-hover:theme-text-90 transition-colors"></span>
|
||||
{tech}
|
||||
<span className="text-lg theme-text-40 group-hover:theme-text-90 transition-colors">{tech.icon}</span>
|
||||
{tech.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@ -67,22 +104,19 @@ export const About = () => {
|
||||
|
||||
<div className="space-y-6 sm:space-y-8">
|
||||
<div className="flex items-baseline gap-4">
|
||||
<h3 className="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">Interests</h3>
|
||||
<h3 className="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
|
||||
Interests
|
||||
</h3>
|
||||
<div className="h-px flex-grow theme-border"></div>
|
||||
</div>
|
||||
<ul className="space-y-4 sm:space-y-5">
|
||||
{[
|
||||
'Web Development',
|
||||
'System Architecture',
|
||||
'UI/UX Design',
|
||||
'Performance Optimization'
|
||||
].map((interest) => (
|
||||
{interests.map((interest) => (
|
||||
<li
|
||||
key={interest}
|
||||
className="text-base sm:text-lg group flex items-center gap-3 theme-text-70 hover:theme-text-90 transition-colors cursor-default"
|
||||
key={interest.name}
|
||||
className="text-base sm:text-lg group flex items-center gap-3 theme-text-70 hover:theme-text-90 transition-colors cursor-default bg-white/[0.02] px-3 py-2 rounded-md"
|
||||
>
|
||||
<span className="w-2 h-2 rounded-full theme-text-40 group-hover:theme-text-90 transition-colors"></span>
|
||||
{interest}
|
||||
<span className="text-lg theme-text-40 group-hover:theme-text-90 transition-colors">{interest.icon}</span>
|
||||
{interest.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@ -94,18 +128,20 @@ export const About = () => {
|
||||
href="https://github.com/AtomicWasTaken"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-full text-center px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide font-medium theme-text-90"
|
||||
className="w-full text-center px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide font-medium theme-text-90 flex items-center justify-center"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
<FaGithub className="mr-2" />
|
||||
View GitHub
|
||||
</motion.a>
|
||||
<motion.a
|
||||
href="https://www.linkedin.com/in/janmarlonleibl/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-full text-center px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide font-medium theme-text-90"
|
||||
className="w-full text-center px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide font-medium theme-text-90 flex items-center justify-center"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
<FaLinkedin className="mr-2" />
|
||||
Connect on LinkedIn
|
||||
</motion.a>
|
||||
</div>
|
||||
|
@ -1,39 +1,109 @@
|
||||
import { FadeIn } from '../ui/FadeIn';
|
||||
import { SiNextdotjs, SiTailwindcss, SiTypescript, SiPhp, SiJavascript, SiMysql, SiDiscord } from 'react-icons/si';
|
||||
import { BsLightningChargeFill } from 'react-icons/bs';
|
||||
import { FaCode } from 'react-icons/fa';
|
||||
import { HiOutlineCollection } from 'react-icons/hi';
|
||||
import { MdLaunch } from 'react-icons/md';
|
||||
import React from 'react';
|
||||
|
||||
interface Project {
|
||||
title: string;
|
||||
year: string;
|
||||
description: string;
|
||||
tags: string[];
|
||||
icon: React.ReactNode;
|
||||
tags: Array<{
|
||||
name: string;
|
||||
icon: React.ReactNode;
|
||||
}>;
|
||||
}
|
||||
|
||||
const getTagIcon = (tag: string) => {
|
||||
switch (tag) {
|
||||
case 'Next.js':
|
||||
return <SiNextdotjs className="text-lg" />;
|
||||
case 'Tailwind CSS':
|
||||
return <SiTailwindcss className="text-lg" />;
|
||||
case 'TypeScript':
|
||||
return <SiTypescript className="text-lg" />;
|
||||
case 'PHP':
|
||||
return <SiPhp className="text-lg" />;
|
||||
case 'JavaScript':
|
||||
return <SiJavascript className="text-lg" />;
|
||||
case 'MySQL':
|
||||
return <SiMysql className="text-lg" />;
|
||||
case 'Performance':
|
||||
return <BsLightningChargeFill className="text-lg" />;
|
||||
case 'Discord API':
|
||||
return <SiDiscord className="text-lg" />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getProjectIcon = (title: string) => {
|
||||
if (title.includes('ventry')) {
|
||||
return <MdLaunch className="text-2xl" />;
|
||||
} else if (title.includes('ShareUpload')) {
|
||||
return <HiOutlineCollection className="text-2xl" />;
|
||||
} else if (title.includes('RestoreM')) {
|
||||
return <SiDiscord className="text-2xl" />;
|
||||
} else {
|
||||
return <FaCode className="text-2xl" />;
|
||||
}
|
||||
};
|
||||
|
||||
const projects: Project[] = [
|
||||
{
|
||||
title: 'ventry.host v2',
|
||||
year: '2025',
|
||||
description: 'Free file hosting revamped with a modern design and improved user experience.',
|
||||
tags: ['Next.js', 'Tailwind CSS', 'TypeScript']
|
||||
icon: getProjectIcon('ventry.host v2'),
|
||||
tags: [
|
||||
{ name: 'Next.js', icon: getTagIcon('Next.js') },
|
||||
{ name: 'Tailwind CSS', icon: getTagIcon('Tailwind CSS') },
|
||||
{ name: 'TypeScript', icon: getTagIcon('TypeScript') }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'ventry.host',
|
||||
year: '2023',
|
||||
description: 'A free file hosting solution with thousands of daily visitors.',
|
||||
tags: ['PHP', 'JavaScript', 'MySQL']
|
||||
icon: getProjectIcon('ventry.host'),
|
||||
tags: [
|
||||
{ name: 'PHP', icon: getTagIcon('PHP') },
|
||||
{ name: 'JavaScript', icon: getTagIcon('JavaScript') },
|
||||
{ name: 'MySQL', icon: getTagIcon('MySQL') }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'ShareUpload',
|
||||
year: '2022',
|
||||
description: 'High-performance file sharing platform with unlimited storage.',
|
||||
tags: ['PHP', 'MySQL', 'Performance']
|
||||
icon: getProjectIcon('ShareUpload'),
|
||||
tags: [
|
||||
{ name: 'PHP', icon: getTagIcon('PHP') },
|
||||
{ name: 'MySQL', icon: getTagIcon('MySQL') },
|
||||
{ name: 'Performance', icon: getTagIcon('Performance') }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'RestoreM',
|
||||
year: '2023',
|
||||
description: 'Discord server backup and restoration service.',
|
||||
tags: ['PHP', 'MySQL', 'Discord API']
|
||||
icon: getProjectIcon('RestoreM'),
|
||||
tags: [
|
||||
{ name: 'PHP', icon: getTagIcon('PHP') },
|
||||
{ name: 'MySQL', icon: getTagIcon('MySQL') },
|
||||
{ name: 'Discord API', icon: getTagIcon('Discord API') }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// Sort projects by year (newest first)
|
||||
const sortedProjects = [...projects].sort((a, b) => {
|
||||
return parseInt(b.year) - parseInt(a.year);
|
||||
});
|
||||
|
||||
export const Work = () => {
|
||||
return (
|
||||
<section id="work" className="py-20 sm:py-40 px-4 sm:px-8 relative">
|
||||
@ -41,16 +111,20 @@ export const Work = () => {
|
||||
<div className="max-w-screen-xl mx-auto relative">
|
||||
<FadeIn>
|
||||
<div className="flex flex-col gap-3 mb-12 sm:mb-24">
|
||||
<span className="theme-text-40 uppercase tracking-[0.2em] text-sm sm:text-base font-['Instrument_Sans']">Portfolio</span>
|
||||
<span className="theme-text-40 uppercase tracking-[0.2em] text-sm sm:text-base font-['Instrument_Sans']">
|
||||
Portfolio
|
||||
</span>
|
||||
<div className="flex items-baseline gap-4">
|
||||
<h2 className="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">Selected Work</h2>
|
||||
<h2 className="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">
|
||||
Selected Work
|
||||
</h2>
|
||||
<div className="h-px flex-grow theme-border"></div>
|
||||
</div>
|
||||
</div>
|
||||
</FadeIn>
|
||||
|
||||
<div className="grid gap-24 sm:gap-40">
|
||||
{projects.map((project, index) => (
|
||||
{sortedProjects.map((project, index) => (
|
||||
<FadeIn key={index} delay={index * 0.1}>
|
||||
<div className="group relative">
|
||||
<div className="absolute top-0 left-0 right-0 flex items-center gap-4">
|
||||
@ -72,15 +146,19 @@ export const Work = () => {
|
||||
|
||||
<div className="space-y-6 sm:space-y-12">
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
<h4 className="font-['Instrument_Sans'] text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">Technologies</h4>
|
||||
<h4 className="font-['Instrument_Sans'] text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
|
||||
Technologies
|
||||
</h4>
|
||||
<div className="flex flex-wrap items-center gap-3 sm:gap-4">
|
||||
{project.tags.map((tag, tagIndex) => (
|
||||
<span
|
||||
key={tagIndex}
|
||||
className="text-sm sm:text-base theme-text-70 font-['Instrument_Sans'] tracking-wide py-1 sm:py-2 group-hover:theme-text-90 transition-colors"
|
||||
className="flex items-center text-sm sm:text-base theme-text-70 font-['Instrument_Sans'] tracking-wide py-1 sm:py-2 group-hover:theme-text-90 transition-colors bg-white/[0.02] px-3 sm:px-4 rounded-full shadow-sm"
|
||||
>
|
||||
{tag}{tagIndex !== project.tags.length - 1 && (
|
||||
<span className="mx-3 sm:mx-4 theme-text-40 select-none">•</span>
|
||||
<span className="mr-2 flex items-center">{tag.icon}</span>
|
||||
{tag.name}
|
||||
{tagIndex !== project.tags.length - 1 && (
|
||||
<span className="ml-2 opacity-0">•</span>
|
||||
)}
|
||||
</span>
|
||||
))}
|
||||
|
Reference in New Issue
Block a user