Frontend

TAILADMIN VUE.JS - INTEGRAÇÃO E DESIGN SYSTEM

TAILADMIN VUE.JS - INTEGRAÇÃO E DESIGN SYSTEM

VISÃO GERAL

O projeto AgrSis utiliza TailAdmin Vue.js como template base para os frontends (produtor e fornecedor), garantindo uma interface moderna, responsiva e consistente.

Site Oficial: https://tailadmin.com/Versão: Vue.js (Nuxt 3 compatible) Licença: (verificar licença adquirida)


1. CARACTERÍSTICAS DO TAILADMIN

Componentes Principais:

  • Dashboard completo - Gráficos, estatísticas e cards
  • Tabelas de dados - Com filtros, paginação e ordenação
  • Formulários - Inputs, selects, datepickers, validação
  • Autenticação - Telas de login, registro, recuperação de senha
  • Navegação - Sidebar, topbar, breadcrumbs
  • Modais e Alerts - Componentes de feedback
  • Cards e Widgets - Elementos reutilizáveis
  • Gráficos - Chart.js integrado
  • Dark Mode - Tema claro/escuro

Tecnologias Utilizadas:

  • Vue 3 com Composition API
  • Nuxt 3 para SSR/SSG
  • Tailwind CSS para estilização
  • TypeScript para type safety
  • Pinia para gerenciamento de estado
  • VueUse para composables utilitários

2. DESIGN SYSTEM AGRSIS

Cores Primárias

// tailwind.config.js - Cores AgrSis
module.exports = {
  theme: {
    extend: {
      colors: {
        // Cores principais AgrSis
        agrsis: {
          primary: {
            50: '#e6f7e6',
            100: '#b3e6b3',
            200: '#80d480',
            300: '#4dc24d',
            400: '#1ab01a',
            500: '#00a000',  // Verde principal
            600: '#008000',
            700: '#006600',
            800: '#004d00',
            900: '#003300',
          },
          secondary: {
            50: '#fff4e6',
            100: '#ffe0b3',
            200: '#ffcc80',
            300: '#ffb84d',
            400: '#ffa41a',
            500: '#ff9000',  // Laranja secundário
            600: '#cc7300',
            700: '#995600',
            800: '#663a00',
            900: '#331d00',
          },
          neutral: {
            50: '#f8f9fa',
            100: '#e9ecef',
            200: '#dee2e6',
            300: '#ced4da',
            400: '#adb5bd',
            500: '#6c757d',  // Cinza neutro
            600: '#495057',
            700: '#343a40',
            800: '#212529',
            900: '#0d1117',
          },
          success: '#28a745',
          warning: '#ffc107',
          error: '#dc3545',
          info: '#17a2b8',
        }
      }
    }
  }
}

Tipografia

// Fontes do sistema
fontFamily: {
  sans: ['Inter', 'Roboto', 'Helvetica', 'Arial', 'sans-serif'],
  mono: ['Fira Code', 'Courier New', 'monospace'],
}

Espaçamentos e Breakpoints

// Seguir padrões Tailwind com algumas customizações
spacing: {
  // ... padrão Tailwind
  '18': '4.5rem',
  '88': '22rem',
}

screens: {
  'xs': '480px',
  'sm': '640px',
  'md': '768px',
  'lg': '1024px',
  'xl': '1280px',
  '2xl': '1536px',
}

3. ESTRUTURA DE PASTAS

Frontend Produtor

frontend-produtor/
├── assets/
│   ├── css/
│   │   └── tailadmin.css       # Estilos customizados TailAdmin
│   └── images/
│       └── agrsis-logo.svg     # Logo AgrSis
├── components/
│   ├── tailadmin/              # Componentes TailAdmin base
│   │   ├── Dashboard/
│   │   ├── Forms/
│   │   ├── Tables/
│   │   ├── Navigation/
│   │   └── UI/
│   ├── agrsis/                 # Componentes customizados AgrSis
│   │   ├── PedidoCotacao/
│   │   ├── ListagemProdutos/
│   │   └── HistoricoPedidos/
│   └── shared/                 # Componentes compartilhados
├── composables/
│   └── useTailAdmin.ts         # Composable para TailAdmin
├── layouts/
│   ├── dashboard.vue           # Layout principal com sidebar TailAdmin
│   └── auth.vue                # Layout de autenticação
├── pages/
│   ├── index.vue
│   ├── pedidos/
│   └── perfil/
├── plugins/
│   └── tailadmin.client.ts     # Plugin TailAdmin
├── stores/
│   ├── theme.ts                # Store para tema (dark/light)
│   └── sidebar.ts              # Store para estado do sidebar
└── tailwind.config.js          # Configuração com cores AgrSis

Frontend Fornecedor

frontend-fornecedor/
├── (estrutura similar ao frontend-produtor)
└── components/
    └── agrsis/
        ├── ListagemLicitacoes/
        ├── EnvioPropostas/
        └── HistoricoVendas/

4. CONFIGURAÇÃO INICIAL

