Um guia interativo que te acompanha do setup ao Pull Request. Escolha sua trilha e siga o passo a passo.
Fork, clone e instale as dependências para começar a desenvolver.
Acesse o repositório no GitHub e clique em 'Fork' (canto superior direito). Depois clone o seu fork:
Instale as dependências e inicie o servidor de desenvolvimento:
Crie uma branch a partir de develop:
Conheça as pastas principais e onde cada tipo de código vive.
Clique nas pastas para explorar a estrutura do projeto:
Código-fonte principal da aplicação
Arquivos de tradução por idioma (pt-BR, en, es, de)
Crie o componente principal. O projeto tem dois caminhos: páginas dinâmicas (guides/implementações) e standalone.
Qual tipo de página você quer criar?
O projeto tem dois caminhos: páginas dinâmicas (que aparecem em /dicas, /implementacoes ou /ferramentas automaticamente) e páginas standalone (como as de /contribua). Escolha o caminho certo para sua feature.
Páginas dinâmicas são roteadas automaticamente via slug. Você só precisa criar o componente — a rota já existe em /dicas/[slug], /implementacoes/[slug] ou /ferramentas/[slug].
Pasta em kebab-case: graphql-tips/ (não GraphqlTips/)
"use client";import { useTranslations } from "next-intl";import { HeroSection } from "@/components/hero-section";import { SectionWrapper } from "@/components/section-wrapper";export function GraphqlTips() {const t = useTranslations("graphqlTipsPage");return (<div className="min-h-screen"><HeroSectionbadge={t("hero.badge")}title={t("hero.title")}description={t("hero.description")}showBackLinkbackHref="/dicas"/><SectionWrapper id="content">{/* Conteúdo aqui */}</SectionWrapper></div>);}
Páginas dinâmicas NÃO precisam de page.tsx ou loading.tsx próprios — a rota dinâmica [slug]/page.tsx já existe. O próximo passo (Registro) mostra como conectar seu componente ao sistema.
Para páginas fora do sistema dinâmico (ex: seções do /contribua), você precisa criar a rota manualmente:
"use client";import { useTranslations } from "next-intl";import { HeroSection } from "@/components/hero-section";import { SectionWrapper } from "@/components/section-wrapper";export function MinhaFeaturePage() {const t = useTranslations("minhaFeaturePage");return (<div className="min-h-screen"><HeroSectionbadge={t("hero.badge")}title={t("hero.title")}description={t("hero.description")}showBackLinkbackHref="/contribua"/><SectionWrapper id="content">{/* Conteúdo aqui */}</SectionWrapper></div>);}
import { Metadata } from "next";import { getLocale, getTranslations } from "next-intl/server";import { MinhaFeaturePage } from "@/features/contribute/minha-feature";import { buildPageMetadata } from "@/lib/seo";export async function generateMetadata(): Promise<Metadata> {const [t, locale] = await Promise.all([getTranslations("minhaFeaturePage.meta"),getLocale(),]);return buildPageMetadata({title: t("title"),description: t("description"),path: "/contribua/minha-feature",locale,});}export default function Page() {return <MinhaFeaturePage />;}
import { PageSkeleton } from "@/components/page-skeleton";export default function Loading() {return <PageSkeleton />;}
Conecte seu componente ao sistema de rotas, busca e navegação do projeto.
Sistema de páginas dinâmicas
O projeto usa um sistema centralizado: o componente é registrado uma vez e automaticamente ganha rota, SEO, busca e listagem.
Adicione seu conteúdo no array CONTENT_ITEMS. O slug vira a URL, a category define em qual seção aparece.
// src/data/content.tsexport const CONTENT_ITEMS: ContentItem[] = [// ... itens existentes ...{slug: "graphql-tips",title: "GraphQL Tips — Guia Prático",description: "Guia completo de GraphQL...",component: "GraphqlTips",category: "guide",},];
Conecte o nome do componente (string do content.ts) ao import dinâmico real. Use lazy loading com next/dynamic.
// src/lib/content/component-map.tsconst COMPONENT_MAP: Record<string, React.ComponentType<unknown>> = {// ... componentes existentes ...GraphqlTips: dynamic(() =>import("@/features/guides/graphql-tips").then((m) => m.GraphqlTips,),),};
Para sua página aparecer na busca global (Ctrl+K), faça os dois passos abaixo. Sem isso, quem usar o buscador do site não encontra sua página.
Como funciona: o sistema monta os resultados a partir do content.ts; o título e a descrição vêm dos search.json (um por idioma); as palavras-chave vêm do tagMap. Por isso os dois arquivos são obrigatórios.
Sem search.json e tagMap, a página não entra nos resultados da busca.
// messages/pt-BR/search.json → items{"graphql-tips": {"title": "GraphQL Tips — Guia Prático","description": "Guia completo de GraphQL..."}}
// src/components/global-search/search-data.ts — tagMap (dentro de buildTags)const tagMap: Record<string, string[]> = {// ... outros slugs ..."graphql-tips": ["graphql", "api", "query", "guia"],};
Cada página da listagem (/dicas, /implementacoes) usa um iconMap para exibir ícones. Adicione o slug e um ícone do Lucide.
// src/app/dicas/page.tsxconst iconMap = {// ... ícones existentes ..."graphql-tips": Workflow, // import de lucide-react};
Guia completo (loading, nav, changelog): docs/content-management/ADDING_PAGES.md
Padrões de código, componentes disponíveis e boas práticas do projeto.
Todo texto visível precisa ser traduzido. pt-BR é a fonte de verdade.
// messages/pt-BR/myNamespace.json{"title": "Meu título","description": "Descrição do componente"}// messages/en/myNamespace.json{"title": "My title","description": "Component description"}
// Client Component"use client";import { useTranslations } from "next-intl";export function MyComponent() {const t = useTranslations("myNamespace");return <h1>{t("title")}</h1>;}// Server Componentimport { getTranslations } from "next-intl/server";export async function MyServerComponent() {const t = await getTranslations("myNamespace");return <h1>{t("title")}</h1>;}
Dica
O script pnpm translate pode ajudar a gerar traduções automáticas via DeepL para os outros idiomas.
Garantir que todos consigam usar a plataforma é prioridade.
0/8
Lint, testes e build devem passar antes de abrir o PR.
Verifica padrões de código e imports
Executa testes unitários e de componentes
Build completa — valida TypeScript e SSR
Todos devem passar sem erros antes do PR.
Hora de enviar sua contribuição para review!
Use o formato padrão. Exemplos:
feat: add tutorial pagefix: correct translation key for navbardocs: update README with setup instructions
Parabéns! Sua contribuição está a caminho. Após o review, seu código entra na plataforma.