Communitygithub.com

Samueladewole/claude-skills

Construa componentes de frontend acessíveis, responsivos e performáticos seguindo melhores práticas de sistemas de design, CSS moderno e padrões agnósticos de framework.

O que é claude-skills?

Esta skill auxilia designers e desenvolvedores de frontend a criar interfaces de usuário consistentes, acessíveis e de alto desempenho, adotando um conjunto de melhores práticas modernas. Ao utilizá-la, você obtém componentes reutilizáveis, conformidade WCAG 2.1 AA, design responsivo mobile-first e alinhamento com sistemas de design. A skill fornece padrões de componentes (como Botão, Cartão e Input), tokens de design (cores, espaçamento, tipografia, sombras), padrões de acessibilidade (skip links, gerenciamento de foco, ARIA labels) e técnicas de otimização de performance (CSS crítico, lazy loading, code splitting). Ela é ideal para projetos em qualquer framework (React, Vue, Svelte) e pode ser integrada a fluxos de trabalho que vão do Figma à produção.

Funciona com✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/Samueladewole/claude-skills/tree/HEAD/frontend-designer

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Frontend Designer

Uma skill abrangente para designers e desenvolvedores de frontend criarem interfaces de usuário bonitas, acessíveis e performáticas com as melhores práticas modernas.

O que esta Skill Faz

Ajuda designers/desenvolvedores de frontend com:

  • Design e Desenvolvimento de Componentes - Construa componentes reutilizáveis e acessíveis
  • Sistemas de Design - Implemente tokens, padrões e documentação
  • Design Responsivo - Layouts fluidos mobile-first
  • Acessibilidade (WCAG 2.1) - Padrões de design inclusivos
  • CSS Moderno - Flexbox, Grid, custom properties
  • Otimização de Performance - Frontends rápidos e eficientes
  • Padrões de Framework - Melhores práticas para React, Vue, Svelte
  • Design para Código - Fluxos de trabalho do Figma para a produção

Por que esta Skill é Importante

Sem uma abordagem sistemática:

  • Implementações inconsistentes de componentes
  • Problemas de acessibilidade
  • Comportamento responsivo inadequado
  • Código e estilos duplicados
  • Difícil manutenção
  • Problemas de performance

Com esta skill:

  • Componentes consistentes e reutilizáveis
  • Conformidade WCAG AA por padrão
  • Design responsivo mobile-first
  • Alinhamento com o sistema de design
  • Código-fonte de fácil manutenção
  • Entrega rápida e otimizada

Princípios Fundamentais

1. Acessibilidade em Primeiro Lugar

  • WCAG 2.1 AA no mínimo
  • HTML semântico
  • Navegação por teclado
  • Suporte a leitores de tela
  • Gerenciamento de foco
  • Contraste de cores

2. Responsivo Mobile-First

  • Comece pelo mobile (320px)
  • Melhoria progressiva
  • Tipografia fluida
  • Layouts flexíveis
  • Alvos táteis

3. Performance por Padrão

  • CSS/JS mínimos
  • Carregamento preguiçoso (lazy loading)
  • Imagens otimizadas
  • CSS crítico
  • Tree shaking

4. Orientado a Componentes

  • Metodologia de design atômico
  • Componentes reutilizáveis
  • Customização baseada em props
  • Composição em vez de herança

5. Alinhado ao Sistema de Design

  • Tokens de design
  • Espaçamento consistente
  • Escala tipográfica
  • Paleta de cores
  • Biblioteca de componentes

Padrões de Componentes

Componente Botão

Padrão de botão acessível e flexível:

// Exemplo React
interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  loading?: boolean;
  children: React.ReactNode;
  onClick?: () => void;
}

export const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  size = 'md',
  disabled = false,
  loading = false,
  children,
  onClick,
  ...props
}) => {
  return (
    <button
      className={`btn btn--${variant} btn--${size}`}
      disabled={disabled || loading}
      onClick={onClick}
      aria-busy={loading}
      {...props}
    >
      {loading ? <Spinner /> : children}
    </button>
  );
};

