Begin writing projects

This commit is contained in:
Timothy Pidashev
2024-12-18 13:53:21 -08:00
parent d5cbe73c2d
commit b618f6e807
15 changed files with 243 additions and 114 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -8,6 +8,7 @@ type BlogPost = {
date: string;
tags: string[];
description: string;
image?: string;
};
};
@@ -25,36 +26,70 @@ const formatDate = (dateString: string) => {
export const BlogPostList = ({ posts }: BlogPostListProps) => {
return (
<div className="max-w-3xl mx-auto px-4 py-8">
<ul className="space-y-8">
<div className="w-full max-w-4xl mx-auto">
<h1 className="text-3xl md:text-4xl font-bold mb-6 md:mb-10 text-yellow-bright px-4 md:px-0">Blog Posts</h1>
<ul className="space-y-6 md:space-y-10">
{posts.map((post) => (
<li key={post.slug} className="border-b border-gray-200 pb-8 last:border-b-0">
<li key={post.slug} className="group px-4 md:px-0">
<a
href={`/blog/${post.slug}`}
className="text-xl font-semibold hover:text-blue-600 transition-colors duration-200"
className="block"
>
<article className="flex flex-col md:flex-row gap-4 md:gap-8 pb-6 md:pb-10 border-b border-foreground/20 last:border-b-0 p-2 md:p-4 rounded-lg group-hover:outline group-hover:outline-2 group-hover:outline-purple transition-all duration-200">
{/* Image container with fixed aspect ratio */}
<div className="w-full md:w-1/3 aspect-[16/9] overflow-hidden rounded-lg bg-background">
<img
src={post.data.image || '/api/placeholder/400/300'}
alt={post.data.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
</div>
{/* Content container */}
<div className="w-full md:w-2/3 flex flex-col gap-2 md:gap-4 py-1 md:py-2">
{/* Title and meta info */}
<div className="space-y-1.5 md:space-y-3">
<h2 className="text-lg md:text-2xl font-semibold text-yellow group-hover:text-purple transition-colors duration-200 line-clamp-2">
{post.data.title}
</a>
<div className="mt-2 text-sm text-gray-600">
<span>{post.data.author}</span>
<span className="mx-2"></span>
<time dateTime={post.data.date}>
</h2>
<div className="flex flex-wrap items-center gap-2 md:gap-3 text-sm md:text-base text-foreground/80">
<span className="text-orange">{post.data.author}</span>
<span className="text-foreground/50"></span>
<time dateTime={post.data.date} className="text-blue">
{formatDate(post.data.date)}
</time>
</div>
<p className="mt-3 text-gray-700">
</div>
{/* Description */}
<p className="text-foreground/90 text-sm md:text-lg leading-relaxed line-clamp-2 mt-0.5 md:mt-0">
{post.data.description}
</p>
<div className="mt-3 space-x-2">
{post.data.tags.map((tag) => (
{/* Tags */}
<div className="flex flex-wrap gap-1.5 md:gap-3 mt-1 md:mt-2">
{post.data.tags.slice(0, 3).map((tag) => (
<span
key={tag}
className="text-sm text-gray-600"
className="text-xs md:text-base text-aqua hover:text-aqua-bright transition-colors duration-200"
onClick={(e) => {
e.preventDefault();
window.location.href = `/blog/tag/${tag}`;
}}
>
#{tag}
</span>
))}
{post.data.tags.length > 3 && (
<span className="text-xs md:text-base text-foreground/60">
+{post.data.tags.length - 3}
</span>
)}
</div>
</div>
</article>
</a>
</li>
))}
</ul>

View File

@@ -4,6 +4,7 @@ description: A quick introduction to generics with TypeScript
author: Timothy Pidashev
tags: [typescript]
date: December 25, 2021
image: "/path/to/your/image.jpg"
---
In this quick post we'll cover what are generics and how to use them with TypeScript. It answers a question I got from a friend, and I thought it could also be useful for others. We'll go through the following points:

View File

@@ -8,6 +8,7 @@ export const collections = {
author: z.string(),
tags: z.array(z.string()),
date: z.string(),
image: z.string().optional(),
}),
}),
projects: defineCollection({

View File

@@ -0,0 +1 @@
My gruvbox theme, with a pure black background

View File

View File

View File

@@ -1,9 +0,0 @@
---
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

@@ -1,8 +0,0 @@
---
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

@@ -1,9 +0,0 @@
---
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

@@ -1,9 +0,0 @@
---
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,179 @@
---
title: "Revive Auto Parts"
description: "A car parts listing site built for a client."
demoUrl: "https://reviveauto.parts"
techStack: ["Typescript", "Tanstack Router", "React Query"]
date: "2024-12-15"
image: "/projects/reviveauto/thumbnail.jpeg"
---
## Overview
A car parts listing website built to provide an intuitive and efficient experience
for users searching for automotive parts. This project was commissioned by a client
and showcases some pretty cool modern web technologies, enabling excellent
performance and a clean user interface.
## Key Features
* **Dynamic & Simple Routing**: Powered by TanStack Router, enabling seamless navigation
and deep-linking for product categories and details.
* **Real-Time Data Fetching**: Utilized React Query to handle server state and caching,
ensuring users have up-to-date information.
* **Infinite Scroll**: Implemented React Query's infinite scrolling and memoization
optimization techniques to ensure fast and seamless scrolling through listings.
* **Dynamic Filters**: Created dynamic filters which are editable on the admin panel,
allowing for a high level of customization.
* **Responsive Design**: Built with Tailwind and Shadcn for a fully responsive layout,
providing a consistent experience across desktop and mobile devices.
* **Optimized Performance**: Leveraged Vite for fast builds and optimized code-splitting,
improving page load times drastically.
## Development Highlights
I had numerous highlights and *aha* moments when developing this site. One of these has to
be the site layout, built with [shadcn/ui](https://ui.shadcn.com) components. I had used
this component library in a previous site, but I had yet to grasp just how powerful this
collection of components is. We truly do stand on the shoulders of giants, and using this
library not only allowed me to very quickly prototype a design, but to then flesh it out
without having to dive into the weeds of UI development.
Another great highlight has to be [Tanstack Router](https://tanstack.com/router/latest).
As a seasoned developer, I have had many opportunities to try a lot of different routers
across several frameworks. As many have before me, we stumble onto the nextjs router, and
tend not to look back. However, tanstack did something I did not expect, and it takes routing
to the next level. With TanStack, the routes folder is solely focused on defining routes and
layouts, providing a cleaner, more modular structure. This is a stark contrast to Next.js's
approach, where the app directory can quickly become convoluted by mixing route definitions
with server-side logic, API calls, and other concerns. Anybody who has built a Nextjs project
bigger than a To-Do app can likely relate to the mental pain that is trying to find a route or
endpoint in your app router when its nested and hidden away four or five directories deep.
Another memorable highlight was writing my backend in Python using [Fastapi](https://fastapi.tiangolo.com/).
Sometimes, a project doesn't need a complex nodejs runtime, or an ORM built for a massive service.
As a python enthusiast, I found the combination of fastapi & sqlmodel to be just perfect for this project,
and defining api endpoints and schemas were quite enjoyable. As I do, I decided to roll my own authentication,
and found Python to be a great environment in which to do so.
Lastly, I have to touch on React Query. The combo that is React Query and Fastapi can truly be magical.
To truly showcase what I mean, here's an example of a query and endpoint working together:
```typescript
// features/auth/services/login/queries.ts
export function useLogin() {
const { setCredentials } = useUserStore();
return useMutation<LoginResponseSchemaType, AxiosError<BackendError>, LoginRequestSchemaType>({
mutationFn: user => login(user),
onSuccess: data => {
setCredentials({
accessToken: data.access_token,
});
},
});
}
const login = backend<z.infer<typeof LoginRequestSchema>, z.infer<typeof LoginResponseSchema>>({
method: "POST",
path: `${BACKEND_URL}${AUTH}/login`,
requestSchema: LoginRequestSchema,
responseSchema: LoginResponseSchema,
type: "public",
});
```
```typescript
// features/auth/services/login/schemas
import { z } from "zod";
export const LoginRequestSchema = z.object({
email: z
.string()
.min(1, "Email is required!")
.trim()
.email({ message: "Invalid email!" })
.toLowerCase(),
password: z.string().trim().min(8, { message: "Password must be at least 8 characters long!" }),
});
export type LoginRequestSchemaType = z.infer<typeof LoginRequestSchema>;
export const LoginResponseSchema = z.object({
access_token: z.string(),
});
export type LoginResponseSchemaType = z.infer<typeof LoginResponseSchema>;
```
```python
# routes/auth.py
class LoginResponse(BaseModel):
access_token: str
@router.post(
"/login",
description=
"""
The login endpoint.
Used to create access and refresh tokens for a user.
The refresh token is set as an HTTP-only cookie.
""",
summary="Create access token and set refresh token as HTTP-only cookie."
)
async def login(
response: Response,
form_data: LoginSchema = Body(...),
session: Session = Depends(get_session)
) -> Any:
# Fetch user using the form_data sent by the client
user = await service.authenticate(
email=form_data.email,
password=form_data.password,
session=session
)
# If service returns None, raise exception
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
)
# Set refresh token as HTTP-only cookie
response.set_cookie(
key="refresh_token",
value=create_token(user, type="refresh"),
httponly=True,
path="/auth/refresh",
domain=Config.JWT_COOKIE_DOMAIN,
expires=datetime.now(timezone.utc) + Config.JWT_REFRESH_EXPIRES
)
return LoginResponse(
access_token=create_token(user, type="access")
)
```
Using Zod, the frontend is validating what a user is attempting to submit
before calling the endpoint. If Zod does not throw an error, our frontend will
call our backend endpoint, which also expects the right types to be present.
Afterwards, the backend will respond back with a response that our frontend
will also validate. This allows for a complete multi-directional
request -> response type validation!
## Challenges and Roadblocks
For the most part, there were really no challenges, say for some hiccups here and there.
Probably the most painful parts were creating unit tests for the frontend, and scraping
Facebook for a total of 1,384 posts for my client, who wanted the posts imported over.
As one can imagine, that process is not simple to do manually by hand, so I wrote multiple
python scriptsusing the seleneum library to fetch the posts from the sellers account, a process
which took multiple attempts, several overnight scrapes, and lots of data sanitation afterwards.
Other than that, everything else was an absolute joy to work on, and I finished the project in under
15K LOC.
## Summary
Sometimes, building a CRUD app can be lots of fun, no matter how many times you've done it before.
All it takes is adding something new to the stack, and striving to improve the code you write. This
project was exactly that, a mix of new technologies working together to power a fairly neat site,
which can be viewed [here](https://reviveauto.parts). Maybe there is a car part there which the reader
might need. As always, thanks for the read :)

View File

@@ -1,26 +0,0 @@
---
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

@@ -1,27 +0,0 @@
---
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

@@ -50,7 +50,7 @@ const { Content } = await project.render();
{project.data.demoUrl && (
<a href={project.data.demoUrl}
class="text-foreground/70 hover:text-green-bright transition-colors">
Live Demo
Live Link
</a>
)}
</div>