feat: add initial Astro project structure and components

This commit is contained in:
2025-03-09 13:38:05 +01:00
parent 0ab11c240c
commit 6cc0e06918
41 changed files with 11299 additions and 1023 deletions

View File

@ -0,0 +1,146 @@
---
import FadeIn from '../ui/FadeIn.astro';
import { Icon } from 'astro-icon/components';
import { SiPhp, SiJavascript, SiMysql, SiReact } from 'react-icons/si';
import { FaGithub, FaLinkedin, FaGlobe, FaPalette } from 'react-icons/fa';
import { BsLightningChargeFill } from 'react-icons/bs';
import { IoServerOutline } from 'react-icons/io5';
import { Image } from 'astro:assets';
const technologies = [
{ name: 'PHP', icon: SiPhp },
{ name: 'JavaScript', icon: SiJavascript },
{ name: 'MySQL', icon: SiMysql },
{ name: 'React', icon: SiReact }
];
const interests = [
{ name: 'Web Development', icon: FaGlobe },
{ name: 'System Architecture', icon: IoServerOutline },
{ name: 'UI/UX Design', icon: FaPalette },
{ name: 'Performance Optimization', icon: BsLightningChargeFill }
];
---
<section id="about" class="py-20 sm:py-40 px-4 sm:px-8 theme-bg-gradient">
<div class="max-w-(--breakpoint-xl) mx-auto">
<FadeIn>
<div class="flex items-baseline gap-4 mb-12 sm:mb-24">
<h2 class="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">
About
</h2>
<div class="h-px grow bg-white/10 relative top-[-4px]"></div>
</div>
</FadeIn>
<div class="grid md:grid-cols-[1fr_2fr] gap-12 sm:gap-24">
<div class="space-y-6 sm:space-y-8">
<FadeIn>
<div class="aspect-square bg-linear-to-tr theme-bg-05 rounded-2xl overflow-hidden border theme-border hover:border-white/10 transition-colors mx-auto md:mx-0 max-w-[280px] md:max-w-none">
<Image
src="/profile-image.jpg"
alt="Jan-Marlon Leibl - Fullstack Software Developer"
width="400"
height="400"
class="object-cover w-full h-full hover:scale-105 transition-transform duration-700"
/>
</div>
</FadeIn>
<FadeIn delay={0.1}>
<div class="space-y-2 text-center md:text-left">
<h3 class="font-['DM_Sans'] text-xl sm:text-2xl font-medium theme-primary">
Jan-Marlon Leibl
</h3>
<p class="font-['Instrument_Sans'] theme-text-70 text-base sm:text-lg">
Fullstack Developer
</p>
</div>
</FadeIn>
</div>
<FadeIn delay={0.2}>
<div class="space-y-10 sm:space-y-16 font-['Instrument_Sans']">
<div class="space-y-6 sm:space-y-8">
<p class="text-xl sm:text-2xl theme-text-90 leading-relaxed">
Hello! I'm Jan-Marlon, but please call me Jan. I started my journey in programming at the age of 11 with C#, fascinated by a desktop application my friend created.
</p>
<p class="text-base sm:text-xl theme-text-70 leading-relaxed">
Today, I specialize in PHP and TypeScript development, constantly pushing the boundaries of what's possible on the web. My journey has led me from creating simple applications to developing complex systems used by thousands.
</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-10 sm:gap-16">
<div class="space-y-6 sm:space-y-8">
<div class="flex items-baseline gap-4">
<h3 class="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
Technologies
</h3>
<div class="h-px grow theme-border"></div>
</div>
<ul class="space-y-4 sm:space-y-5">
{technologies.map((tech) => (
<li class="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 class="theme-text-40 group-hover:theme-text-90 flex items-center justify-center w-6 h-6 transition-colors">
<tech.icon className="w-5 h-5" />
</span>
{tech.name}
</li>
))}
</ul>
</div>
<div class="space-y-6 sm:space-y-8">
<div class="flex items-baseline gap-4">
<h3 class="text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
Interests
</h3>
<div class="h-px grow theme-border"></div>
</div>
<ul class="space-y-4 sm:space-y-5">
{interests.map((interest) => (
<li class="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 class="theme-text-40 group-hover:theme-text-90 flex items-center justify-center w-6 h-6 transition-colors">
<interest.icon className="w-5 h-5" />
</span>
{interest.name}
</li>
))}
</ul>
</div>
</div>
<div class="pt-6 sm:pt-8 flex flex-col sm:flex-row gap-3 sm:gap-6">
<a
href="https://github.com/AtomicWasTaken"
target="_blank"
rel="noopener noreferrer"
class="animate-button 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 gap-2"
>
<FaGithub className="w-5 h-5" />
View GitHub
</a>
<a
href="https://www.linkedin.com/in/janmarlonleibl/"
target="_blank"
rel="noopener noreferrer"
class="animate-button 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 gap-2"
>
<FaLinkedin className="w-5 h-5" />
Connect on LinkedIn
</a>
</div>
</div>
</FadeIn>
</div>
</div>
</section>
<style>
.animate-button {
transition: transform 0.2s ease-out;
}
.animate-button:hover {
transform: scale(1.02);
}
</style>

