npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@subg-dev/subg-components

v1.4.1

Published

Componentes reutilizáveis da SUBG - Sistema de Sidebar e Breadcrumb

Readme

@subg-dev/subg-components

Componentes de Sidebar e Breadcrumb reutilizáveis baseados em shadcn/ui para Tailwind CSS v4.


📋 Índice


✨ Visão Geral

Esta biblioteca fornece componentes completos e prontos para uso em aplicações React com Tailwind v4.

🎯 Componentes Principais

  • AppSidebar - Sidebar completa e responsiva com suporte a colapso e navegação hierárquica
  • NavUser - Componente de usuário com avatar, dropdown e ações (Perfil, Configurações, Sair)
  • SidebarFooter - Footer automático com informações de versão, build e usuário
  • NavMain - Navegação vertical integrada com React Router
  • PageBreadcrumb - Breadcrumbs automáticos baseados na URL
  • Badge - Componente de badges com 4 variantes (default, secondary, destructive, outline)

🔧 Utilitários

  • Sistema de Versão - Funções para obter metadata de build (versão, commit SHA, build number, ambiente)
  • Componentes UI base - Todos os primitivos do shadcn/ui necessários (Sidebar, Button, Avatar, Tooltip, etc.)

⚡ Features

  • Footer configurável - 3 modos: com usuário e versão, apenas versão, ou totalmente customizado
  • Navegação hierárquica - Suporta menu com múltiplos níveis de subitens
  • Responsivo - Adapta-se automaticamente para mobile com drawer
  • Modo colapsado - Sidebar pode ser minimizada para ícones
  • Dark mode ready - Variáveis CSS preparadas para tema escuro
  • Tooltips informativos - Build info detalhado com badges de ambiente

Diferencial: Todos os componentes são autônomos e funcionam com Tailwind CSS v4 sem precisar do shadcn/ui instalado.


🚀 Instalação (Copy-Paste)

Seguindo o modelo do shadcn/ui, você copia os componentes diretamente para o seu projeto ao invés de instalar via NPM.

1️⃣ Instalar dependências base

pnpm add @radix-ui/react-avatar @radix-ui/react-collapsible \
         @radix-ui/react-dropdown-menu @radix-ui/react-separator \
         @radix-ui/react-slot @radix-ui/react-tooltip \
         @radix-ui/react-dialog \
         class-variance-authority clsx tailwind-merge \
         lucide-react react-router-dom

2️⃣ Copiar os arquivos de componentes

Copie os seguintes arquivos do repositório para o seu projeto:

📁 Seu Projeto
└── src/
    ├── components/
    │   └── navigation/
    │       ├── app-sidebar.tsx     ← Sidebar principal
    │       ├── nav-main.tsx        ← Menu de navegação
    │       ├── nav-user.tsx        ← Componente de usuário
    │       ├── sidebar-footer.tsx  ← Footer com versão
    │       └── page-breadcrumb.tsx ← Breadcrumbs
    │
    ├── ui/                         ← Componentes base shadcn/ui
    │   ├── sidebar.tsx
    │   ├── separator.tsx
    │   ├── button.tsx
    │   ├── badge.tsx               ← Badges
    │   ├── avatar.tsx
    │   ├── collapsible.tsx
    │   ├── dropdown-menu.tsx
    │   ├── tooltip.tsx
    │   ├── breadcrumb.tsx
    │   ├── sheet.tsx
    │   ├── skeleton.tsx
    │   └── input.tsx
    │
    ├── lib/
    │   └── versao.ts               ← Funções de versão/build
    │
    ├── utils/
    │   └── cn.ts                   ← Utilitário de classes
    │
    └── hooks/
        └── use-mobile.ts           ← Hook de detecção mobile

Link do repositório: github.com/SUBG-RioSaude/subg-components

Você pode clonar o repo e copiar a pasta src/ completa, ou copiar manualmente os arquivos necessários.


🎨 Configuração do Tailwind CSS v4

1️⃣ Adicionar variáveis CSS da Sidebar

No seu arquivo CSS principal (ex: src/index.css ou src/app.css), adicione:

@import 'tailwindcss';

@theme inline {
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  /* Mapeamento de cores para Tailwind */
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-ring: var(--sidebar-ring);
}

:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);

  /* Variáveis da Sidebar - Light Mode */
  --sidebar: oklch(0.404 0.017 264.376);           /* Fundo cinza/azulado */
  --sidebar-foreground: oklch(1 0 0);              /* Texto branco */
  --sidebar-primary: oklch(0.709 0.142 213.68);    /* #43B9EB - Cor primária */
  --sidebar-primary-foreground: oklch(1 0 0);      /* Texto branco */
  --sidebar-accent: oklch(1 0 0 / 0.1);            /* Hover transparente */
  --sidebar-accent-foreground: oklch(0.709 0.142 213.68); /* #43B9EB */
  --sidebar-border: oklch(0.5 0 0);                /* Borda escura */
  --sidebar-ring: oklch(0.709 0.142 213.68);       /* Anel de foco #43B9EB */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);

  /* Variáveis da Sidebar - Dark Mode */
  --sidebar: oklch(0.404 0.017 264.376);           /* Mantém fundo no dark */
  --sidebar-foreground: oklch(1 0 0);
  --sidebar-primary: oklch(0.709 0.142 213.68);
  --sidebar-primary-foreground: oklch(1 0 0);
  --sidebar-accent: oklch(1 0 0 / 0.1);
  --sidebar-accent-foreground: oklch(0.709 0.142 213.68);
  --sidebar-border: oklch(0.5 0 0);
  --sidebar-ring: oklch(0.709 0.142 213.68);
}

@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
}

2️⃣ Configurar tailwind.config.ts (opcional)

O Tailwind v4 não requer plugins para variáveis CSS customizadas. O arquivo pode ficar simples:

export default {
  content: ["./src/**/*.{ts,tsx}"],
  theme: {
    extend: {},
  },
}

📖 Exemplos de Uso

🟢 Exemplo 1: Básico (Mínimo)

Sidebar simples sem footer, apenas navegação essencial.

import { SidebarProvider, SidebarInset } from '@/ui/sidebar'
import { AppSidebar } from '@/components/navigation/app-sidebar'
import { Home, FileText } from 'lucide-react'

export function BasicLayout({ children }: { children: React.ReactNode }) {
  return (
    <SidebarProvider>
      <AppSidebar
        navItems={[
          { title: 'Início', url: '/', icon: Home },
          { title: 'Documentos', url: '/docs', icon: FileText },
        ]}
        logoConfig={{
          mainLogoUrl: '/logo.png',
          mainLogoAlt: 'Logo',
        }}
      />

      <SidebarInset>
        <main className="p-6">
          {children}
        </main>
      </SidebarInset>
    </SidebarProvider>
  )
}

🟡 Exemplo 2: Intermediário

Sidebar com navegação hierárquica, breadcrumbs e footer com versão.

import { SidebarProvider, SidebarInset, SidebarTrigger } from '@/ui/sidebar'
import { AppSidebar } from '@/components/navigation/app-sidebar'
import { PageBreadcrumb } from '@/components/navigation/page-breadcrumb'
import { Home, Settings, Users, FileText } from 'lucide-react'
import { useNavigate } from 'react-router-dom'

export function IntermediateLayout({ children }: { children: React.ReactNode }) {
  const navigate = useNavigate()

  const navItems = [
    { title: 'Início', url: '/', icon: Home },
    {
      title: 'Configurações',
      url: '/settings',
      icon: Settings,
      items: [
        { title: 'Perfil', url: '/settings/profile' },
        { title: 'Preferências', url: '/settings/preferences' },
      ],
    },
    { title: 'Usuários', url: '/users', icon: Users },
    { title: 'Documentos', url: '/docs', icon: FileText },
  ]

  return (
    <SidebarProvider>
      <AppSidebar
        navItems={navItems}
        logoConfig={{
          mainLogoUrl: '/logo.png',
          mainLogoAlt: 'Minha Logo',
          badgeText: 'BETA',
          logoLink: '/dashboard',
        }}
        footerConfig={{
          showVersion: true,
          developerText: 'Desenvolvido com ❤️ pela equipe',
        }}
      />

      <SidebarInset>
        {/* Header com Breadcrumb e Toggle */}
        <header className="sticky top-0 z-10 flex h-16 items-center gap-2 border-b bg-white px-4">
          <SidebarTrigger />
          <PageBreadcrumb
            labelMap={{
              'settings': 'Configurações',
              'users': 'Usuários',
              'docs': 'Documentos',
              'profile': 'Perfil',
              'preferences': 'Preferências',
            }}
          />
        </header>

        {/* Conteúdo Principal */}
        <main className="flex-1 overflow-auto p-6">
          {children}
        </main>
      </SidebarInset>
    </SidebarProvider>
  )
}

