Atenção: Este conteúdo foi traduzido automaticamente. Enviar feedback

Site de portfólio pessoal

Um portfólio moderno e focado em conteúdo criado com Next.js 16, React 19 e TypeScript. Criado do zero com desenvolvimento assistido por IA.

Role: Desenvolvedor e designerdez. de 2025

Durante anos, eu disse a mim mesmo que criaria um site pessoal. O domínio acumulou poeira. A ideia nunca saiu do aplicativo de anotações.

Então, parei de planejar e comecei a criar. Dois dias depois, este site estava no ar.

O que mudou

Eu costumava pensar que entregar um site significava semanas de trabalho. Escolher fontes. Depuração de layouts. Escrever um texto que nunca parecia certo. Dessa vez, eu tinha uma abordagem diferente: criar com IA, entregar rapidamente e melhorar depois.

O resultado: 51 confirmações em 48 horas. Um blog com narração em áudio. Um formulário de contato que realmente funciona. Um sistema de design que posso ampliar. Não é perfeito, mas é real.

O que me surpreendeu não foi a velocidade. Foi a sensação do trabalho. Menos pesquisa, mais construção. Menos dúvidas, mais entrega. As ferramentas cuidaram das partes tediosas para que eu pudesse me concentrar no que importava.

Esta página é a história completa. Como foi montado, o que está por trás e o que eu faria diferente da próxima vez.

Cursor IDE
Cursor IDE com o assistente Claude

Pilha técnica

CategoryTechnologyVersionPurpose
FrameworkNext.js (App Router)16.0.10Server components, routing, SSR
UI LibraryReact19.2.3Component architecture
LanguageTypeScript5.xType safety
StylingTailwind CSS4.xUtility-first styling
Componentsshadcn/uiNew YorkPre-built accessible components
Contentnext-mdx-remote5.0.0MDX rendering with frontmatter
Parsinggray-matter4.0.3Frontmatter extraction
IconsLucide React0.561.0SVG icon library
EmailSendGrid8.1.6Contact form delivery
AnalyticsGoogle Analytics 4Traffic and behavior tracking
AudioElevenLabs Audio NativeText-to-speech for blog posts
Dependencies
Dependências do package.json

Arquitetura

O aplicativo segue as convenções do Next.js App Router com uma separação clara entre páginas, componentes, conteúdo e utilitários.

ftchvs_26/
├── app/ # Páginas do roteador de aplicativos Next.js
│ ├─── layout.tsx # Layout raiz com fontes e navegação
│ ├─── page.tsx # Página inicial
│ ├─── globals.css # Estilos globais e tokens de design
│ ├─── about/ # Página sobre
│ ├─── blog/ # Listagem de blogs e páginas [slug]
│ ├─── projects/ # Listagem de projetos e páginas [slug]
│ ├─── contato/ # Formulário de contato com rota de API
│ └─── currículo/ # Página de currículo
├─── componentes/ # Componentes React
│ ├─── nav.tsx # Navegação com folha móvel
│ ├─── theme-toggle.tsx # Alternância entre os modos escuro e claro
│ ├─── tts-player.tsx # Reprodutor de áudio da ElevenLabs
│ ├─── mdx-content.tsx # Renderizador MDX
│ └─── ui/ # componentes shadcn/ui
Conteúdo/ # arquivos de conteúdo MDX
│ ├─── blog/ # Postagens de blog
│ ├─── páginas/ # Páginas estáticas (sobre)
│ └─── projetos/ # Estudos de caso de projetos
├─── lib/ # Utilitários
│ ├─── content.ts # Carregamento e análise de conteúdo
│ ├─── constants.ts # Configuração do site
│ ├─── schema.tsx # Dados estruturados JSON-LD
│ └── utils.ts # Funções auxiliares
└─── public/ # Ativos estáticos

Fluxo de dados

