From c7ce67b13be0794a0497aaa03b4a82d620c126cd Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Tue, 4 Aug 2026 23:58:09 +0800 Subject: [PATCH 01/71] chore: add blog page with layout and page TSX files --- src/app/blog/layout.tsx | 0 src/app/blog/page.tsx | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/app/blog/layout.tsx create mode 100644 src/app/blog/page.tsx diff --git a/src/app/blog/layout.tsx b/src/app/blog/layout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx new file mode 100644 index 0000000..e69de29 From ff83286d06144825f86893c423dd69d403596404 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 13 Aug 2026 21:54:21 +0800 Subject: [PATCH 02/71] chore(blog): delete layout.tsx --- src/app/blog/layout.tsx | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/app/blog/layout.tsx diff --git a/src/app/blog/layout.tsx b/src/app/blog/layout.tsx deleted file mode 100644 index e69de29..0000000 From fb048ab2ccc6f9471d9f0be6bbb8b79ed68305ee Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 00:37:50 +0800 Subject: [PATCH 03/71] feat(blog): add metadata for blog page --- src/app/blog/page.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index e69de29..a214c35 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -0,0 +1,25 @@ +import type { Metadata } from 'next'; + +const metaDescription = + 'Blog posts on full stack development and tech from Elmar Chavez.'; + +export const metadata: Metadata = { + title: 'Elmar Chavez | Blog', + description: metaDescription, + keywords: [ + 'Elmar Chavez Blog', + 'Web Development Blog', + 'Tech Articles', + 'Tech Community', + 'Software Engineering Blog', + ], + openGraph: { + title: 'Blog | Elmar Chavez', + description: metaDescription, + }, + twitter: { + card: 'summary_large_image', + title: 'Blog | Elmar Chavez', + description: metaDescription, + }, +}; From 68b52a03738991f53c6904f8f9a64328c3cbdf69 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 01:01:33 +0800 Subject: [PATCH 04/71] feat(blog): add initial structure to blog page --- src/app/blog/page.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index a214c35..0be99a7 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -1,4 +1,5 @@ import type { Metadata } from 'next'; +import Footer from '@/components/sections/footer'; const metaDescription = 'Blog posts on full stack development and tech from Elmar Chavez.'; @@ -23,3 +24,12 @@ export const metadata: Metadata = { description: metaDescription, }, }; + +export default function BlogPage() { + return ( +
+

Blog

+
+
+ ); +} From 412a8ed177dc589feba658b1b99e2493e5ace6ef Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 01:39:45 +0800 Subject: [PATCH 05/71] feat(blog): add view all link top right of the section --- src/components/sections/blog.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/sections/blog.tsx b/src/components/sections/blog.tsx index 7b64656..cab9bda 100644 --- a/src/components/sections/blog.tsx +++ b/src/components/sections/blog.tsx @@ -3,9 +3,22 @@ import { blogList } from '@/data/blog-list'; const Blog = () => { return ( -
+

Blog

+ + + View all + + ↗ + + → + + +
    {blogList.map( ({ From 2c8818f55c99313c3b605f3d00b29cb679c308f5 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 01:52:29 +0800 Subject: [PATCH 06/71] feat(ui): create a separate component for section links --- src/components/ui/view-all-link.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/components/ui/view-all-link.tsx diff --git a/src/components/ui/view-all-link.tsx b/src/components/ui/view-all-link.tsx new file mode 100644 index 0000000..862a0cc --- /dev/null +++ b/src/components/ui/view-all-link.tsx @@ -0,0 +1,24 @@ +import Link from 'next/link'; + +type ViewAllLinkProps = { + href: string; +}; + +const ViewAllLink = ({ href }: ViewAllLinkProps) => { + return ( + + + View all + + ↗ + + → + + + ); +}; + +export default ViewAllLink; From 1406db635c92fba71613c2272236241722826cb5 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 01:52:53 +0800 Subject: [PATCH 07/71] feat(blog): use ViewAllLink for blog section --- src/components/sections/blog.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/components/sections/blog.tsx b/src/components/sections/blog.tsx index cab9bda..9e349b5 100644 --- a/src/components/sections/blog.tsx +++ b/src/components/sections/blog.tsx @@ -1,23 +1,13 @@ import Image from 'next/image'; import { blogList } from '@/data/blog-list'; +import ViewAllLink from '../ui/view-all-link'; const Blog = () => { return (

    Blog

    - - - View all - - ↗ - - → - - +
      {blogList.map( From eda8975b0cb3bd4dc76ac578661df4f4ca8f32e6 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 02:15:02 +0800 Subject: [PATCH 08/71] feat(a11y): add tab accessibility, outline, and hover state to view all link --- src/components/ui/view-all-link.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ui/view-all-link.tsx b/src/components/ui/view-all-link.tsx index 862a0cc..7bf16ac 100644 --- a/src/components/ui/view-all-link.tsx +++ b/src/components/ui/view-all-link.tsx @@ -7,14 +7,14 @@ type ViewAllLinkProps = { const ViewAllLink = ({ href }: ViewAllLinkProps) => { return ( - + View all - ↗ - + ↗ + → From 67d19c3792dba5f6511af514aae47494de85e6aa Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Fri, 14 Aug 2026 02:18:20 +0800 Subject: [PATCH 09/71] fix(blog): make read more link in each blog to not go the entire width in mobile view --- src/components/sections/blog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sections/blog.tsx b/src/components/sections/blog.tsx index 9e349b5..a9c74ab 100644 --- a/src/components/sections/blog.tsx +++ b/src/components/sections/blog.tsx @@ -47,7 +47,7 @@ const Blog = () => {
    Date: Fri, 14 Aug 2026 02:20:54 +0800 Subject: [PATCH 10/71] refactor(blog): use Link from Next.js for a more optimized link --- src/components/sections/blog.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/sections/blog.tsx b/src/components/sections/blog.tsx index a9c74ab..7e97286 100644 --- a/src/components/sections/blog.tsx +++ b/src/components/sections/blog.tsx @@ -1,4 +1,5 @@ import Image from 'next/image'; +import Link from 'next/link'; import { blogList } from '@/data/blog-list'; import ViewAllLink from '../ui/view-all-link'; @@ -46,14 +47,14 @@ const Blog = () => { })}
- Read More → - + From 4ef36995a33545fcf1a89b7d2bc9205fec65a6bf Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sat, 15 Aug 2026 02:38:50 +0800 Subject: [PATCH 11/71] feat(blog): update blog page header --- src/app/blog/page.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index 0be99a7..31b9c7b 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -28,7 +28,13 @@ export const metadata: Metadata = { export default function BlogPage() { return (
-

Blog

+
+

Blog

+

+ Articles, thoughts, and tech stuff. +

+
+
); From 1b5f61dff06ca4377d2142740d4167dc9e490f2f Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sat, 15 Aug 2026 02:44:26 +0800 Subject: [PATCH 12/71] feat(blog): add ThemeToggle component to blog header --- src/app/blog/page.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index 31b9c7b..c176e57 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next'; import Footer from '@/components/sections/footer'; +import ThemeToggle from '@/components/theme/theme-toggle'; const metaDescription = 'Blog posts on full stack development and tech from Elmar Chavez.'; @@ -28,11 +29,15 @@ export const metadata: Metadata = { export default function BlogPage() { return (
-
-

Blog

-

- Articles, thoughts, and tech stuff. -

+
+
+

Blog

+

+ Articles, thoughts, and tech stuff. +

+
+ +
From ea82473b47a6102d12ccbb3ba3296ba425ed06bc Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sat, 15 Aug 2026 02:53:53 +0800 Subject: [PATCH 13/71] feat(blog): export all blogs --- src/data/blog-list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/blog-list.ts b/src/data/blog-list.ts index 7d6ad45..dff3109 100644 --- a/src/data/blog-list.ts +++ b/src/data/blog-list.ts @@ -1,6 +1,6 @@ import { BlogType } from '@/types/blog'; -const BLOGS: BlogType[] = [ +export const BLOGS: BlogType[] = [ { id: 1, title: From ca65efe0fa4c60f19694dde35f979a909b732105 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sat, 15 Aug 2026 02:54:21 +0800 Subject: [PATCH 14/71] feat(blog): copy the blog list format from home page to blog page as initial structure --- src/app/blog/page.tsx | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index c176e57..635f946 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -1,6 +1,9 @@ import type { Metadata } from 'next'; +import Image from 'next/image'; +import Link from 'next/link'; import Footer from '@/components/sections/footer'; import ThemeToggle from '@/components/theme/theme-toggle'; +import { BLOGS } from '@/data/blog-list'; const metaDescription = 'Blog posts on full stack development and tech from Elmar Chavez.'; @@ -26,6 +29,8 @@ export const metadata: Metadata = { }, }; +const blogsLatestOrder = BLOGS.slice().reverse(); + export default function BlogPage() { return (
@@ -40,6 +45,63 @@ export default function BlogPage() {
+
    + {blogsLatestOrder.map( + ({ + id, + title, + description, + publishDate, + readTime, + tags, + blogUrl, + imgUrl, + }) => { + return ( +
  • +
    +

    + {title} +

    + +

    + {publishDate} • {readTime} +

    + +

    + {description} +

    + +
    +
      + {tags.map((tag) => { + return
    • {tag}
    • ; + })} +
    + + + Read More → + +
    +
    + +
    + +
    +
  • + ); + }, + )} +
+
); From 78c9a6dfbdddcdf6cab49ca7500c09b18de0be29 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:17:05 +0800 Subject: [PATCH 15/71] feat(a11y): add img alts to each blog banner image --- src/data/blog-list.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data/blog-list.ts b/src/data/blog-list.ts index dff3109..c303923 100644 --- a/src/data/blog-list.ts +++ b/src/data/blog-list.ts @@ -13,6 +13,8 @@ export const BLOGS: BlogType[] = [ blogUrl: 'https://dev.to/devengers/should-you-use-gemma-4-for-your-development-a-multiversal-analysis-to-determine-if-gemma-4-is-2iol', imgUrl: '/img/blog-1.webp', + imgAlt: + 'A collection of anime characters for a multiversal collaboration for an article.', }, { id: 2, @@ -26,6 +28,8 @@ export const BLOGS: BlogType[] = [ blogUrl: 'https://dev.to/devengers/two-devs-and-a-copilot-created-classifierai-a-prototype-chrome-extension-that-automatically-4fge', imgUrl: '/img/blog-2.webp', + imgAlt: + 'A funny backgroups GIF image where Elmar and Francis are dancing with strange creatures.', }, { id: 3, @@ -38,6 +42,7 @@ export const BLOGS: BlogType[] = [ blogUrl: 'https://dev.to/devengers/why-every-software-engineer-should-read-the-psychology-of-money-2b6e', imgUrl: '/img/blog-3.jpg', + imgAlt: 'A meme image for stonks.', }, { id: 4, @@ -50,6 +55,7 @@ export const BLOGS: BlogType[] = [ blogUrl: 'https://dev.to/devengers/how-i-contributed-to-a-laravel-application-without-knowing-laravel-1dkl', imgUrl: '/img/blog-4.jpg', + imgAlt: 'Keyboard caps laid down on a white table.', }, ]; From 194a0a016f586463e3a59e86040de62f5e11247a Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:18:21 +0800 Subject: [PATCH 16/71] test(blog-list): update blog list test to use the entire blogs database and not the latest three instead --- src/data/blog-list.test.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/data/blog-list.test.ts b/src/data/blog-list.test.ts index ecd15c2..08a09fe 100644 --- a/src/data/blog-list.test.ts +++ b/src/data/blog-list.test.ts @@ -1,30 +1,34 @@ -import { blogList } from './blog-list'; +import { BLOGS } from './blog-list'; import { isNotEmpty, isValidUrl } from '@/tests/utils'; describe('Blog list data', () => { test('every blog has a non-empty title', () => { - const titles = blogList.map(({ title }) => title); + const titles = BLOGS.map(({ title }) => title); expect(isNotEmpty(titles)).toBe(true); }); test('every blog has a non-empty description', () => { - const descriptions = blogList.map(({ description }) => description); + const descriptions = BLOGS.map(({ description }) => description); expect(isNotEmpty(descriptions)).toBe(true); }); test('every blog uses a valid HTTPS URL', () => { - const urls = blogList.map(({ blogUrl }) => blogUrl); + const urls = BLOGS.map(({ blogUrl }) => blogUrl); expect(isValidUrl(urls)).toBe(true); }); + test('every blog has a non-empty img alt description', () => { + const imgAlts = BLOGS.map(({ imgAlt }) => imgAlt); + expect(isNotEmpty(imgAlts)).toBe(true); + }); test('every blog has a non-empty image path', () => { - const imgUrls = blogList.map(({ imgUrl }) => imgUrl); + const imgUrls = BLOGS.map(({ imgUrl }) => imgUrl); expect(isNotEmpty(imgUrls)).toBe(true); }); test('every blog has at least three tags', () => { - const tagList = blogList.map(({ tags }) => tags); + const tagList = BLOGS.map(({ tags }) => tags); const hasThreeTags = tagList.every((tags) => tags.length >= 3); expect(hasThreeTags).toBe(true); }); test('every blog has non-empty tag names', () => { - const tagList = blogList.map(({ tags }) => tags); + const tagList = BLOGS.map(({ tags }) => tags); const hasNonEmptyTags = tagList.every((tags) => isNotEmpty(tags)); expect(hasNonEmptyTags).toBe(true); }); From 6f1209790e305c935d9ef3cb921c7d181ffa2bd0 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:19:23 +0800 Subject: [PATCH 17/71] test(blog): renders every read more link to be more specific by adding the accessible name --- src/components/sections/blog.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sections/blog.test.tsx b/src/components/sections/blog.test.tsx index 5e271e2..0736eb1 100644 --- a/src/components/sections/blog.test.tsx +++ b/src/components/sections/blog.test.tsx @@ -18,7 +18,7 @@ describe('Blog section', () => { }); test('renders every read more link', () => { render(); - const links = screen.getAllByRole('link'); + const links = screen.getAllByRole('link', { name: /read more/i }); expect(links).toHaveLength(blogList.length); }); }); From b3bfd68a5a5c34d6638ab75b7a10dbaf94f32303 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:19:59 +0800 Subject: [PATCH 18/71] feat(types): update blog types to add an imgAlt property string --- src/types/blog.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/blog.ts b/src/types/blog.ts index 1187542..cdd0d07 100644 --- a/src/types/blog.ts +++ b/src/types/blog.ts @@ -7,4 +7,5 @@ export type BlogType = { tags: string[]; blogUrl: string; imgUrl: string; + imgAlt: string; }; From 0619a2d66e79de6f54ef13b9b1036e1f4cc572fe Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:28:49 +0800 Subject: [PATCH 19/71] feat(blog): make blog banner styling more uniform --- src/components/sections/blog.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/sections/blog.tsx b/src/components/sections/blog.tsx index 7e97286..06d7f78 100644 --- a/src/components/sections/blog.tsx +++ b/src/components/sections/blog.tsx @@ -21,6 +21,7 @@ const Blog = () => { tags, blogUrl, imgUrl, + imgAlt, }) => { return (
  • { -
    - +
    + {imgAlt}
  • ); From 3e52dc920960a76d49ac43688f38b2be97069a68 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 16 Aug 2026 01:42:48 +0800 Subject: [PATCH 20/71] feat(blog): style the /blog page --- src/app/blog/page.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index 635f946..784af92 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -45,7 +45,7 @@ export default function BlogPage() { - -

    +

    {blogMeta.title}

    From 5cf91e11eefa5cc0bf29e87bfdcf9f40f4dac7b7 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 00:26:04 +0800 Subject: [PATCH 65/71] refactor(blog): move read more articles link to right side --- src/app/blog/[slug]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index eacb34f..11347d3 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -44,7 +44,7 @@ export default async function ArticlePage({ params }: ArticlePageProps) {
    -
    +
    Date: Thu, 27 Aug 2026 20:23:27 +0800 Subject: [PATCH 66/71] feat(blog): add blog-3.mdx file to content --- src/content/blog/blog-3.mdx | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/content/blog/blog-3.mdx diff --git a/src/content/blog/blog-3.mdx b/src/content/blog/blog-3.mdx new file mode 100644 index 0000000..4b0c0a9 --- /dev/null +++ b/src/content/blog/blog-3.mdx @@ -0,0 +1,79 @@ +Habit stacking is one of my goals this year. I've been so focused on improving my software engineering skills, staying fit, and networking. But I realized I have completely ignored one habit: _learning how money works_. + +Software engineering is a lucrative career but that doesn't mean we are automatically good with money. + +_Keeping money is a completely different skill from making money._ + +Because of this, I've decided to read one chapter a day from the book **"The Psychology of Money"** and these are the lessons I think every software engineer should hear. + +--- + +## hugeSalary !== beingWealthy + +Staying wealthy is a skill in itself. Saving consistently and letting compounding do the work is the way to go. I know, _revolutionary_. But that's the point. It's boring, and it works. + +> "Wealth is what we don't see." + +Many of us, myself included, dream of landing a FAANG-level salary. But we also have to check our lifestyle inflation. Huge salaries don't matter if you keep spending more _"just because"_ you needed a bigger apartment, a new car, or more expensive habits. + +--- + +## Never Underestimate the Power of Compounding + +Maybe some of you shrugged off my initial remark on compounding. Honestly, I wouldn't blame you for it. I also underestimated compounding but the more I read about it, the more I am fascinated by its power to change people's lives. + +We software engineers stack skills almost every single day to keep up with the latest tech. Each day, we improve and that compounds. It's the same thing with money. + +What's stopping us from applying that same mindset to our finances? + +_Nothing._ + +--- + +## Freedom Is the End Goal + +As I read through the book, one theme keeps lingering inside my head and that's _freedom_. When you have something saved, you have options. + +> "Controlling your time is the highest dividend money pays." + +The goal is not just to be rich but to be able to use your money to save your ultimate currency: _your time_. Then to be able to spend it on things that matter the most is one of the most beautiful gifts of life. + +I love the tech industry but I also have plans _outside of it_ and I'm sure many of us are not planning to code through our golden years. + +--- + +## We're All on Different Branches + +Someone you know got hired by Google at 18 years old. Someone else got promoted while you've been waiting for months. Plus many other stories that make you feel small. + +But these are stories you can't control. Timing exists, luck exists, risk exists, factors you don't even have to power to change exists. These are real life scenarios and each of them happens differently for each of us. + +_Everyone has different circumstances._ + +We are all committing to our own Git branches on the main timeline. If you stop and inspect other people's branches, you'll just end up wasting time that could have been used for growing yours. + +Looking at other people's finances is inviting _comparison, envy, and elitism_. But if we focus on our own, we'll spend less time feeling _bitter_ and more time getting _better_. + +--- + +## Work, Work, Work + +All of these will be wasted if you are inconsistent. Investing in your engineering skills while investing your money should grow together. + +_For this to work, you have to do the work._ + +Sounds easy on paper but it's definitely hard to do. There will be days when your body feels sluggish that you want to just lie down and rest. Learn to maneuver around that feeling to stay consistent. + +It may not be what you'd hoped for that day, but at least you did the bare minimum. There's still progress. + +Compounding skills and investments only works if you _stay in the game long enough_. + +--- + +## Some Remarks + +What I love most about this book is that it didn't tell what to invest in. It taught me _how to think about money_. It taught me how little my knowledge is when compared to the world's history of wealth and economics. + +I also believe the lessons can be applied to every level of the tech career ladder. That's why I was so excited to make it the first topic for my first solo blog post on this platform. + +I am still learning and applying the lessons every day. Maybe five or ten years from now, I'll come back and read this post I wrote at 2:00 AM. I hope that by then, all the small, consistent efforts I made in my career and finances have compounded into a life I'm proud of. From 4fc4104e56bf65e8bbc5db6333028e17134b3fea Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 20:33:21 +0800 Subject: [PATCH 67/71] refactor(utils): change description line for presentation --- src/lib/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 09164f4..d5e3949 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -21,7 +21,7 @@ export function getBlogMeta(slug: string) { return { id: -99, title: 'Blog not found', - description: 'No description.', + description: "Seems like this file doesn't exist ¯\\\_(ツ)_/¯", publishDate: 'No publish date.', readTime: 'No read time.', tags: [], From e2a0ff905c4025d3d1e2acd57f4141f7f75819ba Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 20:34:02 +0800 Subject: [PATCH 68/71] feat(blog): add a short description on the 404 blog not found article page --- src/components/sections/article-header.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/sections/article-header.tsx b/src/components/sections/article-header.tsx index d97d1e8..8b372c6 100644 --- a/src/components/sections/article-header.tsx +++ b/src/components/sections/article-header.tsx @@ -18,9 +18,13 @@ const ArticleHeader = ({ breadcrumbItems, blogMeta }: ArticleHeaderProps) => {
    -

    +

    {blogMeta.title}

    + +

    + {blogMeta.description} +

    ); } From f502d8da8ce3c6bab86e7dee10074a465720372b Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 22:36:27 +0800 Subject: [PATCH 69/71] perf(blog): add loading eager to blog banner images --- src/components/sections/article-header.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/sections/article-header.tsx b/src/components/sections/article-header.tsx index 8b372c6..d773eed 100644 --- a/src/components/sections/article-header.tsx +++ b/src/components/sections/article-header.tsx @@ -41,6 +41,7 @@ const ArticleHeader = ({ breadcrumbItems, blogMeta }: ArticleHeaderProps) => { {blogMeta.imgAlt} From 10091007cc02573a325556b344604a084761f153 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 23:49:48 +0800 Subject: [PATCH 70/71] test(blog): update test from checking if read more goes to new tab to if blog article link has correct href --- tests/blog.spec.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/blog.spec.ts b/tests/blog.spec.ts index 973bb2c..48ef01a 100644 --- a/tests/blog.spec.ts +++ b/tests/blog.spec.ts @@ -1,15 +1,12 @@ import { test, expect } from '@playwright/test'; import { blogList } from '@/data/blog-list'; -test('visitor can open a blog link in a new tab', async ({ page }) => { +test('blog article link has correct href', async ({ page }) => { await page.goto('/'); const blog = blogList[0]; expect(blog).toBeDefined(); const link = page.getByRole('link', { name: `Read more about ${blog.title}`, }); - const newPagePromise = page.waitForEvent('popup'); - await link.click(); - const newPage = await newPagePromise; - await expect(newPage).toHaveURL(blog.blogUrl); + await expect(link).toHaveAttribute('href', blog.blogUrl); }); From 96cae7283ba5d1fd6fa7d6cad5441c3ed54f751e Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 27 Aug 2026 23:51:46 +0800 Subject: [PATCH 71/71] test(keyboard): update test for when visitor can tab to blog link and then opens to article page --- tests/keyboard.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/keyboard.spec.ts b/tests/keyboard.spec.ts index f8bbcad..dce755f 100644 --- a/tests/keyboard.spec.ts +++ b/tests/keyboard.spec.ts @@ -81,7 +81,7 @@ test.describe('Keyboard Accessibility', () => { const newPage = await newPagePromise; await expect(newPage).toHaveURL('https://github.com/CodingWithJiro'); }); - test('visitor can tab to blog link and open in a new tab', async ({ + test('visitor can tab to blog link and opens article page', async ({ page, browserName, }) => { @@ -93,10 +93,8 @@ test.describe('Keyboard Accessibility', () => { const link = page.getByRole('link', { name: blog.title }); await tabUntilFocused(page, link, blog.title); expect(link).toBeFocused(); - const newPagePromise = page.waitForEvent('popup'); await page.keyboard.press('Enter'); - const newPage = await newPagePromise; - await expect(newPage).toHaveURL(blog.blogUrl); + await expect(page).toHaveURL(blog.blogUrl); }); test('visitor can tab to a certificate link and open in a new tab', async ({ page,