View File

@ -1,149 +0,0 @@
import { motion } from 'framer-motion';
import Image from 'next/image';
import { FadeIn } from '../ui/FadeIn';
import { SiPhp, SiJavascript, SiMysql, SiReact } 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: 'MySQL', icon: <SiMysql /> },
{ name: 'React', icon: <SiReact /> }
];
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 (
<section id="about" className="py-20 sm:py-40 px-4 sm:px-8 theme-bg-gradient">
<div className="max-w-(--breakpoint-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>
<div className="h-px grow bg-white/10 relative top-[-4px]"></div>
</div>
</FadeIn>
<div className="grid md:grid-cols-[1fr_2fr] gap-12 sm:gap-24">
<div className="space-y-6 sm:space-y-8">
<FadeIn>
<div className="aspect-square bg-linear-to-tr theme-bg-05 rounded-2xl overflow-hidden border theme-border hover:border-white/10 transition-colors mx-auto md:mx-0 max-w-[280px] md:max-w-none">
<Image
src="/profile-image.jpg"
alt="Jan-Marlon Leibl - Fullstack Software Developer"
width={400}
height={400}
priority
className="object-cover w-full h-full hover:scale-105 transition-transform duration-700"
/>
</div>
</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>
</div>
</FadeIn>
</div>
<FadeIn delay={0.2}>
<div className="space-y-10 sm:space-y-16 font-['Instrument_Sans']">
<div className="space-y-6 sm:space-y-8">
<p className="text-xl sm:text-2xl theme-text-90 leading-relaxed">
Hello! I&apos;m Jan-Marlon, but please call me Jan. I started my journey in programming at the age of 11 with C#, fascinated by a desktop application my friend created.
</p>
<p className="text-base sm:text-xl theme-text-70 leading-relaxed">
Today, I specialize in PHP and TypeScript development, constantly pushing the boundaries of what&apos;s possible on the web. My journey has led me from creating simple applications to developing complex systems used by thousands.
</p>
</div>
<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>
<div className="h-px grow theme-border"></div>
</div>
<ul className="space-y-4 sm:space-y-5">
{technologies.map((tech) => (
<li
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="text-lg theme-text-40 group-hover:theme-text-90 transition-colors">{tech.icon}</span>
{tech.name}
</li>
))}
</ul>
</div>
<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>
<div className="h-px grow theme-border"></div>
</div>
<ul className="space-y-4 sm:space-y-5">
{interests.map((interest) => (
<li
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="text-lg theme-text-40 group-hover:theme-text-90 transition-colors">{interest.icon}</span>
{interest.name}
</li>
))}
</ul>
</div>
</div>
<div className="pt-6 sm:pt-8 flex flex-col sm:flex-row gap-3 sm:gap-6">
<motion.a
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"
whileHover={{ scale: 1.02 }}
>
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"
whileHover={{ scale: 1.02 }}
>
Connect on LinkedIn
</motion.a>
</div>
</div>
</FadeIn>
</div>
</div>
</section>
);
};

View File