4.1. Instalação do TailAdmin

# Acessar pasta do frontend
cd frontend-produtor # ou frontend-fornecedor

# Instalar dependências
npm install

# Instalar dependências específicas TailAdmin (se necessário)
npm install @headlessui/vue @heroicons/vue apexcharts vue-apexcharts

4.2. Configuração do Tailwind

// tailwind.config.js
import tailadminPreset from './tailadmin.preset'

export default {
  presets: [tailadminPreset],
  content: [
    './components/**/*.{js,vue,ts}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './app.vue',
  ],
  theme: {
    extend: {
      colors: {
        // Cores AgrSis (conforme seção 2)
      }
    }
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
  ],
}

4.3. Configuração Nuxt

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxtjs/tailwindcss',
    '@pinia/nuxt',
    '@vueuse/nuxt',
  ],

  tailwindcss: {
    cssPath: '~/assets/css/tailadmin.css',
    configPath: 'tailwind.config.js',
  },

  app: {
    head: {
      title: 'AgrSis - Plataforma de Licitação Eletrônica',
      meta: [
        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
        { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap' },
      ],
    },
  },
})

5. COMPONENTES CUSTOMIZADOS AGRSIS

5.1. Button Component

<!-- components/agrsis/UI/Button.vue -->
<template>
  <button
    :class="buttonClasses"
    :disabled="disabled || loading"
    @click="$emit('click', $event)"
  >
    <span v-if="loading" class="mr-2">
      <IconSpinner class="animate-spin" />
    </span>
    <slot />
  </button>
</template>

<script setup lang="ts">
interface Props {
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
  disabled?: boolean
  loading?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'primary',
  size: 'md',
  disabled: false,
  loading: false,
})

const buttonClasses = computed(() => {
  const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2'

  const variants = {
    primary: 'bg-agrsis-primary-500 text-white hover:bg-agrsis-primary-600 focus:ring-agrsis-primary-500',
    secondary: 'bg-agrsis-secondary-500 text-white hover:bg-agrsis-secondary-600 focus:ring-agrsis-secondary-500',
    outline: 'border-2 border-agrsis-primary-500 text-agrsis-primary-500 hover:bg-agrsis-primary-50',
    ghost: 'text-agrsis-neutral-700 hover:bg-agrsis-neutral-100',
  }

  const sizes = {
    sm: 'px-3 py-1.5 text-sm',
    md: 'px-4 py-2 text-base',
    lg: 'px-6 py-3 text-lg',
  }

  const disabled = (props.disabled || props.loading) ? 'opacity-50 cursor-not-allowed' : ''

  return `${base} ${variants[props.variant]} ${sizes[props.size]} ${disabled}`
})
</script>

5.2. Card Component

<!-- components/agrsis/UI/Card.vue -->
<template>
  <div :class="cardClasses">
    <div v-if="$slots.header" class="px-6 py-4 border-b border-agrsis-neutral-200">
      <slot name="header" />
    </div>

    <div class="px-6 py-4">
      <slot />
    </div>

    <div v-if="$slots.footer" class="px-6 py-4 border-t border-agrsis-neutral-200 bg-agrsis-neutral-50">
      <slot name="footer" />
    </div>
  </div>
</template>

<script setup lang="ts">
interface Props {
  variant?: 'default' | 'bordered' | 'shadow'
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'default',
})

const cardClasses = computed(() => {
  const base = 'bg-white rounded-lg'

  const variants = {
    default: '',
    bordered: 'border border-agrsis-neutral-200',
    shadow: 'shadow-lg',
  }

  return `${base} ${variants[props.variant]}`
})
</script>

6. LAYOUTS

6.1. Dashboard Layout

<!-- layouts/dashboard.vue -->
<template>
  <div class="flex h-screen overflow-hidden">
    <!-- Sidebar -->
    <TailAdminSidebar
      :open="sidebarOpen"
      @close="sidebarOpen = false"
    />

    <!-- Main Content -->
    <div class="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
      <!-- Header -->
      <TailAdminHeader @toggle-sidebar="sidebarOpen = !sidebarOpen" />

      <!-- Main -->
      <main class="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
        <slot />
      </main>
    </div>
  </div>
</template>

<script setup lang="ts">
const sidebarOpen = ref(false)

// Auto-fechar sidebar em mobile quando route mudar
const route = useRoute()
watch(() => route.path, () => {
  if (window.innerWidth < 1024) {
    sidebarOpen.value = false
  }
})
</script>

7. TEMAS E DARK MODE

7.1. Theme Store

// stores/theme.ts
import { defineStore } from 'pinia'

