Compare commits

...

2 commits

Author SHA1 Message Date
Kaan Barmore-Genç 0f6a60bec9
Set some post images
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-05-11 00:30:08 -05:00
Kaan Barmore-Genç 30da668bd0
Add blog post descriptions 2024-05-11 00:26:07 -05:00
21 changed files with 133 additions and 68 deletions

View file

@ -12,14 +12,20 @@
<meta property="article:author" content="https://bgenc.net" />
<meta property="og:url" content={`https://bgenc.net/${data.slug}/`} />
<meta property="article:published_time" content={formatISO(new Date(data.date))} />
{#if data.updated}
<meta property="article:modified_time" content={formatISO(new Date(data.updated))} />
{/if}
{#if data.image}
<meta property="og:image" content={data.image} />
<meta
property="og:image"
content={data.image.startsWith('https://') ? data.image : `https://bgenc.net${data.image}`}
/>
{:else}
<meta property="og:image" content={`https://bgenc.net${Jpeg}`} />
{/if}
{#if data.excerpt}
<meta name="description" content={data.excerpt} />
<meta property="og:description" content={data.excerpt} />
{#if data.description}
<meta name="description" content={data.description} />
<meta property="og:description" content={data.description} />
{/if}
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Kaan Barmore-Genç's Site" />
@ -27,15 +33,26 @@
<article data-pagefind-body>
<h1>{data.title}</h1>
<time datetime={data.date}>
{format(new Date(data.date), 'MMMM d, yyyy')}
</time>
{#if data.updated}
<p>
Written on <time datetime={data.date}
>{format(new Date(data.date), 'MMMM d, yyyy')}, last updated on
<time datetime={data.updated}
>{format(new Date(data.updated), 'MMMM d, yyyy')}.
</time></time
>
</p>
{:else}
<p>
Written on <time datetime={data.date}>{format(new Date(data.date), 'MMMM d, yyyy')}.</time>
</p>
{/if}
<svelte:component this={data.content} />
</article>
<style>
time {
display: block;
margin-bottom: 4rem;
}
</style>

View file

@ -1,14 +1,15 @@
export async function load({ params }) {
const post = await import(`../posts/${params.slug}.md`);
const { title, date, excerpt, image } = post.metadata;
const { title, date, description, image, updated } = post.metadata;
const content = post.default;
return {
content,
title,
excerpt,
description,
image,
date,
updated,
slug: params.slug,
};
}

View file

@ -9,6 +9,7 @@ tags:
- react
- web
- dev
description: Stop Redux from tanking your web app's performance. Follow along as I diagnose and solve a React performance issue.
---
This might be obvious for some, but I was struggling with a performance issue in
@ -88,7 +89,7 @@ the objects (the object is flat so I don't need recursion).
```ts
export function shallowEquals<
Left extends Record<string, unknown>,
Right extends Record<string, unknown>
Right extends Record<string, unknown>,
>(left: Left, right: Right) {
if (Object.keys(left).length !== Object.keys(right).length) return false;
for (const key of Object.keys(left)) {
@ -100,7 +101,7 @@ export function shallowEquals<
// ...
const { access_token, site } = useAppSelector(
(selector) => pick(selector.auth, 'access_token', 'site'),
shallowEquals
shallowEquals,
);
```

View file

@ -1,10 +1,11 @@
---
title: "Automating My Blog With Gitea and Woodpecker"
title: 'Automating My Blog With Gitea and Woodpecker'
date: 2022-11-19T12:21:40-05:00
toc: false
images:
tags:
- homelab
description: I automated my personal projects with a surprisingly simple CI/CD tool called Woodpecker. Discover how to build and deploy code from your Gitea with just Docker containers!
---
I had been using Gitea for a while. If you haven't heard of it before, it's a

View file

@ -6,6 +6,7 @@ images:
tags:
- dev
- web
description: A short piece about a weird XML parsing error I had to deal with, including some Rust code.
---
I've been seeing this error a lot while working on my project [Bulgur Cloud](/bulgur-cloud-intro/).

View file

@ -1,11 +1,12 @@
---
title: "Hosting websites without a static IP with Gandi LiveDNS"
title: 'Hosting websites without a static IP with Gandi LiveDNS'
date: 2022-12-29T18:11:42-05:00
toc: false
images:
tags:
- web
- homelab
description: Want to ditch expensive dynamic DNS and keep your home server online? I built a tool to use Gandi's free LiveDNS with lightning-fast updates under 250ms!
---
I've been hosting this website at home now for a few years. My ISP doesn't offer
@ -58,6 +59,7 @@ fqdn = "kaangenc.me"
name = "@"
types = ["A"]
```
The configuration file is a bit trimmed, but it shows the gist of everything.
I'm updating `bgenc.net`, along with `gitea.bgenc.net`. I also update
`kaangenc.me`, which is an old domain I was using.

View file

@ -1,11 +1,12 @@
---
title: "Get inferred type for a generic parameter in TypeScript"
title: 'Get inferred type for a generic parameter in TypeScript'
date: 2023-01-28T14:50:54-05:00
toc: false
images:
tags:
- dev
- typescript
description: "Dive into using TypeScript to extract inferred types, inspired by Zod's schema inference magic."
---
Have you used [Zod](https://zod.dev/)? It's a very cool TypeScript library for
@ -14,8 +15,8 @@ strenghts of Zod is that it can do type inference. For example,
```ts
const PersonSchema = z.object({
name: z.string(),
age: z.number(),
name: z.string(),
age: z.number(),
});
type Person = z.infer<typeof PersonSchema>;

View file

@ -5,6 +5,7 @@ toc: false
images:
tags:
- dev
description: Let's explore how to use DevContainers to create a one-click development environment with all the tools and services you need.
---
It is important to have a consistent and streamlined setup process for your

View file

@ -1,10 +1,12 @@
---
title: Enforcing a "Do Not Merge" label with Github Actions
date: 2023-02-18T12:33:32-05:00
updated: 2024-05-11T12:08:00-06:00
toc: false
images:
image: /img/gh-do-not-merge-action.png
tags:
- dev
description: Stop accidental code deployments with a clever GitHub Actions trick using labels to prevent merging pull requests until they're truly ready.
---
At my workplace, we sometimes find ourselves in situations where a PR passes all
@ -103,3 +105,7 @@ This will only apply to new repositories, so you may need to add
the label to your existing repositories. But even if you don't add the label to
the repository, the check should not block you so you don't have to worry about
going through all your repositories to add this label.
> **Update:** We have stopped using this action since. Github Action seemed to
> occasionally get stuck, blocking us from merging PRs even after the label was
> removed.

View file

@ -1,11 +1,12 @@
---
title: "Making the Slow Explicit: Dynamodb vs SQL"
title: 'Making the Slow Explicit: Dynamodb vs SQL'
date: 2023-02-26T15:51:19-05:00
toc: false
images:
tags:
- dev
- web
description: Bad SQL habits are to blame for slow databases, not NoSQL magic. Here's my thoughts on how DynamoDB forces better code for scalability.
---
SQL databases like MySQL, MariaDB, and PostgreSQL are highly performant and can
@ -16,7 +17,8 @@ Proponents of DynamoDB like Alex DeBrie, the author of ["The DynamoDB Book"](htt
point to a few things for this difference: HTTP-based APIs of NoSQL databases are more efficient than TCP connections used by SQL databases,
table joins are slow, SQL databases are designed to save disk space while NoSQL databases take advantage of large modern disks.[^1]
[^1]: I don't have my copy of the book handy, so I wrote these arguments from
[^1]:
I don't have my copy of the book handy, so I wrote these arguments from
memory. I'm confident that I remember them correctly, but apologies if I
misremembered some details.

View file

@ -2,7 +2,8 @@
title: 'Setting up my blog as an Onion service (Tor hidden service)'
date: 2023-03-05T15:54:13-05:00
toc: false
images:
image: /img/tor-censorship-snowflake-chart.webp
description: See how you can use Tor and Docker to create your own hidden onion service, perfect for tech enthusiasts and privacy advocates.
---
If you don't know about it, Tor is a software that helps online privacy and

View file

@ -2,9 +2,10 @@
title: 'Self Hosted Backups with Minio, Kopia, and Tailscale'
date: 2023-04-25T00:11:31-04:00
toc: false
images:
image: /img/2023-04-25.tailscale.png
tags:
- homelab
description: Ditch complex SSH setups and leverage Minio's S3 compatibility with Tailscale for secure, encrypted backups.
---
I've been struggling with my local backup setup for a while now.

View file

@ -1,10 +1,11 @@
---
title: "Fully Headless Setup for Raspberry Pi"
title: 'Fully Headless Setup for Raspberry Pi'
date: 2023-04-27T20:40:00-04:00
toc: false
images:
tags:
- homelab
description: Don't feel like hooking up a monitor and keyboard to your Raspberry Pi? I'll show you how to set up your Raspberry Pi for headless SSH access using just a few commands.
---
I always hit this issue: I have a Raspberry Pi I want to set up, but I don't

View file

@ -6,6 +6,7 @@ images:
tags:
- dev
- web
description: Here is how to make a text area that resizes automatically and has placeholder text, with no JavaScript with this clever CSS trick!
---
The HTML elements `input` and `textarea` include a `placeholder` property. This

View file

@ -2,11 +2,12 @@
title: 'Getting theme colors in JavaScript using React with DaisyUI and TailwindCSS'
date: 2023-08-10T00:18:27-05:00
toc: false
images:
image: /img/2023-08-10.chartjs.png
tags:
- web
- dev
- react
description: This post shows you how to use JavaScript to read CSS variables and create dynamic UIs, using SWR for seamless light & dark mode switching!
---
I've been building a web app using React and TailwindCSS, with DaisyUI. But

View file

@ -1,10 +1,11 @@
---
title: "Next.js error about native node modules using bindings"
title: 'Next.js error about native node modules using bindings'
date: 2023-08-13T16:44:41Z
toc: false
images:
tags:
- dev
description: Struggling to use a native node module with bindings in your Next.js app? I dive into a weird Webpack/Terser issue and a clever Next.js-specific solution to get it working smoothly.
---
This might be a little niche, but I had trouble finding anyone else write about
@ -35,9 +36,9 @@ bundle a module. You can configure this with the
```js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverComponentsExternalPackages: ["libheif-node-dy"],
},
experimental: {
serverComponentsExternalPackages: ['libheif-node-dy'],
},
};
module.exports = nextConfig;

View file

@ -1,9 +1,10 @@
---
title: "Amazon SES Production Access Approval"
title: 'Amazon SES Production Access Approval'
date: 2023-10-03T04:34:37Z
toc: false
images:
tags:
description: Is your Amazon SES approval getting declined? My odyssey through email services & how to finally get the green light (with code!)
---
I've been setting up something for a relative who's trying to start a business,
@ -86,7 +87,7 @@ guess that's the "security purposes".
I'm sure there are other things to consider and explain, but this worked for me.
If you get denied, reopen the case, add even more screenshots and information
and try again.
and try again.
## Brevo
@ -97,38 +98,38 @@ is the code for that actually:
```ts
export type Email = {
sender: {
name: string;
email: string;
};
to: string;
content: {
text: string;
html: string;
};
subject: string;
sender: {
name: string;
email: string;
};
to: string;
content: {
text: string;
html: string;
};
subject: string;
};
export async function sendEmailBrevo({
sender,
to,
content: { html: htmlContent, text: textContent },
subject,
sender,
to,
content: { html: htmlContent, text: textContent },
subject,
}: Email) {
await fetch("https://api.brevo.com/v3/smtp/email", {
method: "POST",
headers: {
accept: "application/json",
"content-type": "application/json",
"api-key": process.env.BREVO_API_KEY,
},
body: JSON.stringify({
sender,
to: [{ email: to }],
subject,
htmlContent,
textContent,
}),
});
await fetch('https://api.brevo.com/v3/smtp/email', {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
'api-key': process.env.BREVO_API_KEY,
},
body: JSON.stringify({
sender,
to: [{ email: to }],
subject,
htmlContent,
textContent,
}),
});
}
```

View file

@ -6,6 +6,7 @@ images:
tags:
- dev
- rust
description: Unleash developer zen with a Rust CLI organization trick! This post uses Clap and a custom trait to create a file system mirrored command structure, making your code a breeze to navigate and maintain.
---
Here's a pattern came up with for building CLI tools in Rust using

View file

@ -9,6 +9,7 @@ tags:
- react
- mobile
- typescript
description: Love fresh sourdough bread but hate remembering to feed your starter? This post details my journey of building a mobile app (with open-source tools) to manage sourdough starter feeding schedules and take the guesswork out of perfect sourdough.
---
I like baking bread. Well, most of all I love bread, and baking it myself is
@ -205,4 +206,4 @@ This is getting really long (for my usual posts), so a few more quick mentions:
I'm about done with the basic functionality I wanted for this app, so I'm hoping
to have a version of this up on the Google Play store by the end of the week.
Oh and I still haven't made that sourdough starter,
Oh and I still haven't made that sourdough starter!

View file

@ -34,13 +34,20 @@
{#each posts as post}
<a href={`/${post.path}`}>
<li>
<h5 class="post-title">
{post.meta.title}
</h5>
<time datetime={post.meta.date}>
{format(new Date(post.meta.date), 'MMMM d')}
</time>
<div>About {post.readingTime.text}</div>
<div>
<h5 class="post-title">
{post.meta.title}
</h5>
{#if post.meta.description}
<p class="description">{post.meta.description}</p>
{/if}
</div>
<div class="meta">
<time datetime={post.meta.date}>
{format(new Date(post.meta.date), 'MMMM d')}
</time>
<div>About {post.readingTime.text}</div>
</div>
</li>
</a>
{/each}
@ -96,7 +103,6 @@
padding: 0.5rem 1rem;
}
.post-title {
margin-bottom: 0.3rem;
text-decoration: underline;
text-decoration-color: transparent;
transition: all var(--animation-speed) var(--animation-type);
@ -123,4 +129,16 @@
.posts {
gap: 1.5rem;
}
.description {
font-size: 0.9rem;
margin-top: -1.4rem;
}
.meta {
display: flex;
flex-direction: row;
flex-wrap: wrap;
font-size: 0.9rem;
opacity: 0.8;
}
</style>

View file

@ -65,3 +65,8 @@ a img {
display: inline-block;
text-decoration: none;
}
blockquote {
padding: 0.1rem 1.5rem;
border-left: 5px solid $color-primary;
}