CSS (com tokens de design):

.btn {
  /* Estilos base */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);

  font-family: var(--font-sans);
  font-weight: 600;
  text-decoration: none;

  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;

  transition: all 0.2s ease;

  /* Acessibilidade */
  min-height: 44px; /* Alvo tátil WCAG */

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
}

/* Variantes */
.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);

  &:hover:not(:disabled) {
    background: var(--color-primary-hover);
  }
}

.btn--secondary {
  background: var(--color-secondary);
  color: var(--color-on-secondary);
}

.btn--ghost {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid currentColor;
}

/* Tamanhos */
.btn--sm {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.btn--md {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
}

.btn--lg {
  padding: var(--space-4) var(--space-6);
  font-size: var(--text-lg);
}

Componente Cartão

Cartão flexível e acessível:

interface CardProps {
  variant?: 'elevated' | 'outlined' | 'filled';
  padding?: 'none' | 'sm' | 'md' | 'lg';
  interactive?: boolean;
  children: React.ReactNode;
}

export const Card: React.FC<CardProps> = ({
  variant = 'elevated',
  padding = 'md',
  interactive = false,
  children,
}) => {
  const Component = interactive ? 'button' : 'div';

  return (
    <Component
      className={`
        card
        card--${variant}
        card--padding-${padding}
        ${interactive ? 'card--interactive' : ''}
      `}
      {...(interactive && { role: 'button', tabIndex: 0 })}
    >
      {children}
    </Component>
  );
};

CSS:

.card {
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.card--elevated {
  box-shadow: var(--shadow-md);
}

.card--outlined {
  border: 1px solid var(--color-border);
}

.card--filled {
  background: var(--color-surface-variant);
}

.card--interactive {
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;

  &:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
  }

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }
}

.card--padding-sm { padding: var(--space-3); }
.card--padding-md { padding: var(--space-4); }
.card--padding-lg { padding: var(--space-6); }

Componente Campo de Formulário

Campo de formulário acessível:

interface InputProps {
  label: string;
  error?: string;
  hint?: string;
  required?: boolean;
  type?: 'text' | 'email' | 'password' | 'number';
}

export const Input: React.FC<InputProps> = ({
  label,
  error,
  hint,
  required = false,
  type = 'text',
  ...props
}) => {
  const id = useId();
  const hintId = `${id}-hint`;
  const errorId = `${id}-error`;

  return (
    <div className="input-wrapper">
      <label htmlFor={id} className="input-label">
        {label}
        {required && <span aria-label="obrigatório">*</span>}
      </label>

      {hint && (
        <p id={hintId} className="input-hint">
          {hint}
        </p>
      )}

      <input
        id={id}
        type={type}
        className={`input ${error ? 'input--error' : ''}`}
        aria-required={required}
        aria-invalid={!!error}
        aria-describedby={error ? errorId : hint ? hintId : undefined}
        {...props}
      />

      {error && (
        <p id={errorId} className="input-error" role="alert">
          {error}
        </p>
      )}
    </div>
  );
};

Tokens de Design

Custom Properties CSS para sistema de design:

