tools

Toolbox

Configuração, design tokens, Git, Docker e utilitários que uso no dia a dia.

Docker : referência rápida

docker : comandos essenciais
# Acessar shell de um container em execução
docker exec -it $(docker ps --format "{{.ID}}	{{.Names}}" | grep "NOME_DO_SERVICO.1" | cut -f1) sh            

# Listar containers com formato personalizado
docker ps --format "table {{.ID}}	{{.Names}}	{{.Status}}	{{.Ports}}"'

# Build com tag
docker build -t minha-app:1.0 .

# Run com porta e variáveis de ambiente
docker run -p 3000:3000 -e NODE_ENV=production minha-app:1.0

# Modo detached (background)
docker run -d --name api minha-app:1.0

# Ver logs
docker logs -f api

# Shell interativo
docker exec -it api sh

# Docker Compose
docker compose up -d              # inicia em background
docker compose down --volumes     # para e remove volumes
docker compose logs -f api        # logs do serviço api
docker compose exec db psql -U user mydb  # acessa banco

# Limpeza
docker system prune -af           # remove tudo não usado
docker volume prune               # remove volumes órfãos

💡 Dica

Use .dockerignore para excluir node_modules, .git, .env e arquivos de desenvolvimento do contexto de build. Imagens menores = deploys mais rápidos.
.dockerignore
node_modules
.git
.gitignore
*.md
.env*
.next
dist
coverage
*.log

tailwind.config.ts

A configuração do Tailwind define design tokens reutilizáveis, cores, fontes, espaçamentos e breakpoints, que mantêm o design consistente em todo o projeto.

tailwind.config.ts (exemplo completo)
import type { Config } from "tailwindcss";

const config: Config = {
  // Paths para o Tailwind escanear e gerar apenas as classes usadas
  content: [
    "./app/**/*.{ts,tsx}",
    "./src/**/*.{ts,tsx}",
    "./components/**/*.{ts,tsx}",
  ],

  // darkMode: "class" ativa dark mode via classe .dark no <html>
  darkMode: "class",

  theme: {
    // Sobrescreve completamente (use para projetos sem defaults do Tailwind)
    // container: { center: true, padding: "1rem" },

    extend: {
      // ===== CORES SEMÂNTICAS =====
      colors: {
        // Cores base do sistema
        base:    "#020617",           // fundo principal
        surface: {
          DEFAULT:  "#0f172a",        // superfície
          elevated: "#1e293b",        // superfície elevada
          card:     "#162032",        // card
        },
        border: {
          DEFAULT: "#1e293b",         // borda padrão
          subtle:  "#334155",         // borda sutil
        },
        text: {
          DEFAULT: "#f1f5f9",         // texto principal
          muted:   "#94a3b8",         // texto secundário
          dim:     "#64748b",         // texto terciário
        },
        accent: {
          DEFAULT: "#38bdf8",         // cor de destaque
          hover:   "#0ea5e9",
          muted:   "#0c4a6e",         // destaque com baixa saturação
        },

        // Brand customizado
        brand: {
          50:  "#f0f9ff",
          100: "#e0f2fe",
          500: "#0ea5e9",
          600: "#0284c7",
          900: "#0c4a6e",
        },
      },

      // ===== FONTES =====
      fontFamily: {
        sans: ["Inter", "system-ui", "sans-serif"],
        mono: ['"JetBrains Mono"', '"Fira Code"', "ui-monospace", "monospace"],
        serif: ["Georgia", "serif"],
      },

      // ===== FONT SIZES CUSTOMIZADOS =====
      fontSize: {
        "2xs": ["0.625rem", { lineHeight: "0.875rem" }],
      },

      // ===== ESPAÇAMENTOS EXTRA =====
      spacing: {
        "18": "4.5rem",
        "88": "22rem",
        "128": "32rem",
      },

      // ===== BORDER RADIUS =====
      borderRadius: {
        "4xl": "2rem",
      },

      // ===== ANIMAÇÕES CUSTOMIZADAS =====
      keyframes: {
        "fade-in": {
          from: { opacity: "0", transform: "translateY(8px)" },
          to:   { opacity: "1", transform: "translateY(0)" },
        },
        "pulse-once": {
          "0%, 100%": { opacity: "1" },
          "50%":       { opacity: "0.5" },
        },
      },
      animation: {
        "fade-in":    "fade-in 0.3s ease-out",
        "pulse-once": "pulse-once 1s ease-in-out 1",
      },
    },
  },

  plugins: [
    // require("@tailwindcss/typography"),  // prose classes
    // require("@tailwindcss/forms"),        // form reset styles
    // require("@tailwindcss/aspect-ratio"),
  ],
};

export default config;

Design Tokens

Design tokens são variáveis nomeadas que representam decisões de design, cores, tipografia, espaçamento. Em Tailwind, você os define no theme.extend e usa como classes utilitárias.

design-tokens-usage.tsx
// Tokens de cor usados como classes Tailwind
function TokenExample() {
  return (
    <div className="bg-base">                    {/* #020617 */}
      <div className="bg-surface">              {/* #0f172a */}
        <div className="bg-surface-elevated">   {/* #1e293b */}
          <p className="text-text-DEFAULT">      {/* #f1f5f9 */}
            Texto principal
          </p>
          <p className="text-text-muted">        {/* #94a3b8 */}
            Texto secundário
          </p>
          <p className="text-accent">            {/* #38bdf8 */}
            Destaque
          </p>
          <div className="border border-border"> {/* #1e293b */}
            Borda padrão
          </div>
        </div>
      </div>
    </div>
  );
}

