gabriel denardi
←voltar pros posts

6 min de leitura

Como eu montei esse blog

Por que subdomínio, por que Next.js com MDX, as três tentativas de visual e como funciona a cordinha que apaga a luz do site.

  • #blog
  • #nextjs
  • #css

No primeiro post eu falei que o próximo provavelmente seria sobre como eu montei esse blog. Olha só, cumpri uma promessa kkkk

Já aviso que esse é mais técnico. Se você veio pela parte da vida, pode pular direto pra parte dos visuais, que é mais fofoca do que código.

Subdomínio ou /blog?

A primeira decisão foi onde o blog ia morar. Meu portfólio já fica em gabrieldenardi.com.br, então eu tinha dois caminhos: colocar o blog dentro dele, em /blog, ou criar um projeto separado em blog.gabrieldenardi.com.br.

Muita gente defende o /blog por causa de SEO, porque o Google enxerga tudo como um site só e o blog aproveita a reputação do domínio principal. Mesmo sabendo disso, fui de subdomínio.

O motivo foi bem prático. O portfólio carrega um monte de dependência que um blog não precisa, e juntar os dois ia deixar o build mais pesado à toa. Separado, cada um tem o seu repositório e o seu projeto na Vercel, e eu posso mexer em um sem medo de quebrar o outro.

A stack

Nada de CMS. Cada post é um arquivo .mdx dentro do repositório. Pra publicar, eu crio o arquivo, dou commit e push, e a Vercel faz o resto sozinha.

  • Next.js 16, com tudo gerado no build. Quando você abre um post, não tem servidor processando nada, é só um HTML pronto.
  • MDX, que é Markdown que aceita componente React. Aquela caixinha de "aviso" do primeiro post é um componente.
  • Tailwind 4 pro CSS.
  • Shiki pra colorir os blocos de código, com um tema preto e branco que eu fiz pra combinar com o resto.
  • Zod validando o cabeçalho de cada post. Se eu esquecer o título ou escrever a data errada, o build quebra e me diz em qual arquivo foi.

O cabeçalho também aceita um draft: true. Post marcado assim só aparece quando eu rodo o projeto na minha máquina. Esse aqui mesmo nasceu como rascunho.

Três visuais até acertar

No primeiro post eu contei isso por cima, então aqui vai a versão completa.

  1. A cópia do portfólio. Fundo off-white, título em fonte serifada, tudo bem sóbrio. Ficou bonito, mas parecia o portfólio com outro nome, e eu queria que o blog tivesse cara própria.
  2. A azul. Azul cobalto, a fonte Hubot Sans (da mesma família que o GitHub usa) e um gráfico de commits de enfeite. Parecia uma ótima ideia até eu perceber que era mais enfeite do que blog.
  3. A preto e branco. Mais descontraída e cheia de animação. Foi a primeira que eu olhei e pensei "beleza, é isso".

As fontes são duas. Nos títulos uso a Anybody, que tem um eixo de largura: dá pra esticar ou espremer as letras sem trocar de fonte, e os títulos daqui usam ela um pouco mais larga que o normal. No texto uso a Atkinson Hyperlegible, que foi desenhada pelo Braille Institute pensando em quem tem baixa visão. Uma letra em que não dá pra confundir l, I e 1 é boa pra todo mundo, ainda mais num blog que tem código.

Os detalhes que eu mais gosto

A cordinha

Lá no canto de cima tem uma cordinha. Puxa e o site troca entre o tema claro e o escuro. Ela balança quando você passa o mouse, estica quando você puxa, e o tema novo se espalha num círculo que sai da ponta dela, como uma luz acendendo.

Esse círculo vem da View Transition API. O navegador tira uma foto da página antes da troca, aplica o tema novo e anima a passagem de um pro outro. Eu só precisei dizer de onde o círculo sai:

::view-transition-new(root) {
  animation: lights-out 0.75s cubic-bezier(0.7, 0, 0.25, 1);
}
 
@keyframes lights-out {
  from {
    clip-path: circle(0 at var(--switch-x, 100%) var(--switch-y, 0));
  }
  to {
    clip-path: circle(150vmax at var(--switch-x, 100%) var(--switch-y, 0));
  }
}

O --switch-x e o --switch-y são a posição da pontinha da cordinha, que eu pego com JavaScript na hora do clique. Se o seu sistema estiver configurado pra reduzir animações, o tema troca na hora, sem círculo nenhum. E a escolha fica salva: se você apagar a luz hoje e voltar amanhã, ela continua apagada.

As letras que pulam

O título de cada post é quebrado letra por letra. Cada letra é um span com o seu próprio atraso, e é por isso que elas sobem uma depois da outra quando a página abre. Passa o mouse em cima de uma e ela dá um pulinho torto. Não serve pra absolutamente nada, e é o meu detalhe favorito kkkk

Pra quem usa leitor de tela isso seria um desastre (imagina ouvir o título soletrado), então as letras animadas ficam escondidas dele, e o título inteiro vai junto numa versão invisível.

O rabisco no "vida"

Na página inicial, a palavra "vida" ganha um círculo feito à mão. É um SVG com um truque antigo: o traço começa escondido com stroke-dashoffset e vai aparecendo aos poucos, como se alguém estivesse rabiscando na hora.

A barra de leitura sem JavaScript

Quando você rola um post, aparece uma barrinha no topo mostrando quanto já leu. Ela é só CSS:

.reading-progress {
  animation: progress linear both;
  animation-timeline: scroll(root block);
}
 
@keyframes progress {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

O animation-timeline: scroll() amarra a animação à rolagem em vez do tempo. Rolou metade da página, a animação tá na metade. Sem nenhum listener de scroll. Nos navegadores que ainda não suportam isso, a barra simplesmente não aparece e a vida segue.

O mesmo truque, trocando scroll() por view(), faz as coisas aparecerem conforme você rola a página.

Fora isso tem a faixa inclinada rodando na página inicial (passa o mouse que ela para), os botões com sombra dura que afundam quando você clica e a imagem de compartilhamento de cada post, que é gerada sozinha no build com o título dele.

O que deu errado

Óbvio que não saiu tudo de primeira.

  • O título da página inicial nasceu enorme. Diminuí, e aproveitei pra trocar a frase, porque a primeira só falava de código e o blog não vai ser só isso.
  • No celular, o rabisco em volta do "vida" invadia a palavra seguinte. Troquei as medidas de pixel pra em, que acompanham o tamanho da fonte, e engrossei o traço, porque na tela pequena ele quase sumia.
  • O cabeçalho passava da largura da tela do celular por 8 pixels. Oito. Uma rolagem lateral inteira por causa de oito pixels kkkk
  • Tinha botão de RSS no topo e no rodapé, e eu tirei os dois porque só ocupavam espaço. O feed continua em /rss.xml pra quem ainda usa leitor de RSS (respeito muito).

Enfim

O blog tá pronto, e agora o difícil passa a ser escrever.

Ah, e depois que ele foi pro ar, meu portfólio resolveu aparecer inteirinho em Times New Roman. O código tava certo e o problema era outro, mas isso rende um post só dele.

Se quiser saber como alguma dessas coisas funciona por dentro, me manda um e-mail pelo botão aqui embaixo.