:root {
  /* Cores - Primárias */
  --color-primary: #0066FF;
  --color-primary-hover: #0052CC;
  --color-on-primary: #FFFFFF;

  /* Cores - Superfície */
  --color-surface: #FFFFFF;
  --color-surface-variant: #F5F5F5;
  --color-on-surface: #1A1A1A;

  /* Cores - Bordas */
  --color-border: #E0E0E0;
  --color-border-hover: #BDBDBD;

  /* Cores - Semânticas */
  --color-error: #D32F2F;
  --color-success: #388E3C;
  --color-warning: #F57C00;
  --color-info: #1976D2;

  /* Escala de Espaçamento (base 8px) */
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-8: 3rem;     /* 48px */
  --space-10: 4rem;    /* 64px */

  /* Escala Tipográfica */
  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */
  --text-4xl: 2.25rem;   /* 36px */

  /* Famílias de Fonte */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "SF Mono", Monaco, "Cascadia Code", monospace;

  /* Alturas de Linha */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* Raio de Borda */
  --radius-sm: 0.25rem;  /* 4px */
  --radius-md: 0.5rem;   /* 8px */
  --radius-lg: 1rem;     /* 16px */
  --radius-full: 9999px;

  /* Sombras */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);

  /* Anel de Foco */
  --color-focus: #0066FF;

  /* Transições */
  --transition-fast: 150ms ease;
  --transition-base: 200ms ease;
  --transition-slow: 300ms ease;
}

/* Modo escuro */
@media (prefers-color-scheme: dark) {
  :root {
    --color-surface: #1A1A1A;
    --color-surface-variant: #2A2A2A;
    --color-on-surface: #FFFFFF;
    --color-border: #3A3A3A;
  }
}

Padrões de Design Responsivo

Breakpoints Mobile-First

/* Abordagem mobile-first */
.container {
  padding: var(--space-4);

  /* Tablet: 768px e acima */
  @media (min-width: 48rem) {
    padding: var(--space-6);
  }

  /* Desktop: 1024px e acima */
  @media (min-width: 64rem) {
    padding: var(--space-8);
    max-width: 1200px;
    margin: 0 auto;
  }
}

Tipografia Fluida

/* Tipografia responsiva */
h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: var(--leading-tight);
}

h2 {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
}

p {
  font-size: clamp(1rem, 2vw, 1.125rem);
  line-height: var(--leading-normal);
}

Layouts Grid

/* Grid responsivo */
.grid {
  display: grid;
  gap: var(--space-4);

  /* Colunas auto-ajustáveis (mín 280px) */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* Sistema de grid de 12 colunas */
.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-4);
}

.col-span-4 {
  grid-column: span 4;
}

/* Empilhar no mobile */
@media (max-width: 48rem) {
  .col-span-4 {
    grid-column: span 12;
  }
}

Padrões de Acessibilidade

Skip Links

export const SkipLink = () => (
  <a href="#main-content" className="skip-link">
    Pular para o conteúdo principal
  </a>
);
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--color-primary);
  color: var(--color-on-primary);
  padding: var(--space-2) var(--space-4);
  text-decoration: none;
  z-index: 100;

  &:focus {
    top: 0;
  }
}

Gerenciamento de Foco

// Modal com armadilha de foco
export const Modal = ({ isOpen, onClose, children }) => {
  const modalRef = useRef(null);

  useEffect(() => {
    if (isOpen) {
      // Salvar elemento atualmente focado
      const previouslyFocused = document.activeElement;

      // Focar primeiro elemento focalizável no modal
      const firstFocusable = modalRef.current?.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      firstFocusable?.focus();

      // Restaurar foco ao fechar
      return () => previouslyFocused?.focus();
    }
  }, [isOpen]);

  if (!isOpen) return null;

  return (
    <div
      ref={modalRef}
      role="dialog"
      aria-modal="true"
      className="modal-overlay"
    >
      <div className="modal">
        {children}
      </div>
    </div>
  );
};

ARIA Labels

// Botão de ícone com rótulo acessível
export const IconButton = ({ icon, label, ...props }) => (
  <button
    aria-label={label}
    className="icon-button"
    {...props}
  >
    <span aria-hidden="true">{icon}</span>
  </button>
);

// Estado de carregamento
export const LoadingButton = ({ loading, children, ...props }) => (
  <button
    aria-busy={loading}
    aria-live="polite"
    disabled={loading}
    {...props}
  >
    {loading ? 'Carregando...' : children}
  </button>
);

Otimização de Performance

CSS Crítico