🔴 Exemplo 3: Completo (Todas as Features)

Sidebar com todas as props, usuário autenticado, versão, badges e navegação completa.

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
  SidebarProvider,
  SidebarInset,
  SidebarTrigger
} from '@/ui/sidebar'
import { AppSidebar } from '@/components/navigation/app-sidebar'
import { PageBreadcrumb } from '@/components/navigation/page-breadcrumb'
import { Badge } from '@/ui/badge'
import {
  Home,
  Settings,
  Users,
  FileText,
  BarChart3,
  Package,
  CreditCard,
  Bell,
  HelpCircle,
} from 'lucide-react'

export function CompleteLayout({ children }: { children: React.ReactNode }) {
  const navigate = useNavigate()
  const [user] = useState({
    name: 'Matheus Migliani',
    email: '[email protected]',
    avatar: '/avatars/matheus.jpg',
  })

  // Navegação completa com hierarquia
  const navItems = [
    {
      title: 'Dashboard',
      url: '/',
      icon: Home
    },
    {
      title: 'Relatórios',
      url: '/reports',
      icon: BarChart3,
      items: [
        { title: 'Vendas', url: '/reports/sales' },
        { title: 'Financeiro', url: '/reports/financial' },
        { title: 'Analytics', url: '/reports/analytics' },
      ],
    },
    {
      title: 'Produtos',
      url: '/products',
      icon: Package,
      items: [
        { title: 'Catálogo', url: '/products/catalog' },
        { title: 'Estoque', url: '/products/inventory' },
        { title: 'Fornecedores', url: '/products/suppliers' },
      ],
    },
    {
      title: 'Clientes',
      url: '/customers',
      icon: Users,
      items: [
        { title: 'Lista', url: '/customers/list' },
        { title: 'Novo Cliente', url: '/customers/new' },
      ],
    },
    {
      title: 'Financeiro',
      url: '/finance',
      icon: CreditCard,
      items: [
        { title: 'Faturas', url: '/finance/invoices' },
        { title: 'Pagamentos', url: '/finance/payments' },
        { title: 'Cobranças', url: '/finance/billing' },
      ],
    },
    {
      title: 'Documentos',
      url: '/docs',
      icon: FileText
    },
    {
      title: 'Configurações',
      url: '/settings',
      icon: Settings,
      items: [
        { title: 'Perfil', url: '/settings/profile' },
        { title: 'Conta', url: '/settings/account' },
        { title: 'Notificações', url: '/settings/notifications' },
        { title: 'Segurança', url: '/settings/security' },
        { title: 'Integrações', url: '/settings/integrations' },
      ],
    },
  ]

  // Handlers de ações do usuário
  const handleLogout = () => {
    console.log('Logging out...')
    // Lógica de logout
    navigate('/login')
  }

  const handleProfile = () => {
    navigate('/settings/profile')
  }

  const handleSettings = () => {
    navigate('/settings')
  }

  return (
    <SidebarProvider defaultOpen={true}>
      <AppSidebar
        // Navegação
        navItems={navItems}

        // Logo com badge
        logoConfig={{
          mainLogoUrl: '/logo-prefeitura.png',
          mainLogoAlt: 'Logo Prefeitura do Rio',
          badgeText: 'CAC',
          badgeLogoUrl: '/logo-cac.png',
          logoLink: '/dashboard',
        }}

        // Footer completo com usuário e versão
        footerConfig={{
          userConfig: {
            user,
            onLogout: handleLogout,
            onProfile: handleProfile,
            onSettings: handleSettings,
          },
          showVersion: true,
          developerText: 'Desenvolvido pela SUBG',
        }}

        // Props adicionais da Sidebar (shadcn)
        variant="sidebar"
        collapsible="icon"
        className="border-r"
      />

      <SidebarInset>
        {/* Header com todos os recursos */}
        <header className="sticky top-0 z-10 flex h-16 items-center justify-between gap-4 border-b bg-white px-4 shadow-sm">
          <div className="flex items-center gap-2">
            {/* Toggle da sidebar */}
            <SidebarTrigger />

            {/* Breadcrumb */}
            <PageBreadcrumb
              labelMap={{
                'reports': 'Relatórios',
                'sales': 'Vendas',
                'financial': 'Financeiro',
                'analytics': 'Analytics',
                'products': 'Produtos',
                'catalog': 'Catálogo',
                'inventory': 'Estoque',
                'suppliers': 'Fornecedores',
                'customers': 'Clientes',
                'list': 'Lista',
                'new': 'Novo',
                'finance': 'Financeiro',
                'invoices': 'Faturas',
                'payments': 'Pagamentos',
                'billing': 'Cobranças',
                'docs': 'Documentos',
                'settings': 'Configurações',
                'profile': 'Perfil',
                'account': 'Conta',
                'notifications': 'Notificações',
                'security': 'Segurança',
                'integrations': 'Integrações',
              }}
            />
          </div>

          {/* Actions no header */}
          <div className="flex items-center gap-2">
            <Badge variant="outline" className="hidden md:flex">
              Ambiente: Produção
            </Badge>

            <button className="relative p-2 hover:bg-gray-100 rounded-md">
              <Bell className="h-5 w-5" />
              <span className="absolute top-1 right-1 h-2 w-2 bg-red-500 rounded-full" />
            </button>

            <button className="p-2 hover:bg-gray-100 rounded-md">
              <HelpCircle className="h-5 w-5" />
            </button>
          </div>
        </header>

        {/* Conteúdo Principal */}
        <main className="flex-1 overflow-auto p-6 bg-gray-50">
          {children}
        </main>
      </SidebarInset>
    </SidebarProvider>
  )
}

