Henrique Silveira
Voltar

Como construí esse portfólio

As inspirações, as referências, como eu organizei os componentes e a stack por trás desse site.

Todo dev tem aquele portfólio que vive "quase pronto". O meu viveu assim por um bom tempo, até que decidi parar de procurar o template perfeito e construir algo que tivesse a minha cara: um lugar pra guardar as coisas que eu construo, as coisas que eu gosto e os momentos que valem lembrar.

Esse post conta como ele saiu do papel: de onde vieram as ideias, como eu organizei o código e o que tem por baixo do capô.

Inspirações e referências

Antes de escrever qualquer linha, passei um bom tempo olhando portfólios de outros devs. Dois deles me inspiraram muito e merecem uma menção honrosa: o do Rafael Camargo e o do Shreyas Sihasane. Vale a visita.

A ideia nunca foi fazer um currículo em HTML. Eu queria que o site parecesse um caderno pessoal, com anotações à mão na margem, palavras grifadas como se fosse com marca-texto e fotos penduradas na parede. Por isso algumas escolhas se repetem pelo site todo:

  • Coisas escritas à mão. As notas na margem usam uma fonte manuscrita, aparecem letra por letra e vêm até com um som de escrita (dá pra desligar no rodapé).
  • Anotações desenhadas. Os grifos e sublinhados são feitos com o rough-notation, que desenha traços imperfeitos de propósito.
  • Um desktop de verdade. Os projetos ficam em cima de uma área de trabalho estilo macOS, com wallpaper e tudo.
  • Uma colagem de fotos. Os momentos que eu guardo viram um mural no /me, com fotos de formatos diferentes se encaixando.

Pra parte de animação, o Magic UI foi a maior referência. Vários componentes daqui nasceram de lá, como o texto digitando na home, os números que sobem nas reações, o confete e o grão de ruído no fundo. Eu não instalei a biblioteca: reescrevi cada um no projeto, cortando o que não usava e adaptando ao visual daqui.

A stack

  • TanStack Start com React 19: SSR, rotas tipadas e server functions sem precisar de uma API separada.
  • Vite 8 no build e no dev server.
  • Tailwind CSS v4, com as cores e fontes definidas como tokens no próprio CSS.
  • MDX pros posts do blog: cada post é um arquivo .mdx com os metadados exportados no topo.
  • Motion pras animações com mola e Lenis pro scroll suave.
  • Supabase (Postgres) pros contadores de visualização, likes e reações.
  • PostHog pra analytics, sem cookies.
  • Zod validando tudo que chega do banco e das server functions.

Como eu estruturei

O código segue atomic design, com quatro níveis de componentes: átomos são as peças pequenas, moléculas combinam algumas delas, organismos são seções inteiras e templates são o esqueleto das páginas.

src/components/
  atoms/      Pill, Stars, NumberTicker…
  molecules/  PostCard, NavLink, LangToggle…
  organisms/  Header, JobTimeline, Playlist…
  templates/  SiteLayout, PageTemplate…

Cada pasta tem um index.ts que reexporta tudo, então um import fica sempre assim:

import { PostCard, SectionHeading } from '~/components/molecules'
A regra que eu sigo é simples: um átomo não sabe nada do site, enquanto um organismo pode buscar dados e montar uma seção inteira. Quando um componente começa a precisar de contexto demais, ele sobe de nível.

Conteúdo separado do código

Os textos e os dados não ficam espalhados pelos componentes:

  • src/content/ guarda o conteúdo: posts em MDX, projetos, a stack, a playlist, as recomendações.
  • src/lib/i18n.ts concentra todas as strings da interface em português e inglês. O site abre em pt-BR, e o idioma é resolvido já no servidor, então não existe aquele "pisca" de inglês pra português depois que a página carrega.

Assim, trocar um texto ou adicionar um projeto nunca exige mexer em componente.

Pequenos cuidados

  • Tudo que é animação respeita o prefers-reduced-motion.
  • O PostHog só carrega depois da hidratação e não usa cookies, por isso não tem banner de consentimento.
  • As fotos da galeria passam por um script antes do build que lê as dimensões de cada imagem, então o layout não pula quando elas carregam.

E agora?

O site nunca vai estar "pronto", e essa é a graça. A ideia é que esse blog seja o lugar pra contar o que eu ando aprendendo. Se tiver algo que você quer ver por aqui, me chama.