<!-- CSS crítico inline -->
<style>
  /* Estilos acima da dobra */
  body { margin: 0; font-family: var(--font-sans); }
  .header { /* estilos críticos do cabeçalho */ }
  .hero { /* estilos críticos do hero */ }
</style>

<!-- Carregar folha de estilo completa de forma assíncrona -->
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">

Carregamento Preguiçoso de Imagens

export const LazyImage = ({ src, alt, ...props }) => (
  <img
    src={src}
    alt={alt}
    loading="lazy"
    decoding="async"
    {...props}
  />
);

Code Splitting

// Carregamento preguiçoso no React
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Dashboard />
    </Suspense>
  );
}

Técnicas CSS Modernas

Container Queries

.card {
  container-type: inline-size;
}

.card-content {
  display: flex;
  flex-direction: column;

  /* Alternar para layout de linha quando container > 400px */
  @container (min-width: 400px) {
    flex-direction: row;
  }
}

Auto-Fit do CSS Grid

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--space-4);
}

Custom Properties para Temas

/* Tema claro (padrão) */
:root {
  --bg: #ffffff;
  --text: #000000;
}

/* Tema escuro */
[data-theme="dark"] {
  --bg: #000000;
  --text: #ffffff;
}

body {
  background: var(--bg);
  color: var(--text);
}

Estrutura da Biblioteca de Componentes

src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.css
│   │   ├── Button.test.tsx
│   │   └── Button.stories.tsx
│   ├── Card/
│   ├── Input/
│   └── index.ts
├── tokens/
│   ├── colors.css
│   ├── spacing.css
│   ├── typography.css
│   └── index.css
├── utils/
│   ├── a11y.ts
│   └── responsive.ts
└── index.ts

Usando Esta Skill

Gerar Componente

./scripts/generate_component.sh Button

Cria componente com:

  • Arquivo TypeScript/JSX
  • Módulo CSS
  • Arquivo de teste
  • História do Storybook
  • Verificações de acessibilidade

Configuração do Sistema de Design

./scripts/setup_design_system.sh

Cria:

  • Tokens de design (Custom Properties CSS)
  • Estilos base
  • Templates de componentes
  • Estrutura de documentação

Auditoria de Acessibilidade

./scripts/audit_accessibility.sh

Verifica:

  • Taxas de contraste de cores
  • Navegação por teclado
  • Atributos ARIA
  • HTML semântico
  • Gerenciamento de foco

Melhores Práticas

Design de Componentes

✅ FAÇA:

  • Use HTML semântico
  • Torne componentes acessíveis por teclado
  • Forneça rótulos ARIA
  • Suporte modos claro e escuro

...

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

Samueladewole/claude-skills

Create API handoff documentation for frontend developers. Use when backend work is complete and needs to be documented for frontend integration, or user says 'create handoff', 'document API', 'frontend handoff', or 'API documentation'.

Samueladewole/claude-skills

Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling

Samueladewole/claude-skills

Document frontend data needs for backend developers. Use when frontend needs to communicate API requirements to backend, or user says 'backend requirements', 'what data do I need', 'API requirements', or is describing data needs for a UI.

Samueladewole/claude-skills

Master Next.js 14+ App Router with Server Components, streaming, parallel routes, and advanced data fetching. Use when building Next.js applications, implementing SSR/SSG, or optimizing React Server Components.

Samueladewole/claude-skills

Analyze a short-form video (TikTok, Instagram Reel, YouTube Short, or any MP4) to extract its full transcript, understand why it performed, and generate concrete repurposing ideas. Use this skill whenever the user asks to: analyze a video, understand why something went viral, reverse-engineer a creator's content, extract a transcript from a video, figure out what makes a video perform, or get repurposing ideas from a video. Also trigger when the user says things like "why did this perform", "what's the hook here", "can I repurpose this", "analyze this TikTok/Reel", or drops a video file path or URL.

Habilidades Relacionadas