🎨 Customização

Alterar cores da Sidebar

Edite as variáveis CSS no seu index.css:

:root {
  /* Exemplo: Sidebar verde */
  --sidebar: oklch(0.4 0.15 150);              /* Fundo verde */
  --sidebar-primary: oklch(0.6 0.2 150);       /* Verde mais claro */
  --sidebar-accent-foreground: oklch(0.6 0.2 150);
}

Personalizar a Logo

<AppSidebar
  logoConfig={{
    mainLogoUrl: '/custom-logo.svg',
    mainLogoAlt: 'Logo Customizada',
    badgeText: 'BETA',            // Texto da badge
    badgeLogoUrl: '/badge.png',    // Logo da badge (opcional)
    logoLink: '/home',             // Link ao clicar
  }}
  navItems={navItems}
/>

Footer com Usuário e Versão

A sidebar agora suporta um footer completo com informações de usuário e versão:

Opção 1: Footer automático com footerConfig

<AppSidebar
  navItems={navItems}
  logoConfig={logoConfig}
  footerConfig={{
    userConfig: {
      user: {
        name: 'João Silva',
        email: '[email protected]',
        avatar: '/avatar.jpg'
      },
      onLogout: () => handleLogout(),
      onProfile: () => navigate('/profile'),
      onSettings: () => navigate('/settings'),
    },
    showVersion: true,  // Mostra versão e build info
    developerText: 'Desenvolvido pelo time de TI 2025'
  }}
/>

Opção 2: Apenas versão, sem usuário

<AppSidebar
  navItems={navItems}
  logoConfig={logoConfig}
  footerConfig={{
    showVersion: true
  }}
/>

Opção 3: Footer totalmente customizado

<AppSidebar
  navItems={navItems}
  logoConfig={logoConfig}
  footerContent={
    <div className="p-4 space-y-2">
      <button className="w-full btn-primary">Sair</button>
      <p className="text-xs text-center">v1.0.0</p>
    </div>
  }
/>

Configurar Variáveis de Versão

O footer com showVersion: true exibe informações de build obtidas de variáveis de ambiente.

1. Crie um arquivo .env na raiz do projeto:

VITE_APP_VERSION=1.0.0
VITE_COMMIT_SHA=abc1234
VITE_BUILD_NUMBER=42
VITE_BUILD_TIMESTAMP=2025-10-21T12:00:00Z
VITE_AMBIENTE=production

2. Configure no CI/CD (exemplo GitHub Actions):

