From bad4b337c45bb1e6ddc876eb84f359aeb1a220dc Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 6 Sep 2026 22:42:31 +0800 Subject: [PATCH 01/37] feat(certificates): add Front-End Development library certificate from freeCodeCamp --- src/data/experiences.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/data/experiences.ts b/src/data/experiences.ts index 4849326..d30c58a 100644 --- a/src/data/experiences.ts +++ b/src/data/experiences.ts @@ -19,14 +19,14 @@ export const workExperiences: WorkExperience[] = [ }, ]; -export const certificates: Certificate[] = [ +export const CERTIFICATES: Certificate[] = [ { - id: 3, - title: 'Relational Databases', + id: 1, + title: 'Responsive Web Design', institution: 'freeCodeCamp', - dateReceived: 'May 2026', + dateReceived: 'Dec 2025', urlLink: - 'https://www.freecodecamp.org/certification/codingwithjiro/relational-databases-v9', + 'https://www.freecodecamp.org/certification/codingwithjiro/responsive-web-design-v9', }, { id: 2, @@ -37,11 +37,21 @@ export const certificates: Certificate[] = [ 'https://www.freecodecamp.org/certification/codingwithjiro/javascript-v9', }, { - id: 1, - title: 'Responsive Web Design', + id: 3, + title: 'Relational Databases', institution: 'freeCodeCamp', - dateReceived: 'Dec 2025', + dateReceived: 'May 2026', urlLink: - 'https://www.freecodecamp.org/certification/codingwithjiro/responsive-web-design-v9', + 'https://www.freecodecamp.org/certification/codingwithjiro/relational-databases-v9', + }, + { + id: 4, + title: 'Front-End Libraries', + institution: 'freeCodeCamp', + dateReceived: 'September 2026', + urlLink: + 'https://www.freecodecamp.org/certification/codingwithjiro/front-end-development-libraries-v9', }, ]; + +export const certificates: Certificate[] = CERTIFICATES.slice(-3).reverse(); From 600e8fbe8638787ee65556c85322bc3040e6210c Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Sun, 6 Sep 2026 23:11:06 +0800 Subject: [PATCH 02/37] chore(meta): update metadata for article slug page to show blog title and author name --- src/app/blog/[slug]/page.tsx | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index 2e7d854..ced65af 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -4,11 +4,44 @@ import ArticleHeader from '@/components/sections/article-header'; import Footer from '@/components/sections/footer'; import Link from 'next/link'; import { ArrowLeft, ArrowRight } from 'lucide-react'; +import type { Metadata } from 'next'; + +const metaDescription = + 'Blog posts on full stack development and tech from Elmar Chavez.'; type ArticlePageProps = { params: Promise<{ slug: string }>; }; +export async function generateMetadata({ + params, +}: ArticlePageProps): Promise { + const { slug } = await params; + const blog = getBlogMeta(slug); + const title = `${blog.title} | Elmar Chavez`; + const metadata: Metadata = { + title, + description: metaDescription, + keywords: [ + 'Elmar Chavez Blog', + 'Web Development Blog', + 'Tech Articles', + 'Tech Community', + 'Software Engineering Blog', + ], + openGraph: { + title, + description: metaDescription, + }, + twitter: { + card: 'summary_large_image', + title, + description: metaDescription, + }, + }; + return metadata; +} + export default async function ArticlePage({ params }: ArticlePageProps) { const { slug } = await params; const blog = getBlogMeta(slug); From 58e0d118e4899ebdb052ba063716eeccf51a19e3 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Mon, 7 Sep 2026 23:28:37 +0800 Subject: [PATCH 03/37] test(experiences): update data to use the CERTIFICATES data instead of only the latest three certificates --- src/data/experiences.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/experiences.test.ts b/src/data/experiences.test.ts index 159aa35..2175fc5 100644 --- a/src/data/experiences.test.ts +++ b/src/data/experiences.test.ts @@ -1,4 +1,4 @@ -import { workExperiences, certificates } from './experiences'; +import { workExperiences, CERTIFICATES } from './experiences'; import { isNotEmpty, isValidUrl } from '@/tests/utils'; describe('Work Experiences and Certificates data', () => { @@ -11,15 +11,15 @@ describe('Work Experiences and Certificates data', () => { expect(isNotEmpty(companyNames)).toBe(true); }); test('every certificate has a non-empty title', () => { - const titles = certificates.map(({ title }) => title); + const titles = CERTIFICATES.map(({ title }) => title); expect(isNotEmpty(titles)).toBe(true); }); test('every certificate has a non-empty institution', () => { - const institutions = certificates.map(({ institution }) => institution); + const institutions = CERTIFICATES.map(({ institution }) => institution); expect(isNotEmpty(institutions)).toBe(true); }); test('every certificate uses a valid HTTPS URL', () => { - const urls = certificates.map(({ urlLink }) => urlLink); + const urls = CERTIFICATES.map(({ urlLink }) => urlLink); expect(isValidUrl(urls)).toBe(true); }); }); From caf5f07ca1ea40caa108a6db488ac4391a8359f3 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Mon, 7 Sep 2026 23:58:16 +0800 Subject: [PATCH 04/37] feat(tech-stack): add View all link in the Tech Stack section of the landing page --- src/components/sections/tech-stack.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/sections/tech-stack.tsx b/src/components/sections/tech-stack.tsx index bb32382..eaf3ef9 100644 --- a/src/components/sections/tech-stack.tsx +++ b/src/components/sections/tech-stack.tsx @@ -1,3 +1,5 @@ +import ViewAllLink from '../ui/view-all-link'; + export const FRONTEND: string[] = [ 'JavaScript', 'TypeScript', @@ -11,7 +13,10 @@ export const DEVOPS: string[] = ['GitHub Actions', 'Docker']; const TechStack = () => { return (
-

Tech Stack

+
+

Tech Stack

+ +

Frontend

From 8bff087873c87f2a702efcf4b81f8e8ff64477a3 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Tue, 8 Sep 2026 00:08:37 +0800 Subject: [PATCH 05/37] feat(tech-stack): create the initial tech stack page --- src/app/tech-stack/page.tsx | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/app/tech-stack/page.tsx diff --git a/src/app/tech-stack/page.tsx b/src/app/tech-stack/page.tsx new file mode 100644 index 0000000..81810f5 --- /dev/null +++ b/src/app/tech-stack/page.tsx @@ -0,0 +1,53 @@ +import type { Metadata } from 'next'; +import Breadcrumb from '@/components/sections/breadcrumb'; +import ThemeToggle from '@/components/theme/theme-toggle'; +import Footer from '@/components/sections/footer'; + +const metaDescription = + 'List of all the technologies Elmar Chavez have experience with.'; + +export const metadata: Metadata = { + title: 'Elmar Chavez | Tech Stack', + description: metaDescription, + keywords: [ + 'Elmar Chavez Tech Stack', + 'Web Development Technologies', + 'Full Stack Development Skills', + 'Frontend', + 'Backend', + ], + openGraph: { + title: 'Tech Stack | Elmar Chavez', + description: metaDescription, + }, + twitter: { + card: 'summary_large_image', + title: 'Tech Stack | Elmar Chavez', + description: metaDescription, + }, +}; + +export default function TechStackPage() { + return ( +
+
+ + +
+ +
+

Tech Stack

+

+ List of technologies I used so far. +

+
+ +

Add list here.

+ +
+
+ ); +} From 5c1c81e79720d742e6fedbd68bdef72e003507e0 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Tue, 8 Sep 2026 17:16:59 +0800 Subject: [PATCH 06/37] feat(ux): add You are here! label when user hovers over the current page in the Breadcrumb component --- src/app/tech-stack/page.tsx | 4 ++-- src/components/sections/breadcrumb.tsx | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/app/tech-stack/page.tsx b/src/app/tech-stack/page.tsx index 81810f5..a7b1d65 100644 --- a/src/app/tech-stack/page.tsx +++ b/src/app/tech-stack/page.tsx @@ -13,8 +13,8 @@ export const metadata: Metadata = { 'Elmar Chavez Tech Stack', 'Web Development Technologies', 'Full Stack Development Skills', - 'Frontend', - 'Backend', + 'Frontend Tech', + 'Backend Tech', ], openGraph: { title: 'Tech Stack | Elmar Chavez', diff --git a/src/components/sections/breadcrumb.tsx b/src/components/sections/breadcrumb.tsx index 80fd6a5..6dd8347 100644 --- a/src/components/sections/breadcrumb.tsx +++ b/src/components/sections/breadcrumb.tsx @@ -47,12 +47,18 @@ const Breadcrumb = ({ items, currentLabel }: BreadCrumbProps) => { / -

- {currentLabel} -

+
+

+ {currentLabel} +

+ + + You are here! + +
From a59fe219e8940d132a5138675e2a2b588bb2cd76 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Wed, 9 Sep 2026 23:22:49 +0800 Subject: [PATCH 07/37] feat(tech-stack): create initial tech stack data --- src/data/tech-stack.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/data/tech-stack.ts diff --git a/src/data/tech-stack.ts b/src/data/tech-stack.ts new file mode 100644 index 0000000..b924bc2 --- /dev/null +++ b/src/data/tech-stack.ts @@ -0,0 +1,9 @@ +export const FRONTEND: string[] = [ + 'JavaScript', + 'TypeScript', + 'React', + 'Next.js', + 'Tailwind CSS', +]; +export const BACKEND: string[] = ['Node.js', 'Express.js', 'PostgreSQL']; +export const DEVOPS: string[] = ['GitHub Actions', 'Docker']; From 2f62b828627e0c4b10be0ea82f882de46ef223ef Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 10 Sep 2026 00:58:42 +0800 Subject: [PATCH 08/37] feat(tech-stack): complete list of tech used so far and export landing page data --- src/data/tech-stack.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/data/tech-stack.ts b/src/data/tech-stack.ts index b924bc2..e892657 100644 --- a/src/data/tech-stack.ts +++ b/src/data/tech-stack.ts @@ -4,6 +4,33 @@ export const FRONTEND: string[] = [ 'React', 'Next.js', 'Tailwind CSS', + 'React Router', + 'Styled Components', + 'HTML', + 'CSS', + 'Vite', ]; export const BACKEND: string[] = ['Node.js', 'Express.js', 'PostgreSQL']; +export const TESTING_AND_QUALITY: string[] = [ + 'Vitest', + 'React Testing Library', + 'MSW', + 'Playwright', + 'Axe DevTools', + 'ESLint', + 'Prettier', +]; export const DEVOPS: string[] = ['GitHub Actions', 'Docker']; +export const CONTENT: string[] = ['MDX', 'Tailwind CSS Typography']; +export const TOOLS: string[] = [ + 'Git', + 'GitHub', + 'VS Code', + 'Slack', + 'Discord', + 'Teams', +]; + +export const frontend = FRONTEND.slice(0, 5); +export const backend = BACKEND.slice(0, 5); +export const devOps = DEVOPS.slice(0, 5); From 9d0b17d82498e6156ba700cca7d71a16c62a0222 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 10 Sep 2026 00:59:18 +0800 Subject: [PATCH 09/37] refactor(tech-stack): update data in tech stack section and test --- src/components/sections/tech-stack.test.tsx | 4 ++-- src/components/sections/tech-stack.tsx | 17 ++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/components/sections/tech-stack.test.tsx b/src/components/sections/tech-stack.test.tsx index 5cd57c9..6a6bf70 100644 --- a/src/components/sections/tech-stack.test.tsx +++ b/src/components/sections/tech-stack.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import { FRONTEND, BACKEND, DEVOPS } from './tech-stack'; +import { frontend, backend, devOps } from '@/data/tech-stack'; import TechStack from './tech-stack'; describe('Tech Stack section', () => { @@ -26,7 +26,7 @@ describe('Tech Stack section', () => { test('renders every tech in each category', () => { render(); const techLists = screen.getAllByRole('listitem'); - const totalTech = FRONTEND.length + BACKEND.length + DEVOPS.length; + const totalTech = frontend.length + backend.length + devOps.length; expect(techLists.length).toBe(totalTech); }); }); diff --git a/src/components/sections/tech-stack.tsx b/src/components/sections/tech-stack.tsx index eaf3ef9..cf79f7d 100644 --- a/src/components/sections/tech-stack.tsx +++ b/src/components/sections/tech-stack.tsx @@ -1,15 +1,6 @@ +import { backend, devOps, frontend } from '@/data/tech-stack'; import ViewAllLink from '../ui/view-all-link'; -export const FRONTEND: string[] = [ - 'JavaScript', - 'TypeScript', - 'React', - 'Next.js', - 'Tailwind CSS', -]; -export const BACKEND: string[] = ['Node.js', 'Express.js', 'PostgreSQL']; -export const DEVOPS: string[] = ['GitHub Actions', 'Docker']; - const TechStack = () => { return (
@@ -22,7 +13,7 @@ const TechStack = () => {

Frontend

    - {FRONTEND.map((tech) => { + {frontend.map((tech) => { return (
  • {

    Backend

      - {BACKEND.map((tech) => { + {backend.map((tech) => { return (
    • {

      DevOps

        - {DEVOPS.map((tech) => { + {devOps.map((tech) => { return (
      • Date: Thu, 10 Sep 2026 01:35:11 +0800 Subject: [PATCH 10/37] feat(tech-stack): add more technologies and create a TECH_STACK object with category name --- src/data/tech-stack.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/data/tech-stack.ts b/src/data/tech-stack.ts index e892657..abb6e8b 100644 --- a/src/data/tech-stack.ts +++ b/src/data/tech-stack.ts @@ -9,6 +9,7 @@ export const FRONTEND: string[] = [ 'HTML', 'CSS', 'Vite', + 'Responsive Web Design', ]; export const BACKEND: string[] = ['Node.js', 'Express.js', 'PostgreSQL']; export const TESTING_AND_QUALITY: string[] = [ @@ -17,6 +18,7 @@ export const TESTING_AND_QUALITY: string[] = [ 'MSW', 'Playwright', 'Axe DevTools', + 'Lighthouse', 'ESLint', 'Prettier', ]; @@ -34,3 +36,30 @@ export const TOOLS: string[] = [ export const frontend = FRONTEND.slice(0, 5); export const backend = BACKEND.slice(0, 5); export const devOps = DEVOPS.slice(0, 5); + +export const TECH_STACK = [ + { + category: 'Frontend', + technologies: FRONTEND, + }, + { + category: 'Backend', + technologies: BACKEND, + }, + { + category: 'DevOps', + technologies: DEVOPS, + }, + { + category: 'Testing & Quality', + technologies: TESTING_AND_QUALITY, + }, + { + category: 'Content', + technologies: CONTENT, + }, + { + category: 'Tools', + technologies: TOOLS, + }, +]; From 846ff659eb2a539f5f39b03972eaf614634bf75c Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 10 Sep 2026 01:41:52 +0800 Subject: [PATCH 11/37] feat(tech-list): create a TechList component section --- src/components/sections/tech-list.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/components/sections/tech-list.tsx diff --git a/src/components/sections/tech-list.tsx b/src/components/sections/tech-list.tsx new file mode 100644 index 0000000..775f780 --- /dev/null +++ b/src/components/sections/tech-list.tsx @@ -0,0 +1,25 @@ +interface TechListProps { + category: string; + technologies: string[]; +} + +export default function TechList({ category, technologies }: TechListProps) { + return ( +
        +

        {category}

        + +
          + {technologies.map((tech) => { + return ( +
        • + {tech} +
        • + ); + })} +
        +
        + ); +} From 87d67e2d833d21a8f427c2b5d8f2764cb3779e64 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 10 Sep 2026 01:42:41 +0800 Subject: [PATCH 12/37] refactor(tech-stack): use TechList component --- src/components/sections/tech-stack.tsx | 55 ++------------------------ 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/src/components/sections/tech-stack.tsx b/src/components/sections/tech-stack.tsx index cf79f7d..53b0a51 100644 --- a/src/components/sections/tech-stack.tsx +++ b/src/components/sections/tech-stack.tsx @@ -1,5 +1,6 @@ import { backend, devOps, frontend } from '@/data/tech-stack'; import ViewAllLink from '../ui/view-all-link'; +import TechList from './tech-list'; const TechStack = () => { return ( @@ -8,57 +9,9 @@ const TechStack = () => {

        Tech Stack

        - -
        -

        Frontend

        - -
          - {frontend.map((tech) => { - return ( -
        • - {tech} -
        • - ); - })} -
        -
        - -
        -

        Backend

        - -
          - {backend.map((tech) => { - return ( -
        • - {tech} -
        • - ); - })} -
        -
        - -
        -

        DevOps

        - -
          - {devOps.map((tech) => { - return ( -
        • - {tech} -
        • - ); - })} -
        -
        + + +
); }; From 5cf656b9d11b77739d503f8731737e4c3d0b8573 Mon Sep 17 00:00:00 2001 From: Elmar Chavez Date: Thu, 10 Sep 2026 01:43:38 +0800 Subject: [PATCH 13/37] feat(tech-stack): add lists and content to tech stack page --- src/app/tech-stack/page.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/app/tech-stack/page.tsx b/src/app/tech-stack/page.tsx index a7b1d65..1e51796 100644 --- a/src/app/tech-stack/page.tsx +++ b/src/app/tech-stack/page.tsx @@ -2,9 +2,11 @@ import type { Metadata } from 'next'; import Breadcrumb from '@/components/sections/breadcrumb'; import ThemeToggle from '@/components/theme/theme-toggle'; import Footer from '@/components/sections/footer'; +import TechList from '@/components/sections/tech-list'; +import { TECH_STACK } from '@/data/tech-stack'; const metaDescription = - 'List of all the technologies Elmar Chavez have experience with.'; + 'Technologies and tools Elmar Chavez has worked with across his projects.'; export const metadata: Metadata = { title: 'Elmar Chavez | Tech Stack', @@ -38,14 +40,22 @@ export default function TechStackPage() { -
+

Tech Stack

- List of technologies I used so far. + Technologies and tools I've worked with so far.

-

Add list here.

+
    + {TECH_STACK.map(({ category, technologies }) => { + return ( +
  • + +
  • + ); + })} +