@ -0,0 +1,115 @@
---
import FadeIn from '../ui/FadeIn.astro';
import GermanyFlag from '../ui/GermanyFlag.astro';
---
<section class="min-h-[100dvh] flex items-center justify-center px-4 sm:px-8 relative pt-24 sm:pt-8" id="hero">
<div class="absolute inset-0 theme-bg-gradient"></div>
<div class="max-w-7xl w-full relative pt-8 sm:pt-24">
<FadeIn className="space-y-8 sm:space-y-16">
<div class="space-y-6 sm:space-y-8">
<div class="space-y-6 sm:space-y-8">
<div class="inline-flex items-center gap-2.5 px-4 py-2 rounded-full theme-accent theme-border theme-transition">
<span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
<span class="theme-secondary uppercase tracking-[0.2em] text-xs sm:text-sm font-['Instrument_Sans']">Available for Work</span>
</div>
<div class="space-y-2 sm:space-y-3">
<h2 class="font-['DM_Sans'] text-xl sm:text-3xl theme-secondary tracking-wide font-medium theme-transition">
Jan-Marlon Leibl
</h2>
<div>
<h1 class="font-['DM_Sans'] text-4xl sm:text-6xl md:text-7xl lg:text-8xl font-bold tracking-tight leading-[1.1] sm:leading-[0.95] max-w-4xl theme-primary theme-transition">
Software Developer
<br />
<span class="theme-secondary">based in <GermanyFlag /></span>
</h1>
</div>
</div>
</div>
<p class="font-['Instrument_Sans'] theme-secondary text-lg sm:text-2xl max-w-2xl leading-relaxed tracking-wide theme-transition">
Passionate about creating digital experiences, with a focus on PHP and modern web technologies.
</p>
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4">
<a
href="#work"
class="animate-button w-full sm:w-auto text-center inline-flex items-center justify-center gap-2 px-6 sm:px-8 py-3 sm:py-4 theme-button-primary rounded-lg sm:rounded-full transition-colors text-sm sm:text-base tracking-wide font-medium group"
>
View My Work
<svg
class="w-4 h-4 sm:w-5 sm:h-5 transform group-hover:translate-x-1 transition-transform"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</a>
<a
href="mailto:jleibl@proton.me"
class="animate-button w-full sm:w-auto text-center inline-flex items-center justify-center gap-2 px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full theme-button-secondary hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide group"
>
Get in Touch
<svg
class="w-4 h-4 sm:w-5 sm:h-5 transform group-hover:translate-x-1 transition-transform"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</a>
</div>
</div>
<div class="border-t theme-border pt-5 pb-5">
<div class="grid grid-cols-1 sm:grid-cols-3 w-full gap-8 sm:gap-0 py-6 sm:py-8 font-['Instrument_Sans']">
<div class="text-center sm:border-r theme-border last:border-r-0">
<div class="mb-3 sm:mb-4">
<span class="theme-text-40 uppercase tracking-[0.2em] text-xs sm:text-sm">EMAIL</span>
</div>
<a
href="mailto:jleibl@proton.me"
class="theme-text-90 hover:theme-primary transition-colors text-base sm:text-lg"
>
jleibl@proton.me
</a>
</div>
<div class="text-center sm:border-r theme-border last:border-r-0">
<div class="mb-3 sm:mb-4">
<span class="theme-text-40 uppercase tracking-[0.2em] text-xs sm:text-sm">ROLE</span>
</div>
<span class="theme-text-90 text-base sm:text-lg">
Fullstack Developer
</span>
</div>
<div class="text-center">
<div class="mb-3 sm:mb-4">
<span class="theme-text-40 uppercase tracking-[0.2em] text-xs sm:text-sm">EXPERIENCE</span>
</div>
<span class="theme-text-90 text-base sm:text-lg">
5+ Years
</span>
</div>
</div>
</div>
</FadeIn>
</div>
</section>
<style>
.animate-button {
transition: transform 0.2s ease-out;
}
.animate-button:hover {
transform: scale(1.03);
}
.animate-button:active {
transform: scale(0.97);
}
</style>

View File