- name: Build
  env:
    VITE_APP_VERSION: ${{ github.ref_name }}
    VITE_COMMIT_SHA: ${{ github.sha }}
    VITE_BUILD_NUMBER: ${{ github.run_number }}
    VITE_BUILD_TIMESTAMP: ${{ github.event.head_commit.timestamp }}
    VITE_AMBIENTE: production
  run: pnpm build

Se as variáveis não forem definidas, o sistema usa valores padrão (versão 1.0.0, build "local", etc.).


📚 API de Componentes

AppSidebar

| Prop | Tipo | Descrição | |------|------|-----------| | navItems | NavItem[] | Lista de itens de navegação (requerido) | | logoConfig | LogoConfig | Configuração da logo (requerido) | | footerConfig | SidebarFooterProps | Configuração automática do footer com versão e usuário (opcional) | | footerContent | ReactNode | Conteúdo totalmente customizado do footer (opcional, alternativa ao footerConfig) |

NavItem

interface NavItem {
  title: string
  url: string
  icon: LucideIcon
  items?: { title: string; url: string }[]  // Subitens opcionais
}

LogoConfig

interface LogoConfig {
  mainLogoUrl: string         // URL da logo principal
  mainLogoAlt?: string        // Texto alternativo
  badgeLogoUrl?: string       // URL da logo da badge
  badgeText?: string          // Texto da badge (ex: "CAC")
  logoLink?: string           // Link ao clicar na logo
}

SidebarFooterProps

interface SidebarFooterProps {
  userConfig?: {
    user?: {
      name: string
      email: string
      avatar?: string
    }
    onLogout?: () => void
    onProfile?: () => void
    onSettings?: () => void
  }
  showVersion?: boolean       // Padrão: true
  developerText?: string      // Texto customizado do desenvolvedor
}

NavUser

Componente standalone para exibir usuário com dropdown de ações.

| Prop | Tipo | Descrição | |------|------|-----------| | user | { name, email, avatar? } | Dados do usuário (opcional, mostra placeholder se omitido) | | onLogout | () => void | Callback ao clicar em "Sair" (opcional) | | onProfile | () => void | Callback ao clicar em "Perfil" (opcional) | | onSettings | () => void | Callback ao clicar em "Configurações" (opcional) |

Badge

Componente de badge baseado em shadcn/ui.

| Prop | Tipo | Valores | Descrição | |------|------|---------|-----------| | variant | string | default, secondary, destructive, outline | Variante visual do badge |

Exemplo:

<Badge variant="default">Novo</Badge>
<Badge variant="destructive">Erro</Badge>

PageBreadcrumb

| Prop | Tipo | Descrição | |------|------|-----------| | labelMap | Record<string, string> | Mapeia segmentos da URL para labels legíveis (opcional) | | items | BreadcrumbItemType[] | Lista manual de breadcrumbs (opcional) |

SidebarProvider

| Prop | Tipo | Descrição | |------|------|-----------| | defaultOpen | boolean | Estado inicial da sidebar (padrão: true) | | open | boolean | Controle externo do estado (opcional) | | onOpenChange | (open: boolean) => void | Callback ao mudar estado (opcional) |

Funções de Versão

// Obtém versão da aplicação
obterVersaoApp(): string

// Obtém ano atual
obterAnoAtual(): number

// Obtém metadata completa
obterMetadataVersao(): MetadataVersao

interface MetadataVersao {
  versao: string
  buildNumber: string
  commitSha: string
  buildTimestamp: string
  ambiente: 'development' | 'staging' | 'production'
}

🏗️ Desenvolvimento Local

Se você quiser contribuir ou modificar a biblioteca:

# Clonar o repositório
git clone https://github.com/SUBG-RioSaude/subg-components.git
cd subg-components

# Instalar dependências
pnpm install

# Build
pnpm build

# Watch mode (desenvolvimento)
pnpm dev

📦 Distribuição via NPM (Legado)

⚠️ Nota: A instalação via NPM não é mais recomendada devido a incompatibilidades com Tailwind v4. Use o método copy-paste descrito acima.

Se ainda assim quiser instalar via NPM:

pnpm add @subg-dev/subg-components

Você precisará importar o CSS manualmente:

@import '@subg-dev/subg-components/styles.css';

📄 Licença

MIT License · SUBG - Subsecretaria de Gestão


🤝 Contribuindo

Contribuições são bem-vindas! Abra uma issue ou pull request no repositório GitHub.


Desenvolvido com ❤️ pela equipe SUBG