Skip to contentJMRG
All projects
COMPLETED

Portfolio

Personal portfolio at jmrg.dev. Next.js 16 with the App Router and React 19, in Spanish and English with translated routes, every piece of content served from the REST API and nothing hard-coded.

Next.js · React · TypeScript · Tailwind CSS · next-intl · Playwright

What it solves

The old site mixed data and presentation, and had no way of telling whether a change made loading worse. Here every section declares which API fields it consumes, and none ships without measuring before and after against the production build.

Server rendering by default

Components only reach the browser when they need interaction, and at the deepest leaf that needs it: marking it higher up would drag the whole tree to the client. Articles are turned into HTML on the server, so the text arrives complete for indexing and costs no JavaScript in the browser.

The sections of the landing page hydrate in pieces rather than in a single blocking pass, so the page answers the first gesture sooner.

Two real languages

Locale prefix always, and translated routes: /es/proyectos and /en/projects are the same page in two languages, not two different pages. Switching language keeps you on the page you were reading, down to the specific article or project.

Alternate tags declare only the languages the content exists in, and the sitemap does the same per entry. Advertising a translation that does not exist sends a crawler to a 404.

A world, not a template

The interface is a machine panel: data typography reserved for data, a single accent colour, cheap CSS motion and no effect that needs an animation library. Pieces that come from a catalogue are rewritten against the panel tokens instead of being installed.

Stack

Layer Technology
Framework Next.js 16, App Router, React 19
Styling Tailwind CSS 4, CSS-first configuration
Languages next-intl, translated routes
Data Own REST API, read from the server
Testing Playwright