export const useThemeStore = defineStore('theme', {
  state: () => ({
    isDark: false,
  }),

  actions: {
    toggleTheme() {
      this.isDark = !this.isDark
      this.applyTheme()
    },

    applyTheme() {
      if (this.isDark) {
        document.documentElement.classList.add('dark')
      } else {
        document.documentElement.classList.remove('dark')
      }

      // Salvar preferência
      localStorage.setItem('theme', this.isDark ? 'dark' : 'light')
    },

    initTheme() {
      // Carregar preferência salva ou usar preferência do sistema
      const savedTheme = localStorage.getItem('theme')
      const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches

      this.isDark = savedTheme === 'dark' || (!savedTheme && prefersDark)
      this.applyTheme()
    },
  },
})

7.2. Dark Mode Classes

/* assets/css/tailadmin.css */

/* Cores para Dark Mode */
:root {
  --agrsis-bg-primary: #ffffff;
  --agrsis-text-primary: #0d1117;
}

.dark {
  --agrsis-bg-primary: #0d1117;
  --agrsis-text-primary: #ffffff;
}

/* Aplicar em componentes */
.bg-primary {
  background-color: var(--agrsis-bg-primary);
}

.text-primary {
  color: var(--agrsis-text-primary);
}

8. INTEGRAÇÃO COM API LARAVEL

8.1. Configuração do Cliente HTTP

// plugins/api.ts
export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig()

  const api = $fetch.create({
    baseURL: config.public.apiBase,
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
    onRequest({ options }) {
      // Adicionar token de autenticação
      const token = useCookie('auth_token')
      if (token.value) {
        options.headers = {
          ...options.headers,
          Authorization: `Bearer ${token.value}`,
        }
      }
    },
    onResponseError({ response }) {
      // Tratar erros globalmente
      if (response.status === 401) {
        // Redirect para login
        navigateTo('/login')
      }
    },
  })

  return {
    provide: {
      api,
    },
  }
})

8.2. Composable para API

// composables/useApi.ts
export const useApi = () => {
  const { $api } = useNuxtApp()

  return {
    // Pedidos
    pedidos: {
      list: () => $api('/pedidos'),
      get: (id: number) => $api(`/pedidos/${id}`),
      create: (data: any) => $api('/pedidos', { method: 'POST', body: data }),
      update: (id: number, data: any) => $api(`/pedidos/${id}`, { method: 'PUT', body: data }),
      delete: (id: number) => $api(`/pedidos/${id}`, { method: 'DELETE' }),
    },

    // Produtos
    produtos: {
      list: () => $api('/produtos'),
      get: (id: number) => $api(`/produtos/${id}`),
    },

    // Autenticação
    auth: {
      login: (credentials: any) => $api('/login', { method: 'POST', body: credentials }),
      logout: () => $api('/logout', { method: 'POST' }),
      me: () => $api('/me'),
    },
  }
}

9. BOAS PRÁTICAS

9.1. Componentização

  • ✅ Criar componentes pequenos e reutilizáveis
  • ✅ Seguir convenção de nomenclatura: AgrSis[Nome]Component.vue
  • ✅ Usar Composition API com <script setup>
  • ✅ Definir Props e Emits com TypeScript

9.2. Estilização

  • ✅ Preferir classes utilitárias Tailwind
  • ✅ Criar classes customizadas apenas quando necessário
  • ✅ Manter consistência com Design System AgrSis
  • ✅ Usar variáveis CSS para temas dinâmicos

9.3. Performance

  • ✅ Lazy loading de componentes pesados
  • ✅ Otimizar imagens (WebP, lazy loading)
  • ✅ Code splitting por rota
  • ✅ Usar v-memo para listas grandes

9.4. Acessibilidade

  • ✅ Usar atributos ARIA apropriados
  • ✅ Garantir contraste adequado de cores
  • ✅ Suporte total a navegação por teclado
  • ✅ Textos alternativos em imagens

10. CHECKLIST DE INTEGRAÇÃO

Fase 1: Setup Inicial

  • Instalar TailAdmin Vue.js nos projetos frontend
  • Configurar Tailwind com cores AgrSis
  • Criar preset customizado do TailAdmin
  • Configurar layouts base (dashboard, auth)

Fase 2: Componentes Base

  • Adaptar componentes TailAdmin para Design System AgrSis
  • Criar componentes customizados AgrSis
  • Implementar sistema de temas (dark/light)
  • Configurar navegação (sidebar, header)

Fase 3: Integração API

  • Configurar cliente HTTP
  • Criar composables para API
  • Implementar autenticação com Sanctum
  • Criar stores Pinia para estado global

Fase 4: Páginas e Fluxos

  • Implementar telas de autenticação
  • Criar dashboards (produtor e fornecedor)
  • Desenvolver fluxos principais
  • Adicionar validações e feedback

Fase 5: Testes e Otimização

  • Testes de responsividade
  • Testes de acessibilidade
  • Otimização de performance
  • Documentação de componentes

11. RECURSOS E REFERÊNCIAS

Documentação Oficial:

Ferramentas Úteis:

Design:

  • Figma: (link para designs AgrSis, quando disponível)
  • Paleta de Cores: https://coolors.co (gerar variações)

Última atualização: 2025-12-05 Versão do documento: 1.0 Responsável: Claude Code AI

Copyright © 2026