// Botão com tokens
function Button({ children }: { children: React.ReactNode }) {
  return (
    <button className="
      bg-accent hover:bg-accent-hover
      text-base font-semibold
      px-4 py-2 rounded-lg
      transition-colors
      focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
      focus-visible:ring-offset-surface
    ">
      {children}
    </button>
  );
}
base
#020617
surface
#0f172a
surface-elevated
#1e293b
border
#334155
accent
#38bdf8
text
#f1f5f9
text-muted
#94a3b8
success
#4ade80

@layer base, components, utilities

As diretivas @layer controlam a ordem de cascata e permitem adicionar estilos customizados sem perder a possibilidade de sobrescrever com utilidades.

app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

/* @layer base :       estilos globais de reset e defaults */
@layer base {
  :root {
    --font-mono: "JetBrains Mono", monospace;
    color-scheme: dark;
  }

  html { scroll-behavior: smooth; }

  body {
    @apply bg-base text-text font-sans antialiased;
  }

  /* Typography global */
  h1 { @apply text-3xl font-bold tracking-tight; }
  h2 { @apply text-2xl font-semibold; }

  /* Focus ring global */
  :focus-visible {
    @apply outline-none ring-2 ring-accent ring-offset-2 ring-offset-base;
  }

  ::selection {
    @apply bg-accent-muted text-sky-100;
  }
}

/* @layer components :        componentes reutilizáveis */
@layer components {
  .btn-primary {
    @apply bg-accent hover:bg-accent-hover text-base
           font-medium px-4 py-2 rounded-lg transition-colors
           focus-visible:ring-2 focus-visible:ring-accent;
  }

  .card {
    @apply bg-surface-card border border-border rounded-lg p-4
           hover:border-border-subtle transition-colors;
  }

  .input {
    @apply w-full bg-surface border border-border rounded-lg
           px-3 py-2 text-sm text-text placeholder:text-text-dim
           focus-visible:ring-2 focus-visible:ring-accent
           focus-visible:border-transparent;
  }
}

/* @layer utilities :        utilidades customizadas */
@layer utilities {
  .text-balance { text-wrap: balance; }

  .scrollbar-thin::-webkit-scrollbar { width: 4px; height: 4px; }
  .scrollbar-thin::-webkit-scrollbar-track { @apply bg-surface; }
  .scrollbar-thin::-webkit-scrollbar-thumb { @apply bg-border rounded; }
}

Responsividade

Tailwind usa breakpoints mobile-first. As classes sem prefixo se aplicam a todos os tamanhos; prefixos como sm: se aplicam a esse tamanho e acima.

PrefixoMin-widthUso comum
— (nenhum)0pxmobile
sm:640pxtablet pequeno
md:768pxtablet
lg:1024pxdesktop
xl:1280pxdesktop largo
2xl:1536pxultrawide
responsive-patterns.tsx
// Grid responsivo
<div className="
  grid
  grid-cols-1        // mobile: 1 coluna
  sm:grid-cols-2     // sm+: 2 colunas
  lg:grid-cols-3     // lg+: 3 colunas
  xl:grid-cols-4     // xl+: 4 colunas
  gap-4
">

// Tipografia fluida com clamp (sem breakpoints)
<h1 className="text-[clamp(1.75rem,4vw,3rem)] font-bold">

// Visibilidade por breakpoint
<nav className="hidden lg:flex">         // esconde no mobile
<button className="lg:hidden">           // mostra só no mobile

// Padding responsivo
<div className="px-4 sm:px-6 md:px-8 lg:px-12">

// Flex → Grid em desktop
<div className="
  flex flex-col gap-4
  lg:grid lg:grid-cols-[300px_1fr] lg:gap-8
">
  <aside>Sidebar</aside>
  <main>Conteúdo</main>
</div>

Dark Mode

tailwind.config.ts + uso
// tailwind.config.ts
const config = {
  darkMode: "class", // ativa via classe .dark no <html>
  // ou "media" para respeitar prefers-color-scheme do sistema
};

// Uso de dark: nas classes
<div className="bg-white dark:bg-slate-900">
  <p className="text-slate-900 dark:text-slate-100">Texto</p>
  <div className="border border-slate-200 dark:border-slate-800">
    <span className="text-blue-600 dark:text-sky-400">Link</span>
  </div>
</div>

// Toggle de tema (Client Component)
"use client";
import { useEffect, useState } from "react";

export function ThemeToggle() {
  const [dark, setDark] = useState(true);

  useEffect(() => {
    document.documentElement.classList.toggle("dark", dark);
  }, [dark]);

  return (
    <button onClick={() => setDark((d) => !d)} aria-label="Alternar tema">
      {dark ? "🌙" : "☀️"}
    </button>
  );
}

Git : comandos e boas práticas

Conventional Commits

Formato: type(scope): description

  • feat: nova funcionalidade
  • fix: correção de bug
  • refactor: refatoração sem mudança de comportamento
  • chore: tarefas de manutenção
  • docs: documentação
  • test: testes
  • perf: melhoria de performance
git : comandos do dia a dia
# Branch por feature
git checkout -b feat/user-auth

# Commit convencional
git commit -m "feat(auth): add JWT refresh token rotation"

# Rebase interativo (ajustar histórico antes do PR)
git rebase -i origin/main

# Stash com nome
git stash push -m "wip: form validation"
git stash list
git stash pop

# Log visual
git log --oneline --graph --all --decorate

# Desfazer último commit (preserva mudanças)
git reset --soft HEAD~1

# Cherry-pick de commit específico
git cherry-pick abc1234

# Comparar branch com main
git diff main...HEAD

# Blame para contexto de mudança
git log -p --follow -S "functionName" -- src/auth.ts
.gitconfig aliases úteis
[alias]
  lg = log --oneline --graph --all --decorate
  st = status -sb
  co = checkout
  br = branch
  undo = reset --soft HEAD~1
  aliases = config --get-regexp alias