Guilherme CastroGC/Blog

Building a personal website with AI: 1. Initial project setup

Learn how to get started with Next.js to build a website wit AI.
beginner
ai
nextjs

Welcome to this series on building a personal website. I'll share some thoughts and my experience building my own - the one you're on right now.

I hope this gives you a good enough starting point to get your website up and running!

Choosing technologies

Because this is meant as a personal website and/or simple blog we must ground our technology choices around clear objectives:

  • Easy and simple maintability;
  • Easy to expand and add simple content to;
  • Easy to add and support accessibility;
  • Straightforward to deploy;

I'm going to add another objective, in a super arbitrary way, which is to try some new things out and have fun.

As such in this attempt I tried to find out the latest in web dev and AI, and strategies to combine the two. I challenged myself to try and to build this as fast as possible, using as much AI as I could.

You don't need to do the same, in fact I encourage you to come up with a goal and a set of objectives that make sense to you, and frame this exercise against them. I'm sure it'll be much more rewarding.

I really wanted to try out v0 by Vercel. Because it generates code based on shad/cn, Tailwind CSS and, well, React I followed these choices as well. I also chose Next.js as my site's framework as I wanted to also try out the App Router.

Let's briefly discuss each technology choice.

React

Our beloved library for creating user interfaces out of reusable components is still a great choice, better than ever even. I'm assuming most people reading this will be familiar with React. If not, I highly recommend learning it. Reach out to me on X if you need help.

Of particular interest to us at this time are React Server Components, implemented by Next.js's App Router. We'll use them as the base of our website.

Next.js

Next.js is interesting to us at this time due to it implementing RSCs with its App Router feature. It also presents a good starting point for building any website or app. Combined with Vercel it's also trivial to deploy and manage, without any ops whatsoever.

Tailwind CSS

Tailwind CSS is a great tool for writing styles really fast and really well. Let's break it down:

Writing CSS is not necessarily hard, but there's a lot to it. If you add in a lot of semantic class names as part of your stylesheet, it can get quite complex. It takes cognitive energy to work with, much like overly abstracted code.

Tailwind CSS combines mnemonics, reasonable design primitives and a smaller API surface to greatly reduce this complexity, while maintaining most of the capabilities.

This means that Tailwind CSS easily becomes muscle memory! It becomes effortless to write most styles as you get used to it. This does have a learning curve, of course, but it's not that big.

The intentional choice to eschew semantic class names means you can't entrap yourself back into complexity.

Finally it does not block you from abstracting styles, but that'll be done in shareable, reusable components.

For the purpose of this website Tailwind will allow us to move extremely fast, and build our design as we want.

shad/cn

Shad/cn is a very interesting component library "starter" more or less that provides many pre-built React components built with Tailwind, Radix and other lower-level libraries.

It's an interesting take on the UI component library space in that it allows you to copy paste the code and "own it", as such that you can make modifications to the code, commit it to source control etc.

There are many options available for copy-pastable Tailwind React components but shad/cn is unique in that it is meant as a cohesive design system, including variables and primitives automatically configured when you install it.

For our use case we're going to use a few components to speed up our development. Also, it's the primary output of v0, so we'll want to have these components available for the full setup to work.

v0

v0 is an AI based tool by Vercel which allows us to generate arbitrary UI code from text prompts. It's super fascinating and worth our exploration.

We'll use it to generate starting points for our UI. It'll help us get over the "blank canvas effect" and help us get started, as well as help quickly iterate on design prototypes.

The cool thing is that once you're happy with what it generated, you can copy and paste the code into your project as is. Because it uses Tailwind, there's no CSS dependency to worry about, and it'll just work. It does depend on shad/cn components, however, but we'll have them available in time.

MDX

While it's possible to simply write our blog with html or even really jsx, it's a much better authoring experience to use mdx. Mdx is a superset of Markdown that allows us to use React components directly in our content.

Right now we're not going to set up a CMS or any backend for our content, so we'll simply load it from local mdx files.

AI Tools

As supplementary AI tools for this project, I'm using Perplexity AI for general research, questions and debugging, as well as the Cursor IDE to help me generate code, fixes and for AI-powered autocomplete.

For the images on my website I'm using a combination of ChatGPT's Dall-e and Midjourney.

I'll expand on how to combine these tools into a cohesive workflows, and how to utilize them to better effect.