@ -1,107 +0,0 @@
import { motion } from 'framer-motion';
import { FadeIn } from '../ui/FadeIn';
import { GermanyFlag } from '../ui/GermanyFlag';
export const Hero = () => {
return (
<section className="min-h-[100dvh] flex items-center px-4 sm:px-8 relative pt-24 sm:pt-8">
<div className="absolute inset-0 theme-bg-gradient"></div>
<div className="max-w-(--breakpoint-xl) w-full relative pt-8 sm:pt-24">
<FadeIn className="space-y-8 sm:space-y-16">
<div className="space-y-6 sm:space-y-8">
<div className="space-y-6 sm:space-y-8">
<div className="inline-flex items-center gap-2.5 px-4 py-2 rounded-full theme-accent theme-border theme-transition">
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
<span className="theme-secondary uppercase tracking-[0.2em] text-xs sm:text-sm font-['Instrument_Sans']">Available for Work</span>
</div>
<div className="space-y-2 sm:space-y-3">
<h2 className="font-['DM_Sans'] text-xl sm:text-3xl theme-secondary tracking-wide font-medium theme-transition">
Jan-Marlon Leibl
</h2>
<div>
<h1 className="font-['DM_Sans'] text-4xl sm:text-6xl md:text-7xl lg:text-8xl font-bold tracking-tight leading-[1.1] sm:leading-[0.95] max-w-4xl theme-primary theme-transition">
Software Developer
<br />
<span className="theme-secondary">based in <GermanyFlag /></span>
</h1>
</div>
</div>
</div>
<p className="font-['Instrument_Sans'] theme-secondary text-lg sm:text-2xl max-w-2xl leading-relaxed tracking-wide theme-transition">
Passionate about creating digital experiences, with a focus on PHP and modern web technologies.
</p>
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4">
<motion.a
href="#work"
className="w-full sm:w-auto text-center inline-flex items-center justify-center gap-2 px-6 sm:px-8 py-3 sm:py-4 theme-button-primary rounded-lg sm:rounded-full transition-colors text-sm sm:text-base tracking-wide font-medium group"
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
>
View My Work
<svg
className="w-4 h-4 sm:w-5 sm:h-5 transform group-hover:translate-x-1 transition-transform"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</motion.a>
<motion.a
href="mailto:jleibl@proton.me"
className="w-full sm:w-auto text-center inline-flex items-center justify-center gap-2 px-6 sm:px-8 py-3 sm:py-4 border theme-border rounded-lg sm:rounded-full theme-button-secondary hover:theme-bg-05 transition-colors text-sm sm:text-base tracking-wide group"
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
>
Get in Touch
<svg
className="w-4 h-4 sm:w-5 sm:h-5 transform group-hover:translate-x-1 transition-transform"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</motion.a>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 sm:gap-8 font-['Instrument_Sans'] text-sm sm:text-base tracking-wide border-t theme-border pt-6 sm:pt-8">
<div className="space-y-1.5 sm:space-y-2.5 group">
<span className="theme-text-40 block uppercase tracking-[0.2em] text-xs sm:text-sm">Email</span>
<a
href="mailto:jleibl@proton.me"
className="theme-text-90 hover:theme-primary transition-colors flex items-center gap-2 sm:gap-2.5 group-hover:gap-3 duration-300"
>
jleibl@proton.me
<svg
className="w-4 h-4 sm:w-5 sm:h-5 opacity-0 group-hover:opacity-100 transition-all -translate-x-4 group-hover:translate-x-0 duration-300"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</a>
</div>
<div className="space-y-1.5 sm:space-y-2.5">
<span className="theme-text-40 block uppercase tracking-[0.2em] text-xs sm:text-sm">Role</span>
<span className="theme-text-90">
Fullstack Developer
</span>
</div>
<div className="space-y-1.5 sm:space-y-2.5">
<span className="theme-text-40 block uppercase tracking-[0.2em] text-xs sm:text-sm">Experience</span>
<span className="theme-text-90">
5+ Years
</span>
</div>
</div>
</FadeIn>
</div>
</section>
);
};

View File

