Add about components; implement projects

This commit is contained in:
Timothy Pidashev
2024-12-18 10:22:48 -08:00
parent d96a27e612
commit d5cbe73c2d
19 changed files with 639 additions and 22 deletions

View File

@@ -0,0 +1,134 @@
import React from 'react';
import { Code2, BookOpen, RocketIcon, Compass } from 'lucide-react';
export default function CurrentFocus() {
const recentProjects = [
{
title: "Project Name 1",
description: "Short description of the project",
href: "/projects/project-1",
tech: ["React", "TypeScript", "Node.js"]
},
{
title: "Project Name 2",
description: "Short description of the project",
href: "/projects/project-2",
tech: ["Python", "Django", "PostgreSQL"]
},
{
title: "Project Name 3",
description: "Short description of the project",
href: "/projects/project-3",
tech: ["Next.js", "Tailwind", "Prisma"]
}
];
return (
<div className="flex justify-center items-center w-full">
<div className="w-full max-w-6xl p-4 sm:px-6 py-6 sm:py-8">
<h2 className="text-3xl sm:text-4xl font-bold text-center text-yellow-bright mb-8 sm:mb-12">
Current Focus
</h2>
{/* Recent Projects Section */}
<div className="mb-8 sm:mb-16">
<div className="flex items-center justify-center gap-2 mb-6">
<Code2 className="text-yellow-bright" size={24} />
<h3 className="text-xl font-bold text-foreground/90">Recent Projects</h3>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6 max-w-5xl mx-auto">
{recentProjects.map((project) => (
<a
href={project.href}
key={project.title}
className="p-4 sm:p-6 rounded-lg border border-foreground/10 hover:border-yellow-bright/50
transition-all duration-300 group bg-background/50"
>
<h4 className="font-bold text-lg group-hover:text-yellow-bright transition-colors">
{project.title}
</h4>
<p className="text-foreground/70 mt-2 text-sm sm:text-base">{project.description}</p>
<div className="flex flex-wrap gap-2 mt-3">
{project.tech.map((tech) => (
<span key={tech} className="text-xs px-2 py-1 rounded-full bg-foreground/5 text-foreground/60">
{tech}
</span>
))}
</div>
</a>
))}
</div>
</div>
{/* Current Learning & Interests */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8 max-w-5xl mx-auto">
{/* What I'm Learning */}
<div className="space-y-4 p-4 sm:p-6 rounded-lg border border-foreground/10 bg-background/50">
<div className="flex items-center justify-center gap-2">
<BookOpen className="text-green-bright" size={24} />
<h3 className="text-lg sm:text-xl font-bold text-foreground/90">Currently Learning</h3>
</div>
<ul className="space-y-3 text-sm sm:text-base text-foreground/70">
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-green-bright flex-shrink-0" />
<span>Rust Programming</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-green-bright flex-shrink-0" />
<span>WebAssembly with Rust</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-green-bright flex-shrink-0" />
<span>HTTP/3 & WebTransport</span>
</li>
</ul>
</div>
{/* Project Interests */}
<div className="space-y-4 p-4 sm:p-6 rounded-lg border border-foreground/10 bg-background/50">
<div className="flex items-center justify-center gap-2">
<RocketIcon className="text-blue-bright" size={24} />
<h3 className="text-lg sm:text-xl font-bold text-foreground/90">Project Interests</h3>
</div>
<ul className="space-y-3 text-sm sm:text-base text-foreground/70">
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-blue-bright flex-shrink-0" />
<span>AI Model Integration</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-blue-bright flex-shrink-0" />
<span>Rust Systems Programming</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-blue-bright flex-shrink-0" />
<span>Cross-platform WASM Apps</span>
</li>
</ul>
</div>
{/* Areas to Explore */}
<div className="space-y-4 p-4 sm:p-6 rounded-lg border border-foreground/10 bg-background/50">
<div className="flex items-center justify-center gap-2">
<Compass className="text-purple-bright" size={24} />
<h3 className="text-lg sm:text-xl font-bold text-foreground/90">Want to Explore</h3>
</div>
<ul className="space-y-3 text-sm sm:text-base text-foreground/70">
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-purple-bright flex-shrink-0" />
<span>LLM Fine-tuning</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-purple-bright flex-shrink-0" />
<span>Rust 2024 Edition</span>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-purple-bright flex-shrink-0" />
<span>Real-time Web Transport</span>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,11 +1,11 @@
import React from "react";
import { ChevronDown } from "lucide-react";
import { ChevronDownIcon } from "@/components/icons";
export default function Intro() {
const scrollToNext = () => {
window.scrollTo({
top: window.innerHeight,
behavior: 'smooth'
behavior: "smooth"
});
};
@@ -26,7 +26,7 @@ export default function Intro() {
</h2>
<div className="text-sm sm:text-xl text-foreground/70 space-y-2 sm:space-y-3">
<p className="flex items-center justify-center font-bold sm:justify-start gap-2">
<span className="text-blue">Full Stack Developer</span>
<span className="text-blue">Software Systems Engineer</span>
</p>
<p className="flex items-center justify-center font-bold sm:justify-start gap-2">
<span className="text-green">Open Source Enthusiast</span>
@@ -39,7 +39,7 @@ export default function Intro() {
</div>
<div className="space-y-8">
<p className="text-foreground/80 text-center text-base sm:text-2xl italic max-w-3xl mx-auto font-medium">
Coffee-to-code conversion isn't just a clever phrase
"Turning coffee into code" isn't just a clever phrase
<span className="text-aqua-bright"> it's how I approach each project:</span>
<span className="text-purple-bright"> methodically,</span>
<span className="text-blue-bright"> with attention to detail,</span>
@@ -51,7 +51,7 @@ export default function Intro() {
className="text-foreground/50 hover:text-yellow-bright transition-colors duration-300"
aria-label="Scroll to next section"
>
<ChevronDown size={40} className="animate-bounce" />
<ChevronDownIcon size={40} className="animate-bounce" />
</button>
</div>
</div>

View File

@@ -0,0 +1,65 @@
import React from 'react';
import { Fish, Mountain, Book, Car } from 'lucide-react';
export default function OutsideCoding() {
const interests = [
{
icon: <Fish className="text-blue-bright" size={20} />,
title: "Fishing",
description: "Finding peace and adventure on the water, always looking for the next great fishing spot"
},
{
icon: <Mountain className="text-green-bright" size={20} />,
title: "Hiking",
description: "Exploring trails with friends and seeking out scenic viewpoints in nature"
},
{
icon: <Book className="text-purple-bright" size={20} />,
title: "Reading",
description: "Deep diving into novels & technical books that expand my horizons & captivate my mind"
},
{
icon: <Car className="text-yellow-bright" size={20} />,
title: "Project Cars",
description: "Working on automotive projects, modifying & restoring sporty sedans"
}
];
return (
<div className="flex justify-center items-center w-full">
<div className="w-full max-w-4xl px-4 py-8">
<h2 className="text-2xl md:text-4xl font-bold text-center text-yellow-bright mb-8">
Outside of Programming
</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
{interests.map((interest) => (
<div
key={interest.title}
className="flex flex-col items-center text-center p-4 rounded-lg border border-foreground/10
hover:border-yellow-bright/50 transition-all duration-300 bg-background/50"
>
<div className="mb-3">
{interest.icon}
</div>
<h3 className="font-bold text-foreground/90 mb-2">
{interest.title}
</h3>
<p className="text-sm text-foreground/70">
{interest.description}
</p>
</div>
))}
</div>
<p className="text-center text-foreground/80 mt-8 max-w-2xl mx-auto text-sm md:text-base italic">
When I'm not writing code, you'll find me
<span className="text-blue-bright"> out on the water,</span>
<span className="text-green-bright"> hiking trails,</span>
<span className="text-purple-bright"> reading books,</span>
<span className="text-yellow-bright"> or modifying my current ride.</span>
</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,81 @@
import React from "react";
import { Check, Code, GitBranch, Star } from "lucide-react";
export default function Timeline() {
const timelineItems = [
{
year: "2024",
title: "Present",
description: "The wisdom of past ventures now flows through my work, whether crafting elegant CRUD applications or embarking on bold projects that expand my limits.",
technologies: ["Rust", "Typescript", "Go", "Postgres"],
icon: <Code className="text-yellow-bright" size={20} />
},
{
year: "2022",
title: "Diving Deeper",
description: "The worlds of systems programming and scalable infrastructure collided as I explored low-level C++ graphics programming and containerization with Docker.",
technologies: ["C++", "Cmake", "Docker", "Docker Compose"],
icon: <GitBranch className="text-green-bright" size={20} />
},
{
year: "2020",
title: "Exploring the Stack",
description: "Starting with pure HTML and CSS, I explored the foundations of web development, gradually venturing into JavaScript and React to bring my static pages to life.",
technologies: ["Javascript", "Tailwind", "React", "Express"],
icon: <Star className="text-blue-bright" size={20} />
},
{
year: "2018",
title: "Starting the Journey",
description: "An elective Python class in 8th grade transformed my keen interest in programming into a relentless obsession, one that drove me to constantly explore new depths.",
technologies: ["Python", "Discord.py", "Asyncio", "Sqlite"],
icon: <Check className="text-purple-bright" size={20} />
}
];
return (
<div className="w-full max-w-6xl px-4 py-8 relative z-0">
<h2 className="text-2xl md:text-4xl font-bold text-center text-yellow-bright mb-8 md:mb-12">
Journey Through Code
</h2>
<div className="relative">
<div className="absolute left-4 sm:left-1/2 h-full w-0.5 bg-foreground/10 -translate-x-1/2" />
<div className="ml-8 sm:ml-0">
{timelineItems.map((item, index) => (
<div key={item.year} className="relative mb-8 md:mb-12 last:mb-0">
<div className={`flex flex-col sm:flex-row items-start ${
index % 2 === 0 ? 'sm:flex-row-reverse' : ''
}`}>
<div className="absolute -left-8 sm:left-1/2 w-6 h-6 sm:w-8 sm:h-8 bg-background
rounded-full border-2 border-yellow-bright sm:-translate-x-1/2
flex items-center justify-center z-10">
{item.icon}
</div>
<div className={`w-full sm:w-[calc(50%-32px)] ${
index % 2 === 0 ? 'sm:pr-8 md:pr-12' : 'sm:pl-8 md:pl-12'
}`}>
<div className="p-4 sm:p-6 bg-background/50 rounded-lg border border-foreground/10
hover:border-yellow-bright/50 transition-colors duration-300">
<span className="text-xs sm:text-sm font-mono text-yellow-bright">{item.year}</span>
<h3 className="text-lg sm:text-xl font-bold text-foreground/90 mt-2">{item.title}</h3>
<p className="text-sm sm:text-base text-foreground/70 mt-2">{item.description}</p>
<div className="flex flex-wrap gap-2 mt-3">
{item.technologies.map((tech) => (
<span key={tech}
className="px-2 py-1 text-xs sm:text-sm rounded-full bg-foreground/5
text-foreground/60 hover:text-yellow-bright transition-colors duration-300">
{tech}
</span>
))}
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}

View File

@@ -27,7 +27,7 @@ export default function Header() {
));
return (
<header className={`fixed top-0 left-0 right-0 bg-black font-bold transition-transform duration-300 ${
<header className={`fixed z-50 top-0 left-0 right-0 bg-black font-bold transition-transform duration-300 ${
visible ? "translate-y-0" : "-translate-y-full"
}`}>
<div className="flex flex-row pt-1 px-2 text-lg lg:pt-2 lg:text-3xl md:text-2xl items-center justify-between md:justify-center space-x-2 md:space-x-10 lg:space-x-20">

View File

@@ -0,0 +1,78 @@
import React from "react"
import type { CollectionEntry } from "astro:content";
interface ProjectCardProps {
project: CollectionEntry<"projects">;
}
export function ProjectCard({ project }: ProjectCardProps) {
const hasLinks = project.data.githubUrl || project.data.demoUrl;
return (
<article className="group relative h-full">
<a
href={`/projects/${project.slug}`}
className="block rounded-lg border-2 border-foreground/20
hover:border-blue transition-all duration-300
bg-background overflow-hidden h-full flex flex-col"
>
<div className="aspect-video w-full border-b border-foreground/20 bg-foreground/5 overflow-hidden flex-shrink-0">
{project.data.image ? (
<img
src={project.data.image}
alt={`${project.data.title} preview`}
className="w-full h-full object-cover object-center group-hover:scale-105 transition-transform duration-300"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-foreground/30">
<span className="text-sm">No preview available</span>
</div>
)}
</div>
<div className="p-4 sm:p-6 space-y-3 flex flex-col flex-grow">
<h3 className="text-lg sm:text-xl font-bold group-hover:text-blue transition-colors">
{project.data.title}
</h3>
<div className="flex flex-wrap gap-2">
{project.data.techStack.map(tech => (
<span key={tech} className="text-xs px-2 py-1 rounded-full bg-purple-bright/10 text-purple-bright">
{tech}
</span>
))}
</div>
<p className="text-foreground/70 text-sm sm:text-base flex-grow">
{project.data.description}
</p>
{hasLinks && (
<div className="flex gap-4 pt-3 border-t border-foreground/10 mt-auto">
{project.data.githubUrl && (
<a
href={project.data.githubUrl}
className="text-sm text-blue hover:text-blue-bright
transition-colors z-10"
onClick={(e) => e.stopPropagation()}
>
View Source
</a>
)}
{project.data.demoUrl && (
<a
href={project.data.demoUrl}
className="text-sm text-green hover:text-green-bright
transition-colors z-10"
onClick={(e) => e.stopPropagation()}
>
Live Link
</a>
)}
</div>
)}
</div>
</a>
</article>
);
}

View File

@@ -0,0 +1,45 @@
import React from "react";
import type { CollectionEntry } from "astro:content";
import { ProjectCard } from "@/components/projects/project-card";
interface ProjectListProps {
projects: CollectionEntry<"projects">[];
}
export function ProjectList({ projects }: ProjectListProps) {
const latestProjects = projects.slice(0, 3);
const otherProjects = projects.slice(3);
return (
<div className="w-full max-w-6xl mx-auto pt-24 sm:pt-32">
<h1 className="text-2xl sm:text-3xl font-bold text-blue mb-12 text-center px-4 leading-relaxed">
Here's what I've been <br className="sm:hidden" />
building lately
</h1>
<div className="px-4 mb-16">
<h2 className="text-xl font-bold text-foreground/90 mb-6">
Featured Projects
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{latestProjects.map(project => (
<ProjectCard key={project.slug} project={project} />
))}
</div>
</div>
{otherProjects.length > 0 && (
<div className="px-4 pb-8">
<h2 className="text-xl font-bold text-foreground/90 mb-6">
All Projects
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{otherProjects.map(project => (
<ProjectCard key={project.slug} project={project} />
))}
</div>
</div>
)}
</div>
);
}

View File

@@ -10,4 +10,15 @@ export const collections = {
date: z.string(),
}),
}),
}
projects: defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
githubUrl: z.string().url().optional(),
demoUrl: z.string().url().optional(),
techStack: z.array(z.string()),
date: z.string(),
image: z.string().optional(),
}),
}),
};

View File

@@ -0,0 +1,9 @@
---
title: "AI Code Review Assistant"
description: "An AI-powered code review tool that integrates with GitHub to provide automated code analysis and suggestions"
githubUrl: "https://github.com/username/ai-code-reviewer"
techStack: ["Python", "OpenAI API", "GitHub API", "FastAPI"]
date: "2024-02-28"
image: "/projects/ai-reviewer-preview.png"
---

View File

@@ -0,0 +1,8 @@
---
title: "Embedded Rust Framework"
description: "A framework for writing embedded systems applications in Rust with a focus on safety and performance"
githubUrl: "https://github.com/username/embedded-rust"
techStack: ["Rust", "Embedded Systems", "RTOS", "HAL"]
date: "2024-01-15"
image: "/projects/embedded-preview.png"
---

View File

@@ -0,0 +1,9 @@
---
title: "LLM Fine-tuning Pipeline"
description: "A toolkit for fine-tuning large language models on custom datasets with optimized training procedures"
githubUrl: "https://github.com/username/llm-fine-tuning"
demoUrl: "https://llm-tuning.demo.dev"
techStack: ["Python", "PyTorch", "CUDA", "MLFlow"]
date: "2024-01-01"
image: "/projects/llm-preview.png"
---

View File

@@ -0,0 +1,9 @@
---
title: "Real-time Collaboration Editor"
description: "A collaborative text editor with real-time synchronization using WebTransport protocol for minimal latency"
githubUrl: "https://github.com/username/real-time-collab"
demoUrl: "https://collab.demo.dev"
techStack: ["TypeScript", "React", "WebTransport", "CRDT"]
date: "2024-02-10"
image: "/projects/collab-preview.png"
---

View File

@@ -0,0 +1,26 @@
---
title: "Project Name"
description: "Project description here"
demoUrl: "https://demo.project.com" # optional
techStack: ["React", "TypeScript", "Tailwind"]
date: "2024-03-15"
image: "/projects/preview.png" # optional
---
# Project Overview
This is a detailed description of the project...
## Features
- Feature 1
- Feature 2
- Feature 3
## Technical Details
Here's how it works...
## Challenges & Solutions
During development...

View File

@@ -0,0 +1,27 @@
---
title: "Rust WASM Game Engine"
description: "A lightweight 2D game engine built with Rust and compiled to WebAssembly for high-performance browser games"
githubUrl: "https://github.com/username/rust-wasm-game"
demoUrl: "https://rust-wasm-game.demo.dev"
techStack: ["Rust", "WebAssembly", "Canvas API", "Web Workers"]
date: "2024-03-15"
image: "/projects/rust-wasm-preview.png"
---
# Project Overview
This is a detailed description of the project...
## Features
- Feature 1
- Feature 2
- Feature 3
## Technical Details
Here's how it works...
## Challenges & Solutions
During development...

View File

@@ -0,0 +1,33 @@
---
import "@/style/globals.css";
import Header from "@/components/header";
import Footer from "@/components/footer";
export interface Props {
title: string;
description?: string;
permalink?: string;
}
const { title, description, permalink } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>{title}</title>
{description && <meta name="description" content={description} />}
{permalink && <link rel="canonical" href={permalink} />}
</head>
<body class="bg-background text-foreground">
<Header client:load />
<main>
<div class="max-w-5xl mx-auto pt-12 px-4 py-8">
<slot />
</div>
</main>
<Footer client:load />
</body>
</html>

View File

@@ -1,12 +1,27 @@
---
import "@/style/globals.css"
import MainLayout from "@/layouts/main.astro";
import Intro from "@/components/about/intro";
import Timeline from "@/components/about/timeline";
import CurrentFocus from "@/components/about/current-focus";
import OutsideCoding from "@/components/about/outside-coding";
---
<MainLayout content={{ title: "About | Timothy Pidashev" }}>
<div class="flex items-center justify-center h-screen w-full">
<div class="min-h-screen">
<section class="h-screen flex items-center justify-center">
<Intro client:load />
</section>
<section class="flex items-center justify-center py-16">
<Timeline client:load />
</section>
<section class="flex items-center justify-center py-16">
<CurrentFocus client:load />
</section>
<section class="flex items-center justify-center py-16">
<OutsideCoding client:load />
</section>
</div>
</MainLayout>

View File

@@ -1,11 +0,0 @@
---
import "@/style/globals.css"
import MainLayout from "@/layouts/main.astro";
---
<MainLayout content={{ title: "Projects | Timothy Pidashev" }}>
<div class="flex items-center justify-center h-screen w-full">
<h1 class="text-4xl text-yellow font-bold">Projects</h1>
</div>
</MainLayout>

View File

@@ -0,0 +1,63 @@
---
import { getCollection } from "astro:content";
import ProjectsLayout from "@/layouts/projects.astro";
export async function getStaticPaths() {
const projects = await getCollection("projects");
return projects.map(project => ({
params: { slug: project.slug },
props: { project },
}));
}
const { project } = Astro.props;
const { Content } = await project.render();
---
<ProjectsLayout title={`${project.data.title} | Timothy Pidashev`}>
<article class="w-full mx-auto px-4 pt-6 sm:pt-12">
{/* Image Section */}
{project.data.image && (
<div class="w-full rounded-lg overflow-hidden mb-8 border-2 border-foreground/20 aspect-video">
<img
src={project.data.image}
alt={project.data.title}
class="w-full h-full object-cover"
/>
</div>
)}
<header class="mb-8">
<h1 class="text-3xl sm:text-4xl font-bold text-yellow-bright mb-4">
{project.data.title}
</h1>
<div class="flex flex-wrap gap-2 mb-4">
{project.data.techStack.map(tech => (
<span class="text-xs px-2 py-1 rounded-full bg-purple-bright/10 text-purple-bright">
{tech}
</span>
))}
</div>
<div class="flex gap-4">
{project.data.githubUrl && (
<a href={project.data.githubUrl}
class="text-foreground/70 hover:text-blue-bright transition-colors">
View Source
</a>
)}
{project.data.demoUrl && (
<a href={project.data.demoUrl}
class="text-foreground/70 hover:text-green-bright transition-colors">
Live Demo
</a>
)}
</div>
</header>
<div class="prose prose-invert max-w-none">
<Content />
</div>
</article>
</ProjectsLayout>

View File

@@ -0,0 +1,15 @@
---
import { getCollection } from "astro:content";
import ProjectsLayout from "@/layouts/projects.astro";
import { ProjectList } from "@/components/projects/project-list";
const projects = (await getCollection("projects", ({ data }) => {
return data.isDraft !== true;
})).sort(
(a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
);
---
<ProjectsLayout title="Projects | Timothy Pidashev">
<ProjectList projects={projects} client:load />
</ProjectsLayout>