Setting up a base project

With the most important technologies selected we can start building. This assumes you have a Node.js environment configured. We'll use bun for this tutorial but you can use npm, yarn or pnpm as you like.

Let's start by creating a Next.js project by using create-next-app:

Pro tip: always refer to the original documentation of any command or instruction found online before proceeding.

bunx create-next-app

You can configure the project as you like but make sure to say "Yes" to TypeScript, Tailwind CSS and App Router.

Start the project with:

bun dev

You should be able to see the standard Next.js in localhost:3000.

Project structure

Before we start building, let's familizarize ourselves with the initial project structure.

Starting with the app folder, that's where Next.js will source our app's routes from. It uses a specific convention for file names in order to generate routes correctly. For now let's start with the page.tsx and layout.tsx files.

In Next.js's convention, each route will render these files in a specific order. Let's visualize it in this simplification, visualizing a route as a React component:

<Layout>
  <Page />
</Layout>

For simplicity, we'll be nesting layouts and pages as we build our routes. Thinking about them, a very simple website with a blog can consist of the following files, in the Next.js convention:

/app
- /blog
	- layout.tsx
	- page.tsx
- layout.tsx
- page.tsx

As such, accessing our website's blog route localhost:3000/blog should give us the following "component", as a simplification:

<Layout> -> /app/layout.tsx
  <Layout> -> /app/blog/layout.tsx
    <Page /> -> /app/blog/page.tsx
  </Layout>
</Layout>

Notice how we can start to think about how we want to compose our website. Of course Next.js's App Router can get much more complex than this, but this will get us started.

We'll revisit this once it's time to add a route for the actual blog posts.

Refer to the Next.js documentation for the full hierarchy.

Besides the App Router /app directory, notice how there's many different configuration files, such as tailwing.config.ts, tsconfig.json etc. Each of these files are worth exploring in depth and understanding. For now the standards should suffice.

Installing shad/cn

Let's follow the installation guide from shac/dn for Next.js.

We already created the project, so let's just install shad/cn:

bunx --bun shadcn-ui@latest init

Feel free to configure it as you like. I recommended choosing "Yes" for using CSS Variables.

Shad/cn uses a specific folder structure. Most important being the path in which components are installed to, which is ./components/ui.

For simplicity if we don't change anything the shad/cn CLI and v0 exports will work without issues. Because the structure is reasonable I suggest keeping it.

Installing components is straightforward, like so:

bunx --bun shadcn-ui@latest add button

This will create a Button component in ./components/ui. This pattern is repeated for all shad/cn components.

Getting started

With this initial configuration done, we can start building. What I did for this project, and something I found very fascinating, is using v0 to generate some prototypes.

For example, take a look at this generation I prompted. I ended up using this as the starting point for my blog, and it ended up being pretty much what I needed. Of course, with several tweaks and adjustment, but I find it's a huge boost to productivity versus staring at, as I've mentioned, a blank canvas.

These can be copy pasted into the project, as is. Here's a snippet of the code from the generation I shared:

<main className="col-span-1 lg:col-span-3 grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
	<Card className="group overflow-hidden rounded-lg shadow-lg">
		<img
			alt="Blog Image"
			className="w-full h-48 object-cover transform group-hover:scale-105 transition-transform"
			height={250}
			src="/placeholder.svg"
			style={{
				aspectRatio: "400/250",
				objectFit: "cover",
			}}
			width={400}
		/>
		<CardContent className="p-4">
			<h3 className="text-xl font-bold mb-2">Blog Title 1</h3>
			<p className="text-gray-500">
				This is a short description of the blog post. When the card is hovered, the image will zoom in slightly.
			</p>
		</CardContent>
	</Card>

Notice how it's using Tailwind CSS and shad/cn UI components.

What I recommend is just experimenting, generating some UI, copying it into the project, tweaking, familizaring yourself with the concepts etc. I spent a fair bit of time playing around with these and prototyping ideas until I landed on a design that felt reasonable to me.

As far as a static personal landing page, this should be all that's needed, just design it as you wish and have fun. As surprising as it sounds, we already covered a lot of ground today.

Next Steps

This first part is meant as an introduction to the technology choices and to give you a starting point. On next steps we'll implement actual functionality, interactivity, hook up the content to routes and so forth, until we can finally deploy it and share it with the world.