O conteúdo flui dos arquivos MDX por meio de lib/content.ts para as páginas:

  1. Arquivos MDX armazenam o conteúdo com o frontmatter YAML
  2. **O gray-matter analisa o frontmatter em objetos tipados
  3. O next-mdx-remote serializa o MDX para renderização do React
  4. Componentes de página buscam conteúdo no momento da solicitação
  5. Componentes MDX renderizam o HTML final
GitHub Repo
Estrutura do repositório do GitHub

Sistema de design de tipografia

Criei um sistema de tipografia baseado em tokens para criar um estilo consistente em todas as páginas. Cada token é mapeado para classes específicas do Tailwind.

TokenCSS ClassStylesUsage
Page Title.text-page-titletext-xl font-medium mb-6H1 headings
Section Title.text-section-titletext-lg font-medium mt-8 mb-4H2 headings
Subsection.text-subsection-titletext-base font-medium mt-6 mb-3H3 headings
Body.text-bodytext-[15px] leading-relaxed text-foreground/90Paragraphs
Body Container.text-body-containerspace-y-4 text-[15px] leading-relaxedMultiple paragraphs
Meta.text-metatext-[14px] text-muted-foregroundDates, tags, labels
Link.text-linkunderline underline-offset-2 hover:text-foregroundInline links
List Item.text-list-itemtext-sm text-foreground/80Card and list text

Pilha de fontes

  • Geist Sans** - Tipo principal para o corpo do texto e a interface do usuário
  • Geist Mono** - Blocos de código e o logotipo do terminal

Ambas as fontes são carregadas via next/font/google com display: swap para otimizar o desempenho.

Sistema de cores

As cores usam o espaço de cores OKLCH para ajustes perceptualmente uniformes. O sistema inclui:

  • Modo claro - Escala de cinza neutra com acentos sutis
  • Modo escuro** - Fundos profundos com texto de alto contraste
  • Cores semânticas** - Primárias, secundárias, suaves, acentuadas, destrutivas, de sucesso

Principais recursos

Modo escuro

A preferência de tema persiste no localStorage e respeita as configurações do sistema na primeira visita. Um script de bloqueio no <head> impede o flash do tema errado.

<script dangerouslySetInnerHTML={{
  __html: `(function(){
    var t = localStorage.getItem('theme') ||
      (matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light');
    if (t === 'dark') document.documentElement.classList.add('dark')
  })();`,
}} />

Texto para fala

O player é carregado dinamicamente para evitar problemas de hidratação:

const TTSPlayer = dynamic(
  () => import('@/components/tts-player').then((mod) => mod.TTSPlayer),
  { ssr: false }
);

Criando um clone de voz no ElevenLabs