@ -0,0 +1,178 @@
---
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 FadeIn from '../ui/FadeIn.astro';
interface Project {
title: string;
year: string;
description: string;
icon: any;
tags: Array<{
name: string;
icon: any;
}>;
}
const getTagIcon = (tag: string) => {
switch (tag) {
case 'Next.js':
return SiNextdotjs;
case 'Tailwind CSS':
return SiTailwindcss;
case 'TypeScript':
return SiTypescript;
case 'PHP':
return SiPhp;
case 'JavaScript':
return SiJavascript;
case 'MySQL':
return SiMysql;
case 'Performance':
return BsLightningChargeFill;
case 'Discord API':
return SiDiscord;
default:
return null;
}
};
const getProjectIcon = (title: string) => {
if (title.includes('ventry')) {
return MdLaunch;
} else if (title.includes('ShareUpload')) {
return HiOutlineCollection;
} else if (title.includes('RestoreM')) {
return SiDiscord;
} else {
return FaCode;
}
};
const projects: Project[] = [
{
title: 'ventry.host v2',
year: '2025',
description: 'Free file hosting revamped with a modern design and improved user experience.',
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.',
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.',
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.',
icon: getProjectIcon('RestoreM'),
tags: [
{ name: 'PHP', icon: getTagIcon('PHP') },
{ name: 'MySQL', icon: getTagIcon('MySQL') },
{ name: 'Discord API', icon: getTagIcon('Discord API') }
]
}
];
const sortedProjects = [...projects].sort((a, b) => {
return parseInt(b.year) - parseInt(a.year);
});
---
<section id="work" class="py-20 sm:py-40 px-4 sm:px-8 relative">
<div class="absolute inset-0 bg-linear-to-b from-transparent via-white/[0.02] to-transparent pointer-events-none theme-bg-gradient"></div>
<div class="max-w-(--breakpoint-xl) mx-auto relative">
<FadeIn>
<div class="flex flex-col gap-3 mb-12 sm:mb-24">
<span class="theme-text-40 uppercase tracking-[0.2em] text-sm sm:text-base font-['Instrument_Sans']">
Portfolio
</span>
<div class="flex items-baseline gap-4">
<h2 class="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary">
Selected Work
</h2>
<div class="h-px grow theme-border"></div>
</div>
</div>
</FadeIn>
<div class="grid gap-24 sm:gap-40">
{sortedProjects.map((project, index) => (
<FadeIn delay={index * 0.1}>
<div class="group relative">
<div class="absolute top-0 left-0 right-0 flex items-center gap-4">
<div class="font-['Instrument_Sans'] text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em] py-2 pr-4">
{project.year}
</div>
<div class="h-px grow theme-border"></div>
</div>
<div class="pt-12 sm:pt-16 grid grid-cols-1 lg:grid-cols-[1.5fr_1fr] gap-6 sm:gap-16">
<div class="space-y-4 sm:space-y-8">
<h3 class="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary group-hover:theme-text-90 transition-colors">
{project.title}
</h3>
<p class="font-['Instrument_Sans'] text-base sm:text-xl theme-text-70 leading-relaxed group-hover:theme-text-70 transition-colors max-w-xl">
{project.description}
</p>
</div>
<div class="space-y-6 sm:space-y-12">
<div class="space-y-4 sm:space-y-6">
<h4 class="font-['Instrument_Sans'] text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em]">
Technologies
</h4>
<div class="flex flex-wrap items-center gap-3 sm:gap-4">
{project.tags.map((tag, tagIndex) => {
const Icon = tag.icon;
return (
<span
class="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-xs"
>
<span class="mr-2 flex items-center">
<Icon className="text-lg" />
</span>
{tag.name}
{tagIndex !== project.tags.length - 1 && (
<span class="ml-2 opacity-0">•</span>
)}
</span>
);
})}
</div>
</div>
</div>
</div>
<div class="absolute -inset-x-4 sm:-inset-x-8 -inset-y-4 sm:-inset-y-6 rounded-2xl sm:rounded-3xl border border-white/0 group-hover:theme-border transition-colors"></div>
</div>
</FadeIn>
))}
</div>
</div>
</section>

View File

@ -1,178 +0,0 @@
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;
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.',
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.',
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.',
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.',
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">
<div className="absolute inset-0 bg-linear-to-b from-transparent via-white/[0.02] to-transparent pointer-events-none theme-bg-gradient"></div>
<div className="max-w-(--breakpoint-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>
<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>
<div className="h-px grow theme-border"></div>
</div>
</div>
</FadeIn>
<div className="grid gap-24 sm:gap-40">
{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">
<div className="font-['Instrument_Sans'] text-sm sm:text-base theme-text-40 uppercase tracking-[0.2em] py-2 pr-4">
{project.year}
</div>
<div className="h-px grow theme-border"></div>
</div>
<div className="pt-12 sm:pt-16 grid grid-cols-1 lg:grid-cols-[1.5fr_1fr] gap-6 sm:gap-16">
<div className="space-y-4 sm:space-y-8">
<h3 className="font-['DM_Sans'] text-3xl sm:text-6xl font-semibold tracking-tight theme-primary group-hover:theme-text-90 transition-colors">
{project.title}
</h3>
<p className="font-['Instrument_Sans'] text-base sm:text-xl theme-text-70 leading-relaxed group-hover:theme-text-70 transition-colors max-w-xl">
{project.description}
</p>
</div>
<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>
<div className="flex flex-wrap items-center gap-3 sm:gap-4">
{project.tags.map((tag, tagIndex) => (
<span
key={tagIndex}
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-xs"
>
<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>
))}
</div>
</div>
</div>
</div>
<div className="absolute -inset-x-4 sm:-inset-x-8 -inset-y-4 sm:-inset-y-6 rounded-2xl sm:rounded-3xl border border-white/0 group-hover:theme-border transition-colors"></div>
</div>
</FadeIn>
))}
</div>
</div>
</section>
);
};