diff --git a/src/routes/[slug]/+page.svelte b/src/routes/[slug]/+page.svelte index e79ad5f..4eaf0b1 100644 --- a/src/routes/[slug]/+page.svelte +++ b/src/routes/[slug]/+page.svelte @@ -12,14 +12,17 @@ + {#if data.updated} + + {/if} {#if data.image} {:else} {/if} - {#if data.excerpt} - - + {#if data.description} + + {/if} @@ -27,15 +30,26 @@

{data.title}

- + {#if data.updated} +

+ Written on +

+ {:else} +

+ Written on +

+ {/if} +
diff --git a/src/routes/[slug]/+page.ts b/src/routes/[slug]/+page.ts index bb5c49f..a0a2fbf 100644 --- a/src/routes/[slug]/+page.ts +++ b/src/routes/[slug]/+page.ts @@ -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, }; } diff --git a/src/routes/posts/2022.09.18.solving-react-redux-triggering-too-many-re-renders.md b/src/routes/posts/2022.09.18.solving-react-redux-triggering-too-many-re-renders.md index 2d14037..16cb579 100644 --- a/src/routes/posts/2022.09.18.solving-react-redux-triggering-too-many-re-renders.md +++ b/src/routes/posts/2022.09.18.solving-react-redux-triggering-too-many-re-renders.md @@ -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, - Right extends Record + Right extends Record, >(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, ); ``` diff --git a/src/routes/posts/2022.11.19.automating-my-blog-with-gitea-and-woodpecker.md b/src/routes/posts/2022.11.19.automating-my-blog-with-gitea-and-woodpecker.md index 42426ea..ff25555 100644 --- a/src/routes/posts/2022.11.19.automating-my-blog-with-gitea-and-woodpecker.md +++ b/src/routes/posts/2022.11.19.automating-my-blog-with-gitea-and-woodpecker.md @@ -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 diff --git a/src/routes/posts/2022.12.17.firefox-xml-parsing-error-no-root-element.md b/src/routes/posts/2022.12.17.firefox-xml-parsing-error-no-root-element.md index 8af9c15..f585ca4 100644 --- a/src/routes/posts/2022.12.17.firefox-xml-parsing-error-no-root-element.md +++ b/src/routes/posts/2022.12.17.firefox-xml-parsing-error-no-root-element.md @@ -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/). diff --git a/src/routes/posts/2022.12.29.hosting-websites-without-static-IP-Gandi.md b/src/routes/posts/2022.12.29.hosting-websites-without-static-IP-Gandi.md index a365ac6..ceb13cc 100644 --- a/src/routes/posts/2022.12.29.hosting-websites-without-static-IP-Gandi.md +++ b/src/routes/posts/2022.12.29.hosting-websites-without-static-IP-Gandi.md @@ -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. diff --git a/src/routes/posts/2023.01.28.typescript-get-inferred-type.md b/src/routes/posts/2023.01.28.typescript-get-inferred-type.md index 97fcf3c..bba4788 100644 --- a/src/routes/posts/2023.01.28.typescript-get-inferred-type.md +++ b/src/routes/posts/2023.01.28.typescript-get-inferred-type.md @@ -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; diff --git a/src/routes/posts/2023.02.10.why-use-devcontainer.md b/src/routes/posts/2023.02.10.why-use-devcontainer.md index b1e0d56..299340e 100644 --- a/src/routes/posts/2023.02.10.why-use-devcontainer.md +++ b/src/routes/posts/2023.02.10.why-use-devcontainer.md @@ -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 diff --git a/src/routes/posts/2023.02.18.github-actions-do-not-merge-label.md b/src/routes/posts/2023.02.18.github-actions-do-not-merge-label.md index 3631e10..b0c1bcb 100644 --- a/src/routes/posts/2023.02.18.github-actions-do-not-merge-label.md +++ b/src/routes/posts/2023.02.18.github-actions-do-not-merge-label.md @@ -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: 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. diff --git a/src/routes/posts/2023.02.26.making-the-slow-explicit-dynamodb-sql.md b/src/routes/posts/2023.02.26.making-the-slow-explicit-dynamodb-sql.md index ae8a251..3b98195 100644 --- a/src/routes/posts/2023.02.26.making-the-slow-explicit-dynamodb-sql.md +++ b/src/routes/posts/2023.02.26.making-the-slow-explicit-dynamodb-sql.md @@ -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. diff --git a/src/routes/posts/2023.03.05.set-up-my-blog-as-onion-service.md b/src/routes/posts/2023.03.05.set-up-my-blog-as-onion-service.md index c9d4b0c..790745a 100644 --- a/src/routes/posts/2023.03.05.set-up-my-blog-as-onion-service.md +++ b/src/routes/posts/2023.03.05.set-up-my-blog-as-onion-service.md @@ -3,6 +3,7 @@ title: 'Setting up my blog as an Onion service (Tor hidden service)' date: 2023-03-05T15:54:13-05:00 toc: false images: +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 diff --git a/src/routes/posts/2023.04.25.self-hosted-backups-with-minio-kopia-tailscale.md b/src/routes/posts/2023.04.25.self-hosted-backups-with-minio-kopia-tailscale.md index 0e53d68..998c500 100644 --- a/src/routes/posts/2023.04.25.self-hosted-backups-with-minio-kopia-tailscale.md +++ b/src/routes/posts/2023.04.25.self-hosted-backups-with-minio-kopia-tailscale.md @@ -5,6 +5,7 @@ toc: false images: 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. diff --git a/src/routes/posts/2023.04.27.raspberry-pi-headless-setup.md b/src/routes/posts/2023.04.27.raspberry-pi-headless-setup.md index 22117d2..18bd313 100644 --- a/src/routes/posts/2023.04.27.raspberry-pi-headless-setup.md +++ b/src/routes/posts/2023.04.27.raspberry-pi-headless-setup.md @@ -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 diff --git a/src/routes/posts/2023.07.02.css-only-contenteditable-placeholder.md b/src/routes/posts/2023.07.02.css-only-contenteditable-placeholder.md index 6830c0f..9b9e108 100644 --- a/src/routes/posts/2023.07.02.css-only-contenteditable-placeholder.md +++ b/src/routes/posts/2023.07.02.css-only-contenteditable-placeholder.md @@ -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 diff --git a/src/routes/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md b/src/routes/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md index f0513a9..c6bd070 100644 --- a/src/routes/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md +++ b/src/routes/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md @@ -7,6 +7,7 @@ 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 diff --git a/src/routes/posts/2023.08.13.nextjs-bindings-cannot-read-property-indexof-undefined-getFileName.md b/src/routes/posts/2023.08.13.nextjs-bindings-cannot-read-property-indexof-undefined-getFileName.md index b5d0288..9142e11 100644 --- a/src/routes/posts/2023.08.13.nextjs-bindings-cannot-read-property-indexof-undefined-getFileName.md +++ b/src/routes/posts/2023.08.13.nextjs-bindings-cannot-read-property-indexof-undefined-getFileName.md @@ -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; diff --git a/src/routes/posts/2023.10.02.amazon-SES-production-access-approval.md b/src/routes/posts/2023.10.02.amazon-SES-production-access-approval.md index c1ea230..3f7b78a 100644 --- a/src/routes/posts/2023.10.02.amazon-SES-production-access-approval.md +++ b/src/routes/posts/2023.10.02.amazon-SES-production-access-approval.md @@ -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, + }), + }); } ``` diff --git a/src/routes/posts/2023.12.09.building-well-organized-rust-CLI-tool.md b/src/routes/posts/2023.12.09.building-well-organized-rust-CLI-tool.md index 74e461b..4f20725 100644 --- a/src/routes/posts/2023.12.09.building-well-organized-rust-CLI-tool.md +++ b/src/routes/posts/2023.12.09.building-well-organized-rust-CLI-tool.md @@ -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 diff --git a/src/routes/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md b/src/routes/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md index 98f5f14..6fc4316 100644 --- a/src/routes/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md +++ b/src/routes/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md @@ -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! diff --git a/src/routes/posts/[[page=integer]]/+page.svelte b/src/routes/posts/[[page=integer]]/+page.svelte index 983dfa4..375275d 100644 --- a/src/routes/posts/[[page=integer]]/+page.svelte +++ b/src/routes/posts/[[page=integer]]/+page.svelte @@ -34,13 +34,20 @@ {#each posts as post}
  • -
    - {post.meta.title} -
    - -
    About {post.readingTime.text}
    +
    +
    + {post.meta.title} +
    + {#if post.meta.description} +

    {post.meta.description}

    + {/if} +
    +
    + +
    About {post.readingTime.text}
    +
  • {/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; + } diff --git a/src/typography.scss b/src/typography.scss index 6a48620..877950b 100644 --- a/src/typography.scss +++ b/src/typography.scss @@ -65,3 +65,8 @@ a img { display: inline-block; text-decoration: none; } + +blockquote { + padding: 0.1rem 1.5rem; + border-left: 5px solid $color-primary; +}