Para criar seu próprio clone de voz para o reprodutor de áudio:

  1. Registre-se ou faça login no [ElevenLabs] (https://elevenlabs.io)
  2. Navegue até a seção Voices no dashboard (barra lateral esquerda)
  3. Clique em Adicionar uma nova voz
  4. Escolha Professional Voice Clone (recomendado para melhor qualidade) ou Instant Voice Clone (mais rápido, requer menos áudio)
  5. Faça upload de amostras de áudio:
    • Professional Voice Clone: Pelo menos 1 hora de áudio de alta qualidade (o ideal é de 2 a 3 horas para obter melhores resultados)
    • Clone de voz instantâneo**: Mínimo de 30 segundos de áudio limpo
    • Divida gravações longas em amostras de aproximadamente 30 minutos para facilitar o upload
    • Use gravações limpas e de alta qualidade sem ruído de fundo, eco ou sons indesejados
  6. Opcionalmente, grave diretamente na interface usando Record yourself com os scripts de amostra fornecidos
  7. Nomeie e rotule seu clone de voz
  8. Confirme que você tem o direito e o consentimento para clonar a voz
  9. Clique em Salvar voz para treinar o modelo
  10. Depois de treinado, copie o ID de voz das configurações de voz
  11. Configure-o no projeto atualizando ELEVENLABS_VOICE_ID em lib/constants.ts

Amostra de voz

Aqui está uma amostra da voz clonada:

Amostra de voz
0:00 / 0:00

Para gerar a amostra de áudio, você pode usar o [playground Text to Speech da ElevenLabs] (https://elevenlabs.io/app/speech-synthesis/text-to-speech). Selecione sua voz clonada, digite o texto, clique em Generate (Gerar), faça download e salve o arquivo como voice-sample.mp3 no diretório public/audio/.

Narração de áudio do blog (Kokoro local)

Atualização — abr/2026. Os posts do blog e a página About agora usam Kokoro-82M, um modelo TTS com licença Apache 2.0 (82M de parâmetros, voz af_heart) rodando localmente na CPU via kokoro-onnx. A geração é determinística, gratuita e não depende de nenhuma API externa. A amostra de voz acima continua sendo a voz clonada original do ElevenLabs — só a narração do blog foi migrada.

O setup é único: npm run setup:kokoro cria um diretório .kokoro/ gitignorado com um venv Python e o modelo ONNX (~340 MB). Depois, npm run generate-audio narra todo o conteúdo em inglês e atualiza public/audio/manifest.json com hashes por post. Em um Apple M4 Max o modelo roda a cerca de 5× o tempo real — um post de três minutos gera em torno de trinta segundos.

Formulário de contato

O formulário de contato usa o SendGrid para a entrega de e-mails com:

  • Validação no lado do cliente
  • Rota de API do lado do servidor em /contact/api
  • Cabeçalho "Responder a" para respostas diretas
  • Tratamento de erros com mensagens fáceis de usar

SEO

Cada página inclui:

  • Metadados - Título, descrição, palavras-chave
  • Open Graph** - Imagens e texto de compartilhamento social
  • Twitter Cards** - formatação específica do Twitter
  • JSON-LD** - Dados estruturados para pessoa, site, artigo, Breadcrumb
  • Mapa do site** - Gerado automaticamente em /sitemap.xml
  • Robôs** - Regras de rastreamento do mecanismo de pesquisa
Dashboard da Vercel
Dashboard da Vercel

Processo de compilação

Fase 1: Configuração do projeto

Iniciado com create-next-app usando o modelo do App Router. Adicionamos TypeScript, Tailwind CSS 4 e configuramos o shadcn/ui com a variante de estilo New York.

npx create-next-app@latest ftchvs_26 --typescript --tailwind --app
npx shadcn@latest init

Fase 2: Layout do núcleo

Criamos o layout raiz com as fontes Geist e uma navegação responsiva. A navegação inclui um menu para desktop e uma folha para celular (gaveta deslizante) do shadcn/ui.

O logotipo do terminal (>_) usa uma animação cintilante que se adapta aos modos claro e escuro.

Fase 3: sistema de conteúdo

Criado o lib/content.ts para lidar com o carregamento do MDX:

  • getAllPosts() - Busca todas as postagens do blog classificadas por data
  • getPostBySlug() - Busca um único post com MDX serializado
  • getAllProjects() - Busca todos os projetos
  • getProjectBySlug() - Busca um único projeto com MDX serializado
  • getPageBySlug() - Busca páginas estáticas como About

Cada função lê do sistema de arquivos, analisa o frontmatter com gray-matter e serializa o conteúdo com next-mdx-remote.

Fase 4: páginas

Criamos seis rotas principais:

  • Home - Introdução com lista de textos recentes
  • Sobre** - Histórico profissional carregado do MDX
  • Blog** - Listagem de posts e páginas de posts individuais
  • Projetos** - Mostra de projetos (esta página)
  • Currículo** - Experiência profissional e habilidades
  • Contato** - Formulário com integração com SendGrid

Fase 5: Integrações

SendGrid: Rota de API configurada para enviar e-mails do formulário de contato. O remetente deve ser verificado nas configurações de autenticação do SendGrid.

Google Analytics 4: Adicionado via @next/third-parties com carregamento condicional baseado em NEXT_PUBLIC_GA_ID.

Fase 6: Sistema de design

Implementação de tokens de design de tipografia em globals.css. Adicionadas variáveis de cor OKLCH para os modos claro e escuro. Criação de animação shimmer com propriedades personalizadas do CSS.

Fase 7: SEO

Adicionados metadados a todas as páginas. Criação de geradores de mapa do site e robots.txt. Implementação de dados estruturados JSON-LD para os esquemas Person, WebSite, Article e BreadcrumbList.

Fase 8: Implementação

Transferido para o GitHub e importado para o Vercel. Variáveis de ambiente configuradas:

  • NEXT_PUBLIC_SITE_URL - URL canônico
  • NEXT_PUBLIC_GA_ID - Google Analytics
  • SENDGRID_API_KEY - Entrega de e-mail
  • CONTACT_EMAIL_TO - Endereço do destinatário
  • CONTACT_EMAIL_FROM - Remetente verificado
Implantação da Vercel
Detalhes da implantação da Vercel

Registro de alterações

Uma linha do tempo detalhada do desenvolvimento, extraída do histórico de commits do Git. Último primeiro.

Estatísticas de desenvolvimento

  • Total de commits**: 51
  • Tempo de desenvolvimento**: ~2 dias
  • Principais recursos**: 8
  • Correções de bugs: 12
  • Refatores**: 15
  • Atualizações de estilo**: 16

13 de dezembro de 2025 - Dia 2: polimento e recursos

Noite: Polimento final

CompromissoDescrição
20107f4Major: Melhorias abrangentes de SEO
e3ec3c2Introdução simplificada da página sobre
Configuração centralizada do ID de voz
Configuração de voz personalizada da ElevenLabs
f8533bfMaior: Otimização do ElevenLabs para reduzir os custos de API
f8d31cfPosicionamento do player TTS acima do resumo
7da002aAtualização da tipografia da lista de blogs
872a6baRevisão da postagem do blog para maior clareza e narrativa

Evening: Otimização de áudio

CommitDescrição
fc9cea4Usado ref para inserir HTML (correção de hidratação)
fb9303fUsado iframe embed para áudio nativo
7384478Restaurado o Suspense wrapper para compatibilidade com MDX
ff9ca71Maior: API do Audio Native com projetos de conteúdo completo
76e6e08Removido o Suspense para o Audio Native do SSR
36c512cCarregar Audio Native via useEffect
ID de usuário público codificado com força5073332
ea4e5c7Utilizado próximo/script para carregamento do Audio Native
8a5ee20Simplificado para integração do Audio Native
32fa6caAdicionado script para limpar o cache de áudio
61382caAdicionado cache de áudio para reduzir as chamadas à API
0ab2855Pré-geração de áudio TTS no carregamento da página
d59988fAdicionado registro de depuração ao player TTS

Final da tarde: Sprint de integração de áudio

CommitDescrição
d018e8eRemovido o rodapé da ElevenLabs do player
156eda5Tornou o seletor de velocidade mais minimalista
b87be4fRemovido o cabeçalho da ElevenLabs do player
1d6af2fExibição imediata da interface completa do player de áudio
1a90ebfAtualizamos o player TTS com os componentes de interface do usuário da ElevenLabs
738ebb4Substituiu o Audio Native pela API TTS
fa6fd42Adicionada configuração e regras do Cursor IDE
5152aecMDXRemote com Suspense para React 19
c7b54b2Maior: Adicionada a integração do ElevenLabs Audio Native TTS

Tarde: Tipografia e currículo

CompromissoDescrição
2ff75d4Atualização da declaração de aprendizado na postagem do blog
0c9b17bAtualizada a tagline do currículo
3e6b185Adicionado o prefixo dash aos itens de Habilidades e Educação
3371a03Removida a seção "Looking For" do currículo
649010dMelhoria da tipografia e do alinhamento do currículo
Atualizados os tamanhos de fonte para itens de lista, links e meta texto

Late Morning: Estratégia de conteúdo

| Commit | Descrição | Conteúdo |--------|-------------| | Adicionada segmentação de público-alvo à página Sobre | 45e61a2 | Mensagem de "eu mesmo construindo ferramentas" atenuada | | b7a8cd8 | Atualizações do README para novo posicionamento | ae9f3a3 | Posicionamento refinado do growth marketer em todas as páginas | | 701a36f | Reposicionamento do site como "growth marketer que codifica" | | db41419 | Substituição da página de projetos pelo espaço reservado "Em breve" |

Morning: Sistema de design

CommitDescrição
4b7f5ffAtualização do README com tokens de tipografia, SendGrid, documentos do GA4
d850b7eMenu de navegação reordenado: Sobre, Blog, Projetos, Currículo, Contato
a17536bMaior: Implementação do sistema de token de design de tipografia
a91398fAtualização do favicon para o ícone de prompt do terminal (>_)
Remoção da borda do anel de foco no logotipo do terminal
af50e11Animação shimmer refatorada para suporte ao modo claro/escuro

12 de dezembro de 2025 - Dia 1: Fundação

CompromissoDescrição
0b4e0a2Major: SendGrid integrado ao formulário de contato com interface de usuário aprimorada.
Seleção de texto corrigida ao clicar no logotipo do terminal
2ab20b1Geração estática desativada para MDX (correção de compatibilidade com o React 19)
Adicionadas páginas, componentes e recursos principais
891648cDocumentação README mesclada
08bc5e0Maior: Site inicial do portfólio Next.js com estrutura de blog e projetos.
7850991Inicialização do repositório no GitHub
20aed18Confirmação inicial do aplicativo Create Next

Principais marcos:

  • Estrutura completa do App Router com 6 rotas
  • Sistema de conteúdo MDX com análise de matéria cinza
  • Integração da biblioteca de componentes shadcn/ui
  • Formulário de contato com envio de e-mail
  • Navegação responsiva com gaveta móvel
Histórico de commits
Histórico de commits do GitHub

Capturas de tela

Luz da página inicial
Modo de luz da página inicial
Página inicial escura
Modo escuro da página inicial
Navegação móvel
Navegação móvel
Formulário de contato
Formulário de contato
Postagem do blog
Postagem de blog com reprodutor de áudio

O que eu aprendi

O desenvolvimento assistido por IA é real. O Cursor e o Claude lidaram com o boilerplate, detectaram erros e sugeriram padrões que eu não teria encontrado sozinho. O gargalo deixou de ser a digitação e passou a ser o pensamento.

**Os erros de digitação detectaram bugs antes que eles chegassem ao navegador. O tempo de configuração inicial economizou horas de depuração.

**A definição de classes de tipografia uma vez significou um estilo consistente sem decisões constantes. As alterações se propagam automaticamente.

O MDX é flexível. Os esquemas de frontmatter permitem que o conteúdo conduza a interface do usuário. A adição de um novo campo leva minutos, não refatorações.


Próximas etapas

  • Adicionar mais projetos como estudos de caso
  • Implementar pesquisa e filtragem de posts do blog
  • Adicionar feed RSS para assinantes do blog
  • Explorar a ISR (Incremental Static Regeneration) para atualizações de conteúdo

Outcomes

  • Criado do zero com desenvolvimento assistido por IA (Cursor + Claude)
  • Implementação do sistema de token de design de tipografia personalizada
  • ElevenLabs Audio Native integrado para conversão de texto em fala
  • Configuração do SendGrid para a funcionalidade do formulário de contato
  • Implementado no Vercel com SEO abrangente

Links