US
Home Contact Projects Blog 
2026 © All rights reserved.
Built with ♡& Next.js 16
About Me

Blog and Portfolio: A Personal Website Built with Next.js 

Ulises Sánchez
7 min readUpdated May 7, 2026
Categories:#Next.js#Sanity
Screenshot of the homepage of this website
Table of contents
  • Learning with a real project
  • Initial technologies and tools
  • Beyond the Portfolio: The Blog
  • Integrating a CMS
  • Migrating from Next 13 to 14
  • Implementing Sanity
  • Automatic Table of Contents
  • Reading Time Calculation
  • Graphic and text resources
  • Conclusion
  • Updates
    •  Q2 2026

At the beginning of 2023 I learned React, a frontend development library created and maintained by Meta (or Facebook, for friends).
I found React easy to use, and the idea of separating the interface into components made maintenance and scalability much easier.

As an example, we can think of each part of the interface as a piece of Lego which we can use or replace at any time.

At that time I had two objectives in mind:

  1. Learn Next.js, a React framework.
  2. Create a portfolio to share my projects and ideas.

I like to use a comparison I read a while ago: let's imagine Iron Man. The person inside the suit is React; Next.js is the suit that gives him superpowers.
As an example, if we want to have routing in React we must install React Router DOM, while in Next.js it is enough to create folders.

Learning with a real project

One of my favorite ways to learn is by creating projects. In this case, I searched for a web portfolio from scratch with Next.js and found one on an English-language YouTube channel.

Every day I spent an hour: I watched a section of the video, tried to replicate it and, if I got stuck or forgot something, I repeated it until I succeeded.

The hardest thing for me was the styles, as I had no experience with Tailwind (the framework used in the video). However, as the days went by, it became easier. I liked that it allows styling with great versatility, unlike other frameworks like Bootstrap that already have predefined components.

Initial technologies and tools

The process lasted about three months and I learned a lot:

  • Switch from SVG icons to React Functional Components (RFC).
  • Use the Page Router.
  • Components such as Link or Image, which make it easier to optimize images and navigation.
  • Bookstore Motion for animations.
  • Integration with Tailwind.
  • Tools such as Canva to create assets.

In the end, I had a static portfolio, but I wasn't satisfied.

Beyond the Portfolio: The Blog

I wasn't entirely satisfied: I wanted something more personal that reflected part of me and allowed me to give free rein to another hobby which is writing.

I started by creating a contact page using:

  • React Hook Form to validate data.
  • EmailJS to manage the sending of emails.
  • Sonner to show notifications.
  • Toast for a light but eye-catching animation next to the form.

Integrating a CMS

It was clear to me that I needed a CMS (Content Management System) to manage content without touching code every time you want to change a project or image.

In short, a CMS rests on three pillars:

  1. VPS or cloud service to host it.
  2. Database.
  3. Warehouse for objects (files, images, etc.).

My options were Outstatic, Tina, Payload, Strapi, and Sanity.

Migrating from Next 13 to 14

Most of these CMSs used the App Router, officially introduced in Next 14. So, to keep my site up to date, I had to migrate from Next 13 to Next 14 and change the Page Router by App Router.

I read the documentation and it seemed as simple as executing a command... And so it was: in less than a minute everything was up to date.
The tricky part was changing the router:

  • I created a new folder structure.
  • I placed the folder App within SRC to maintain order.
  • I learned to work with Server Components, which involved segmenting some components that used animations or hooks as useState.

Fun fact: It was possible to use both routers at once, which made it easy to progressively migrate.

Implementing Sanity

I chose Sanity because of its free plan and because I wouldn't have to worry about maintaining databases or object containers.

The implementation was quick, although I had a problem with the styles: the CMS panel conflicted with those on my website. I fixed this by wrapping the CMS and app in separate folders.

My project's folder structure
Folder Structure | Own authorship

Automatic Table of Contents

For navigation on the post and project pages, I wanted a table of contents to be automatically generated with the titles of each section.

I based it on the publication How to Make a Table of Contents from Sanity Block Content by Abdurezak Farah, which explains how to extract headings from Sanity and convert them into a hierarchical structure to render them as a listing with internal links.

From that idea, I adapted the code to my project and managed to make sure that every time I create a post or project, the system detects the headings and automatically builds the table of contents.

Reading Time Calculation

To estimate the reading time of each post, I use a very simple formula in my consultation to Sanity, for which I investigated the average number of words a person reads per minute and the average number of letters per word:

Javascript
const wpm = 180; // Palabras por minuto promedio
const meanWordCharacterCount = 5; // Caracteres promedio por palabra

"estimatedReadingTime": round(
  length(pt::text(description)) / meanWordCharacterCount / wpm
)
const wpm = 180; // Palabras por minuto promedio
const meanWordCharacterCount = 5; // Caracteres promedio por palabra

"estimatedReadingTime": round(
  length(pt::text(description)) / meanWordCharacterCount / wpm
)

This line takes the total length of the text (length(pt::text(description))), divides it by the average number of characters per word and then by the words a person reads per minute, then rounds the value to show an integer number of minutes.

Graphic and text resources

For the images I used:

  • Adobe Illustrator
  • Canva
  • LottieFiles
  • unDraw

With the exception of Illustrator, all are free tools and highly recommended.

For texts:

  • Microsoft Word for drafts.
  • Sanity's rich editor to give the final format.

Conclusion

This project not only allowed me to learn Next.js, Tailwind and the integration of a CMS, but also to solve real problems that do not appear in theory.

Today, this portfolio/blog is a window to show some of my projects and share ideas and thoughts, being proof that learning a technology from scratch is possible if it is combined with perseverance and little (a lot actually) patience.

Updates

As of today I have left my site quite neglected, so I will make some changes, I will put aside the idea of having several projects and I will focus on having a few well maintained, within them is this project, the first change I will make is to make it open source and from then on I will continue to implement quarterly updates.

Q2 2026

DescriptionStatus
Upgrade to Next 16Implemented
Add transition animations for post and project pagesDiscarded
Create a virtual petIn process
Improve Portable Text integration (tables, footer in images, spacing, and code-type text)Implemented
Add open graph (meta description and image) in posts and projectsImplemented
Add social sharing buttons to posts and projectsImplemented
Add filter to sort projects and posts by date or name and in descending and ascendingPending

For more details you can consult the CHANGELOG of the project.

View project

Comments

Share your thoughts or ask a question. I take the time to read and reply to every comment.

All comments

Loading comments...