mcp-tailwindcss 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,38 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
4
  import { createRequire } from 'node:module';
6
- import * as fs from 'fs';
7
- import * as path from 'path';
8
- import { fileURLToPath } from 'url';
9
- import { AstParser, } from './ast-parser.js';
10
- import { checkAndUpdate, checkForUpdates, getRepositoryStatus, scheduleUpdateCheck, ensureRepository, } from './auto-updater.js';
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
5
+ import { ensureRepository, checkForUpdates, scheduleUpdateCheck, checkPackageUpdate, schedulePackageUpdateCheck, } from './auto-updater.js';
6
+ import { registerAstTools } from './tools/ast-tools.js';
7
+ import { registerRepoTools, registerResources } from './tools/repo-tools.js';
8
+ import { registerContentTools } from './tools/content-tools.js';
13
9
  const require = createRequire(import.meta.url);
14
10
  const APP_VERSION = require('../package.json').version ?? '0.0.0';
15
- let TAILWIND_SRC_PATH = process.env.TAILWIND_SRC_PATH || '';
16
- const CATEGORY_EMOJI = {
17
- interface: '📋',
18
- type: '📝',
19
- enum: '🔢',
20
- function: '⚡',
21
- class: '🏛️',
22
- variable: '📦',
23
- namespace: '📁',
24
- 're-export': '🔗',
25
- };
26
- const CATEGORY_LABELS = {
27
- interface: 'Interfaces',
28
- type: 'Type Aliases',
29
- enum: 'Enumerations',
30
- function: 'Functions',
31
- class: 'Classes',
32
- variable: 'Variables/Constants',
33
- namespace: 'Namespaces',
34
- 're-export': 'Re-exports',
35
- };
11
+ const AUTO_UPDATE_INTERVAL = parseInt(process.env.AUTO_UPDATE_INTERVAL || '3600000', 10);
12
+ const AUTO_UPDATE_ENABLED = process.env.AUTO_UPDATE_ENABLED !== 'false';
36
13
  const mcpServer = new McpServer({
37
14
  name: 'mcp-tailwindcss',
38
15
  version: APP_VERSION,
@@ -42,3834 +19,38 @@ const mcpServer = new McpServer({
42
19
  resources: {},
43
20
  },
44
21
  });
45
- function getDirectoryTree(dirPath, prefix = '') {
46
- let result = '';
47
- const items = fs.readdirSync(dirPath, { withFileTypes: true });
48
- const dirs = items.filter((i) => i.isDirectory() && !i.name.startsWith('.'));
49
- const files = items.filter((i) => i.isFile() && (i.name.endsWith('.ts') || i.name.endsWith('.js')));
50
- for (const file of files) {
51
- result += `${prefix}├── ${file.name}\n`;
52
- }
53
- for (let i = 0; i < dirs.length; i++) {
54
- const dir = dirs[i];
55
- const isLast = i === dirs.length - 1;
56
- result += `${prefix}${isLast ? '└── ' : '├── '}${dir.name}/\n`;
57
- result += getDirectoryTree(path.join(dirPath, dir.name), prefix + (isLast ? ' ' : '│ '));
58
- }
59
- return result;
60
- }
61
- function formatProperty(prop) {
62
- if (prop.isMethod || prop.isCallSignature) {
63
- const params = prop.parameters?.join(', ') || '';
64
- return `${prop.name}(${params}): ${prop.returnType || prop.type}`;
65
- }
66
- if (prop.isIndexSignature) {
67
- return `${prop.name}: ${prop.type}`;
68
- }
69
- const optional = prop.optional ? '?' : '';
70
- const readonly = prop.readonly ? 'readonly ' : '';
71
- return `${readonly}${prop.name}${optional}: ${prop.type}`;
72
- }
73
- function formatExtractedType(type, detailed = false) {
74
- let result = `### ${CATEGORY_EMOJI[type.kind]} ${type.kind}: \`${type.name}\`\n\n`;
75
- result += `**Arquivo:** \`${type.file}\`${type.lineNumber ? ` (linha ${type.lineNumber})` : ''}\n`;
76
- result += `**Módulo:** ${type.module}\n\n`;
77
- if (type.docs) {
78
- result += `> ${type.docs}\n\n`;
79
- }
80
- result += '```typescript\n' + type.signature + '\n```\n\n';
81
- if (detailed) {
82
- if (type.typeParameters && type.typeParameters.length > 0) {
83
- result += '**Type Parameters:**\n';
84
- for (const tp of type.typeParameters) {
85
- result += `- \`${tp.name}\``;
86
- if (tp.constraint)
87
- result += ` extends \`${tp.constraint}\``;
88
- if (tp.default)
89
- result += ` = \`${tp.default}\``;
90
- result += '\n';
91
- }
92
- result += '\n';
93
- }
94
- if (type.extends && type.extends.length > 0) {
95
- result += `**Extends:** ${type.extends.map((e) => `\`${e}\``).join(', ')}\n\n`;
96
- }
97
- if (type.implements && type.implements.length > 0) {
98
- result += `**Implements:** ${type.implements.map((i) => `\`${i}\``).join(', ')}\n\n`;
99
- }
100
- if (type.properties && type.properties.length > 0) {
101
- result += '**Properties:**\n';
102
- for (const prop of type.properties.slice(0, 15)) {
103
- result += `- \`${formatProperty(prop)}\`\n`;
104
- if (prop.docs)
105
- result += ` > ${prop.docs}\n`;
106
- }
107
- if (type.properties.length > 15) {
108
- result += `- ... e mais ${type.properties.length - 15} propriedades\n`;
109
- }
110
- result += '\n';
111
- }
112
- if (type.methods && type.methods.length > 0) {
113
- result += '**Methods:**\n';
114
- for (const method of type.methods.slice(0, 15)) {
115
- result += `- \`${formatProperty(method)}\`\n`;
116
- if (method.docs)
117
- result += ` > ${method.docs}\n`;
118
- }
119
- if (type.methods.length > 15) {
120
- result += `- ... e mais ${type.methods.length - 15} métodos\n`;
121
- }
122
- result += '\n';
123
- }
124
- if (type.members && type.members.length > 0) {
125
- result += '**Members:**\n';
126
- for (const member of type.members.slice(0, 20)) {
127
- result += `- \`${member}\`\n`;
128
- }
129
- if (type.members.length > 20) {
130
- result += `- ... e mais ${type.members.length - 20} membros\n`;
131
- }
132
- result += '\n';
133
- }
134
- if (type.value) {
135
- result += `**Value:** \`${type.value}\`\n\n`;
136
- }
137
- }
138
- return result;
139
- }
140
- function formatStatistics(stats) {
141
- let result = '# 📊 Estatísticas da Biblioteca Tailwind CSS\n\n';
142
- result += `**Total de Declarações:** ${stats.totalDeclarations}\n\n`;
143
- result += '## Por Categoria\n\n';
144
- result += '| Categoria | Quantidade | % |\n';
145
- result += '|-----------|------------|---|\n';
146
- for (const [kind, count] of Object.entries(stats.byKind)) {
147
- const percentage = ((count / stats.totalDeclarations) * 100).toFixed(1);
148
- result += `| ${CATEGORY_EMOJI[kind]} ${CATEGORY_LABELS[kind]} | ${count} | ${percentage}% |\n`;
149
- }
150
- result += '\n## Por Módulo\n\n';
151
- result += '| Módulo | Total | Interfaces | Types | Functions | Enums | Variables | Classes |\n';
152
- result += '|--------|-------|------------|-------|-----------|-------|-----------|----------|\n';
153
- for (const mod of stats.byModule) {
154
- result += `| **${mod.module}** | ${mod.total} | ${mod.interfaces} | ${mod.types} | ${mod.functions} | ${mod.enums} | ${mod.variables} | ${mod.classes} |\n`;
155
- }
156
- result += '\n## Top Interfaces\n';
157
- for (const name of stats.topInterfaces) {
158
- result += `- \`${name}\`\n`;
159
- }
160
- result += '\n## Top Types\n';
161
- for (const name of stats.topTypes) {
162
- result += `- \`${name}\`\n`;
163
- }
164
- result += '\n## Top Functions\n';
165
- for (const name of stats.topFunctions) {
166
- result += `- \`${name}\`\n`;
167
- }
168
- return result;
169
- }
170
- function formatDependencies(deps) {
171
- let result = '# 🔗 Análise de Dependências\n\n';
172
- for (const dep of deps) {
173
- result += `## 📁 ${dep.module}\n\n`;
174
- if (dep.exports.length > 0) {
175
- result += `**Exports (${dep.exports.length}):** `;
176
- result += dep.exports.slice(0, 10).map((e) => `\`${e}\``).join(', ');
177
- if (dep.exports.length > 10) {
178
- result += `, ... (+${dep.exports.length - 10})`;
179
- }
180
- result += '\n\n';
181
- }
182
- if (dep.reExportsFrom.length > 0) {
183
- result += `**Re-exports from:** ${dep.reExportsFrom.map((r) => `\`${r}\``).join(', ')}\n\n`;
184
- }
185
- }
186
- return result;
187
- }
188
- mcpServer.server.setRequestHandler(ListToolsRequestSchema, async () => {
189
- return {
190
- tools: [
191
- {
192
- name: 'tailwind_estrutura',
193
- description: 'Lista a estrutura de arquivos do pacote Tailwind CSS (packages/tailwindcss/src). Útil para entender a organização do código.',
194
- inputSchema: {
195
- type: 'object',
196
- properties: {
197
- subpasta: {
198
- type: 'string',
199
- description: 'Subpasta específica para listar (ex: utils, compat). Deixe vazio para listar tudo.',
200
- },
201
- },
202
- required: [],
203
- },
204
- },
205
- {
206
- name: 'tailwind_ler_arquivo',
207
- description: 'Lê o conteúdo de um arquivo específico da biblioteca Tailwind CSS.',
208
- inputSchema: {
209
- type: 'object',
210
- properties: {
211
- caminho: {
212
- type: 'string',
213
- description: 'Caminho relativo do arquivo dentro de src/ (ex: utils/resolve-config.ts)',
214
- },
215
- },
216
- required: ['caminho'],
217
- },
218
- },
219
- {
220
- name: 'tailwind_extrair_tipos',
221
- description: 'Extrai interfaces, types, enums, funções, classes, variáveis e namespaces exportados do Tailwind usando análise de AST. Economiza tokens mostrando apenas assinaturas.',
222
- inputSchema: {
223
- type: 'object',
224
- properties: {
225
- modulo: {
226
- type: 'string',
227
- description: 'Nome do módulo para extrair tipos (ex: utils, compat, intellisense). Deixe vazio para todos.',
228
- },
229
- apenas_kind: {
230
- type: 'string',
231
- enum: ['interface', 'type', 'enum', 'function', 'class', 'variable', 'namespace', 're-export'],
232
- description: 'Filtrar por tipo específico de declaração.',
233
- },
234
- },
235
- required: [],
236
- },
237
- },
238
- {
239
- name: 'tailwind_buscar_tipo',
240
- description: 'Busca a definição de um tipo específico do Tailwind pelo nome. Retorna assinatura completa, propriedades, métodos e documentação.',
241
- inputSchema: {
242
- type: 'object',
243
- properties: {
244
- nome: {
245
- type: 'string',
246
- description: 'Nome do tipo a buscar (ex: Config, PluginCreator, ThemeValue)',
247
- },
248
- },
249
- required: ['nome'],
250
- },
251
- },
252
- {
253
- name: 'tailwind_buscar_fuzzy',
254
- description: 'Busca tipos do Tailwind usando correspondência aproximada. Útil quando não sabe o nome exato.',
255
- inputSchema: {
256
- type: 'object',
257
- properties: {
258
- query: {
259
- type: 'string',
260
- description: 'Termo de busca (ex: "message send", "auth state", "socket config")',
261
- },
262
- limite: {
263
- type: 'number',
264
- description: 'Número máximo de resultados (default: 20)',
265
- },
266
- },
267
- required: ['query'],
268
- },
269
- },
270
- {
271
- name: 'tailwind_listar_exports',
272
- description: 'Lista todos os exports públicos do Tailwind, agrupados por módulo e categoria.',
273
- inputSchema: {
274
- type: 'object',
275
- properties: {},
276
- required: [],
277
- },
278
- },
279
- {
280
- name: 'tailwind_categorias',
281
- description: 'Lista declarações de uma categoria específica (interfaces, types, enums, functions, classes, variables, namespaces) do Tailwind.',
282
- inputSchema: {
283
- type: 'object',
284
- properties: {
285
- categoria: {
286
- type: 'string',
287
- enum: ['interface', 'type', 'enum', 'function', 'class', 'variable', 'namespace', 're-export'],
288
- description: 'Categoria de declarações para listar.',
289
- },
290
- modulo: {
291
- type: 'string',
292
- description: 'Filtrar por módulo específico (opcional).',
293
- },
294
- },
295
- required: ['categoria'],
296
- },
297
- },
298
- {
299
- name: 'tailwind_constantes',
300
- description: 'Lista todas as constantes e variáveis exportadas do Tailwind (configurações, defaults, etc).',
301
- inputSchema: {
302
- type: 'object',
303
- properties: {
304
- modulo: {
305
- type: 'string',
306
- description: 'Filtrar por módulo específico (ex: Defaults, WABinary).',
307
- },
308
- },
309
- required: [],
310
- },
311
- },
312
- {
313
- name: 'tailwind_hierarquia',
314
- description: 'Mostra a hierarquia de herança de um tipo (extends/implements, pais e filhos).',
315
- inputSchema: {
316
- type: 'object',
317
- properties: {
318
- nome: {
319
- type: 'string',
320
- description: 'Nome do tipo para analisar hierarquia.',
321
- },
322
- },
323
- required: ['nome'],
324
- },
325
- },
326
- {
327
- name: 'tailwind_estatisticas',
328
- description: 'Retorna estatísticas detalhadas do Tailwind: contagem por categoria, por módulo, top tipos.',
329
- inputSchema: {
330
- type: 'object',
331
- properties: {},
332
- required: [],
333
- },
334
- },
335
- {
336
- name: 'tailwind_dependencias',
337
- description: 'Analisa as dependências entre módulos do Tailwind: o que cada módulo exporta e re-exporta.',
338
- inputSchema: {
339
- type: 'object',
340
- properties: {},
341
- required: [],
342
- },
343
- },
344
- {
345
- name: 'tailwind_enums',
346
- description: 'Lista todas as enumerações exportadas do Tailwind com seus valores.',
347
- inputSchema: {
348
- type: 'object',
349
- properties: {},
350
- required: [],
351
- },
352
- },
353
- {
354
- name: 'tailwind_interfaces',
355
- description: 'Lista todas as interfaces do Tailwind com suas propriedades e métodos.',
356
- inputSchema: {
357
- type: 'object',
358
- properties: {
359
- modulo: {
360
- type: 'string',
361
- description: 'Filtrar por módulo específico.',
362
- },
363
- detalhado: {
364
- type: 'boolean',
365
- description: 'Incluir propriedades e métodos (default: false).',
366
- },
367
- },
368
- required: [],
369
- },
370
- },
371
- {
372
- name: 'tailwind_funcoes',
373
- description: 'Lista todas as funções exportadas do Tailwind com suas assinaturas.',
374
- inputSchema: {
375
- type: 'object',
376
- properties: {
377
- modulo: {
378
- type: 'string',
379
- description: 'Filtrar por módulo específico (ex: Utils, Socket).',
380
- },
381
- },
382
- required: [],
383
- },
384
- },
385
- {
386
- name: 'tailwind_check_updates',
387
- description: 'Verifica se há atualizações disponíveis no repositório oficial do Tailwind CSS (GitHub). Não aplica atualizações, apenas verifica.',
388
- inputSchema: {
389
- type: 'object',
390
- properties: {},
391
- required: [],
392
- },
393
- },
394
- {
395
- name: 'tailwind_update',
396
- description: 'Atualiza o repositório local do Tailwind CSS para a versão mais recente do GitHub. Executa git pull automaticamente.',
397
- inputSchema: {
398
- type: 'object',
399
- properties: {},
400
- required: [],
401
- },
402
- },
403
- {
404
- name: 'tailwind_status',
405
- description: 'Mostra o status atual do repositório Tailwind: SHA do commit, se há atualizações pendentes, caminho do repositório.',
406
- inputSchema: {
407
- type: 'object',
408
- properties: {},
409
- required: [],
410
- },
411
- },
412
- {
413
- name: 'tailwind_integracoes',
414
- description: 'Passo a passo e snippets para integrar Tailwind CSS com frameworks (Vite, Next.js, Nuxt, SvelteKit, Remix, Astro, Vue, React).',
415
- inputSchema: {
416
- type: 'object',
417
- properties: {
418
- framework: {
419
- type: 'string',
420
- description: 'Framework alvo (vite, next, nuxt, sveltekit, remix, astro, vue, react).',
421
- },
422
- },
423
- required: ['framework'],
424
- },
425
- },
426
- {
427
- name: 'tailwind_utilities',
428
- description: 'Lista completa de classes utilitárias do Tailwind CSS organizadas por categoria (layout, flexbox, grid, spacing, sizing, typography, backgrounds, borders, effects, filters, transitions, transforms). Inclui sintaxe e CSS gerado.',
429
- inputSchema: {
430
- type: 'object',
431
- properties: {
432
- categoria: {
433
- type: 'string',
434
- enum: ['layout', 'flexbox', 'grid', 'spacing', 'sizing', 'typography', 'backgrounds', 'borders', 'effects', 'filters', 'transitions', 'transforms', 'interactivity', 'svg', 'tables', 'accessibility'],
435
- description: 'Categoria de utilities para listar. Se omitido, lista todas as categorias disponíveis.',
436
- },
437
- },
438
- required: [],
439
- },
440
- },
441
- {
442
- name: 'tailwind_variants',
443
- description: 'Lista completa de variants (modificadores) do Tailwind CSS: pseudo-classes (hover, focus, active), pseudo-elements (before, after), media queries (sm, md, lg), estados (disabled, checked), dark mode, e variants compostos (group-hover, peer-focus).',
444
- inputSchema: {
445
- type: 'object',
446
- properties: {
447
- tipo: {
448
- type: 'string',
449
- enum: ['pseudo-classes', 'pseudo-elements', 'responsive', 'dark-mode', 'state', 'compound', 'aria', 'data'],
450
- description: 'Tipo de variant para listar. Se omitido, lista todos os tipos.',
451
- },
452
- },
453
- required: [],
454
- },
455
- },
456
- {
457
- name: 'tailwind_cores',
458
- description: 'Paleta completa de cores do Tailwind CSS v4 com valores em OKLCH e equivalentes hex. Inclui todas as escalas (50-950) para cada cor (slate, gray, red, orange, yellow, green, blue, indigo, purple, pink).',
459
- inputSchema: {
460
- type: 'object',
461
- properties: {
462
- cor: {
463
- type: 'string',
464
- description: 'Nome da cor específica (slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose). Se omitido, lista todas.',
465
- },
466
- },
467
- required: [],
468
- },
469
- },
470
- {
471
- name: 'tailwind_spacing',
472
- description: 'Escala completa de espaçamento do Tailwind CSS. Mostra todos os valores de spacing (0, 0.5, 1, 1.5, 2, ... 96, px) com seus valores em rem/px. Usado para margin, padding, gap, width, height, etc.',
473
- inputSchema: {
474
- type: 'object',
475
- properties: {},
476
- required: [],
477
- },
478
- },
479
- {
480
- name: 'tailwind_breakpoints',
481
- description: 'Breakpoints responsivos do Tailwind CSS com valores e exemplos de uso. Mostra sm, md, lg, xl, 2xl e como usar min-*, max-* e container queries (@sm, @md, etc).',
482
- inputSchema: {
483
- type: 'object',
484
- properties: {},
485
- required: [],
486
- },
487
- },
488
- {
489
- name: 'tailwind_receitas',
490
- description: 'Receitas e exemplos prontos de componentes comuns com Tailwind CSS: buttons, cards, forms, modals, navbars, footers, heroes, grids responsivos. Código HTML+classes pronto para copiar.',
491
- inputSchema: {
492
- type: 'object',
493
- properties: {
494
- componente: {
495
- type: 'string',
496
- enum: ['button', 'card', 'form', 'input', 'modal', 'navbar', 'footer', 'hero', 'grid', 'alert', 'badge', 'avatar', 'dropdown', 'tabs', 'breadcrumb', 'pagination', 'skeleton'],
497
- description: 'Componente específico para ver a receita.',
498
- },
499
- },
500
- required: ['componente'],
501
- },
502
- },
503
- {
504
- name: 'tailwind_migracao_v4',
505
- description: 'Guia completo de migração do Tailwind CSS v3 para v4. Mudanças de sintaxe, novas features, breaking changes, e exemplos de código antes/depois.',
506
- inputSchema: {
507
- type: 'object',
508
- properties: {
509
- topico: {
510
- type: 'string',
511
- enum: ['overview', 'css-first', 'theme-config', 'utilities', 'variants', 'plugins', 'breaking-changes', 'postcss-vite'],
512
- description: 'Tópico específico da migração. Se omitido, mostra overview completo.',
513
- },
514
- },
515
- required: [],
516
- },
517
- },
518
- {
519
- name: 'tailwind_boas_praticas',
520
- description: 'Boas práticas e dicas para usar Tailwind CSS de forma eficiente: organização de classes, extração de componentes, performance, acessibilidade, responsive design, dark mode.',
521
- inputSchema: {
522
- type: 'object',
523
- properties: {
524
- topico: {
525
- type: 'string',
526
- enum: ['organizacao', 'componentes', 'performance', 'acessibilidade', 'responsivo', 'dark-mode', 'animacoes', 'forms'],
527
- description: 'Tópico específico. Se omitido, mostra dicas gerais.',
528
- },
529
- },
530
- required: [],
531
- },
532
- },
533
- ],
534
- };
535
- });
536
- mcpServer.server.setRequestHandler(CallToolRequestSchema, async (request) => {
537
- const { name, arguments: args } = request.params;
538
- try {
539
- switch (name) {
540
- case 'tailwind_estrutura': {
541
- const subpasta = args?.subpasta;
542
- const targetPath = subpasta ? path.join(TAILWIND_SRC_PATH, subpasta) : TAILWIND_SRC_PATH;
543
- if (!fs.existsSync(targetPath)) {
544
- return {
545
- content: [{ type: 'text', text: `❌ Pasta não encontrada: ${subpasta || 'src'}` }],
546
- isError: true,
547
- };
548
- }
549
- const tree = getDirectoryTree(targetPath);
550
- return {
551
- content: [
552
- {
553
- type: 'text',
554
- text: `# 📁 Estrutura de ${subpasta || 'tailwindcss/packages/tailwindcss/src'}\n\n\`\`\`\n${tree}\`\`\``,
555
- },
556
- ],
557
- };
558
- }
559
- case 'tailwind_ler_arquivo': {
560
- const caminho = args.caminho;
561
- const fullPath = path.join(TAILWIND_SRC_PATH, caminho);
562
- if (!fs.existsSync(fullPath)) {
563
- return {
564
- content: [{ type: 'text', text: `❌ Arquivo não encontrado: ${caminho}` }],
565
- isError: true,
566
- };
567
- }
568
- const content = fs.readFileSync(fullPath, 'utf-8');
569
- const ext = path.extname(caminho).slice(1) || 'typescript';
570
- return {
571
- content: [
572
- {
573
- type: 'text',
574
- text: `# 📄 ${caminho}\n\n\`\`\`${ext}\n${content}\n\`\`\``,
575
- },
576
- ],
577
- };
578
- }
579
- case 'tailwind_extrair_tipos': {
580
- const { modulo, apenas_kind } = args;
581
- const parser = new AstParser(TAILWIND_SRC_PATH);
582
- let types;
583
- if (modulo) {
584
- types = parser.getTypesFromModule(modulo);
585
- }
586
- else {
587
- types = parser.extractAllTypes();
588
- }
589
- if (apenas_kind) {
590
- types = types.filter((t) => t.kind === apenas_kind);
591
- }
592
- const grouped = {};
593
- for (const type of types) {
594
- if (!grouped[type.module])
595
- grouped[type.module] = [];
596
- grouped[type.module].push(type);
597
- }
598
- let result = `# 📚 Tipos Exportados${modulo ? ` (${modulo})` : ''}${apenas_kind ? ` - ${CATEGORY_LABELS[apenas_kind]}` : ''}\n\n`;
599
- result += `**Total:** ${types.length} declarações\n\n`;
600
- for (const [mod, moduleTypes] of Object.entries(grouped)) {
601
- result += `## 📁 ${mod}\n\n`;
602
- for (const type of moduleTypes) {
603
- result += formatExtractedType(type, false);
604
- }
605
- }
606
- return {
607
- content: [{ type: 'text', text: result }],
608
- };
609
- }
610
- case 'tailwind_buscar_tipo': {
611
- const nome = args.nome;
612
- const parser = new AstParser(TAILWIND_SRC_PATH);
613
- const found = parser.searchType(nome);
614
- if (!found) {
615
- const fuzzyResults = parser.fuzzySearch(nome, 5);
616
- let suggestion = '';
617
- if (fuzzyResults.length > 0) {
618
- suggestion = '\n\n**Você quis dizer:**\n' + fuzzyResults.map((t) => `- \`${t.name}\` (${t.kind})`).join('\n');
619
- }
620
- return {
621
- content: [
622
- {
623
- type: 'text',
624
- text: `❌ Tipo "${nome}" não encontrado.${suggestion}`,
625
- },
626
- ],
627
- isError: true,
628
- };
629
- }
630
- return {
631
- content: [{ type: 'text', text: formatExtractedType(found, true) }],
632
- };
633
- }
634
- case 'tailwind_buscar_fuzzy': {
635
- const { query, limite } = args;
636
- const parser = new AstParser(TAILWIND_SRC_PATH);
637
- const results = parser.fuzzySearch(query, limite || 20);
638
- if (results.length === 0) {
639
- return {
640
- content: [{ type: 'text', text: `❌ Nenhum resultado encontrado para "${query}"` }],
641
- isError: true,
642
- };
643
- }
644
- let result = `# 🔍 Resultados para "${query}"\n\n`;
645
- result += `**Encontrados:** ${results.length} tipos\n\n`;
646
- for (const type of results) {
647
- result += `- ${CATEGORY_EMOJI[type.kind]} **\`${type.name}\`** (${type.kind}) - \`${type.file}\`\n`;
648
- if (type.docs)
649
- result += ` > ${type.docs.substring(0, 100)}...\n`;
650
- }
651
- return {
652
- content: [{ type: 'text', text: result }],
653
- };
654
- }
655
- case 'tailwind_listar_exports': {
656
- const parser = new AstParser(TAILWIND_SRC_PATH);
657
- const types = parser.extractAllTypes();
658
- const byModule = {};
659
- for (const type of types) {
660
- if (!byModule[type.module]) {
661
- byModule[type.module] = {};
662
- }
663
- if (!byModule[type.module][type.kind]) {
664
- byModule[type.module][type.kind] = [];
665
- }
666
- byModule[type.module][type.kind].push(type.name);
667
- }
668
- let result = '# 📚 Exports da Biblioteca Tailwind CSS\n\n';
669
- result += `**Total:** ${types.length} declarações exportadas\n\n`;
670
- for (const [module, kinds] of Object.entries(byModule)) {
671
- const total = Object.values(kinds).flat().length;
672
- result += `## 📁 ${module} (${total})\n\n`;
673
- for (const [kind, names] of Object.entries(kinds)) {
674
- result += `### ${CATEGORY_EMOJI[kind]} ${CATEGORY_LABELS[kind]} (${names.length})\n`;
675
- for (const name of names.slice(0, 10)) {
676
- result += `- \`${name}\`\n`;
677
- }
678
- if (names.length > 10) {
679
- result += `- ... e mais ${names.length - 10}\n`;
680
- }
681
- result += '\n';
682
- }
683
- }
684
- return {
685
- content: [{ type: 'text', text: result }],
686
- };
687
- }
688
- case 'tailwind_categorias': {
689
- const { categoria, modulo } = args;
690
- const parser = new AstParser(TAILWIND_SRC_PATH);
691
- let types = parser.getTypesByKind(categoria);
692
- if (modulo) {
693
- types = types.filter((t) => t.module.toLowerCase() === modulo.toLowerCase());
694
- }
695
- let result = `# ${CATEGORY_EMOJI[categoria]} ${CATEGORY_LABELS[categoria]}\n\n`;
696
- result += `**Total:** ${types.length}\n\n`;
697
- for (const type of types) {
698
- result += formatExtractedType(type, categoria === 'enum' || categoria === 'interface');
699
- }
700
- return {
701
- content: [{ type: 'text', text: result }],
702
- };
703
- }
704
- case 'tailwind_constantes': {
705
- const { modulo } = args;
706
- const parser = new AstParser(TAILWIND_SRC_PATH);
707
- let constants = parser.getConstants();
708
- if (modulo) {
709
- constants = constants.filter((c) => c.module.toLowerCase() === modulo.toLowerCase());
710
- }
711
- let result = '# 📦 Constantes e Variáveis Exportadas\n\n';
712
- result += `**Total:** ${constants.length}\n\n`;
713
- const byModule = {};
714
- for (const c of constants) {
715
- if (!byModule[c.module])
716
- byModule[c.module] = [];
717
- byModule[c.module].push(c);
718
- }
719
- for (const [mod, vars] of Object.entries(byModule)) {
720
- result += `## 📁 ${mod}\n\n`;
721
- for (const v of vars) {
722
- result += `### \`${v.name}\`\n`;
723
- result += `**Tipo:** \`${v.signature.replace(`const ${v.name}: `, '')}\`\n`;
724
- if (v.value) {
725
- result += `**Valor:** \`${v.value}\`\n`;
726
- }
727
- result += '\n';
728
- }
729
- }
730
- return {
731
- content: [{ type: 'text', text: result }],
732
- };
733
- }
734
- case 'tailwind_hierarquia': {
735
- const { nome } = args;
736
- const parser = new AstParser(TAILWIND_SRC_PATH);
737
- const hierarchy = parser.getTypeHierarchy(nome);
738
- if (!hierarchy) {
739
- return {
740
- content: [{ type: 'text', text: `❌ Tipo "${nome}" não encontrado.` }],
741
- isError: true,
742
- };
743
- }
744
- let result = `# 🌳 Hierarquia de \`${hierarchy.type.name}\`\n\n`;
745
- result += formatExtractedType(hierarchy.type, false);
746
- if (hierarchy.parents.length > 0) {
747
- result += '## ⬆️ Herda de (Parents)\n\n';
748
- for (const parent of hierarchy.parents) {
749
- result += `- \`${parent}\`\n`;
750
- }
751
- result += '\n';
752
- }
753
- if (hierarchy.children.length > 0) {
754
- result += '## ⬇️ Herdado por (Children)\n\n';
755
- for (const child of hierarchy.children) {
756
- result += `- \`${child}\`\n`;
757
- }
758
- result += '\n';
759
- }
760
- if (hierarchy.parents.length === 0 && hierarchy.children.length === 0) {
761
- result += '*Este tipo não possui relacionamentos de herança.*\n';
762
- }
763
- return {
764
- content: [{ type: 'text', text: result }],
765
- };
766
- }
767
- case 'tailwind_estatisticas': {
768
- const parser = new AstParser(TAILWIND_SRC_PATH);
769
- const stats = parser.getStatistics();
770
- return {
771
- content: [{ type: 'text', text: formatStatistics(stats) }],
772
- };
773
- }
774
- case 'tailwind_dependencias': {
775
- const parser = new AstParser(TAILWIND_SRC_PATH);
776
- const deps = parser.analyzeDependencies();
777
- return {
778
- content: [{ type: 'text', text: formatDependencies(deps) }],
779
- };
780
- }
781
- case 'tailwind_enums': {
782
- const parser = new AstParser(TAILWIND_SRC_PATH);
783
- const enums = parser.getEnums();
784
- let result = '# 🔢 Enumerações da Biblioteca\n\n';
785
- result += `**Total:** ${enums.length}\n\n`;
786
- for (const e of enums) {
787
- result += `## \`${e.name}\`\n\n`;
788
- result += `**Arquivo:** \`${e.file}\`\n\n`;
789
- if (e.docs)
790
- result += `> ${e.docs}\n\n`;
791
- if (e.members && e.members.length > 0) {
792
- result += '**Valores:**\n';
793
- for (const member of e.members) {
794
- result += `- \`${member}\`\n`;
795
- }
796
- }
797
- result += '\n';
798
- }
799
- return {
800
- content: [{ type: 'text', text: result }],
801
- };
802
- }
803
- case 'tailwind_interfaces': {
804
- const { modulo, detalhado } = args;
805
- const parser = new AstParser(TAILWIND_SRC_PATH);
806
- let interfaces = parser.getInterfaces();
807
- if (modulo) {
808
- interfaces = interfaces.filter((i) => i.module.toLowerCase() === modulo.toLowerCase());
809
- }
810
- let result = '# 📋 Interfaces da Biblioteca\n\n';
811
- result += `**Total:** ${interfaces.length}\n\n`;
812
- for (const iface of interfaces) {
813
- result += formatExtractedType(iface, detalhado || false);
814
- }
815
- return {
816
- content: [{ type: 'text', text: result }],
817
- };
818
- }
819
- case 'tailwind_funcoes': {
820
- const { modulo } = args;
821
- const parser = new AstParser(TAILWIND_SRC_PATH);
822
- let functions = parser.getFunctions();
823
- if (modulo) {
824
- functions = functions.filter((f) => f.module.toLowerCase() === modulo.toLowerCase());
825
- }
826
- let result = '# ⚡ Funções da Biblioteca\n\n';
827
- result += `**Total:** ${functions.length}\n\n`;
828
- const byModule = {};
829
- for (const f of functions) {
830
- if (!byModule[f.module])
831
- byModule[f.module] = [];
832
- byModule[f.module].push(f);
833
- }
834
- for (const [mod, funcs] of Object.entries(byModule)) {
835
- result += `## 📁 ${mod}\n\n`;
836
- for (const func of funcs) {
837
- result += formatExtractedType(func, true);
838
- }
839
- }
840
- return {
841
- content: [{ type: 'text', text: result }],
842
- };
843
- }
844
- case 'tailwind_integracoes': {
845
- const { framework } = args;
846
- const key = framework.toLowerCase();
847
- const guides = {
848
- vite: {
849
- title: 'Vite (React/Vue/Svelte)',
850
- v4: {
851
- steps: [
852
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
853
- 'Configure o plugin no vite.config.ts',
854
- 'Crie o CSS com @import "tailwindcss"',
855
- 'Importe o CSS no entry (main.tsx/main.ts)',
856
- ],
857
- configSnippet: `// vite.config.ts
858
- import tailwindcss from '@tailwindcss/vite'
859
- import { defineConfig } from 'vite'
860
-
861
- export default defineConfig({
862
- plugins: [tailwindcss()]
863
- })`,
864
- cssSnippet: `/* app.css */
865
- @import "tailwindcss";
866
-
867
- @theme {
868
- /* Customize theme variables */
869
- --color-brand: oklch(0.72 0.11 221.19);
870
- }`,
871
- },
872
- v3: {
873
- steps: [
874
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
875
- 'Gere config: npx tailwindcss init -p',
876
- 'Configure content no tailwind.config.js',
877
- 'Crie CSS com diretivas @tailwind',
878
- ],
879
- configSnippet: `// tailwind.config.js
880
- module.exports = {
881
- content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue,svelte}'],
882
- theme: { extend: {} },
883
- plugins: [],
884
- }`,
885
- cssSnippet: `/* src/index.css */
886
- @tailwind base;
887
- @tailwind components;
888
- @tailwind utilities;`,
889
- },
890
- contentGlob: './index.html, ./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
891
- },
892
- next: {
893
- title: 'Next.js (App Router)',
894
- v4: {
895
- steps: [
896
- 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
897
- 'Configure postcss.config.mjs',
898
- 'Crie app/globals.css com @import "tailwindcss"',
899
- 'Importe em app/layout.tsx',
900
- ],
901
- configSnippet: `// postcss.config.mjs
902
- export default {
903
- plugins: {
904
- '@tailwindcss/postcss': {}
905
- }
906
- }`,
907
- cssSnippet: `/* app/globals.css */
908
- @import "tailwindcss";
909
-
910
- @theme {
911
- --color-primary: oklch(0.62 0.21 259.81);
912
- }`,
913
- },
914
- v3: {
915
- steps: [
916
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
917
- 'Gere config: npx tailwindcss init -p',
918
- 'Configure content no tailwind.config.js',
919
- 'Crie globals.css com diretivas @tailwind',
920
- ],
921
- configSnippet: `// tailwind.config.js
922
- module.exports = {
923
- content: [
924
- './app/**/*.{js,ts,jsx,tsx,mdx}',
925
- './pages/**/*.{js,ts,jsx,tsx}',
926
- './components/**/*.{js,ts,jsx,tsx}',
927
- './src/**/*.{js,ts,jsx,tsx,mdx}',
928
- ],
929
- theme: { extend: {} },
930
- plugins: [],
931
- }`,
932
- cssSnippet: `/* app/globals.css */
933
- @tailwind base;
934
- @tailwind components;
935
- @tailwind utilities;`,
936
- },
937
- contentGlob: './app/**/*.{js,ts,jsx,tsx,mdx}, ./components/**/*.{js,ts,jsx,tsx}',
938
- },
939
- nuxt: {
940
- title: 'Nuxt 3',
941
- v4: {
942
- steps: [
943
- 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
944
- 'Configure postcss no nuxt.config.ts',
945
- 'Crie assets/css/main.css com @import "tailwindcss"',
946
- 'Adicione o CSS ao nuxt.config.ts',
947
- ],
948
- configSnippet: `// nuxt.config.ts
949
- export default defineNuxtConfig({
950
- css: ['~/assets/css/main.css'],
951
- postcss: {
952
- plugins: {
953
- '@tailwindcss/postcss': {}
954
- }
955
- }
956
- })`,
957
- cssSnippet: `/* assets/css/main.css */
958
- @import "tailwindcss";
959
-
960
- @theme {
961
- --color-brand: oklch(0.69 0.17 162.48);
962
- }`,
963
- },
964
- v3: {
965
- steps: [
966
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
967
- 'Gere config: npx tailwindcss init -p',
968
- 'Configure content e adicione CSS ao nuxt.config.ts',
969
- ],
970
- configSnippet: `// tailwind.config.js
971
- module.exports = {
972
- content: [
973
- './components/**/*.{vue,js,ts}',
974
- './layouts/**/*.vue',
975
- './pages/**/*.vue',
976
- './app.vue',
977
- './plugins/**/*.{js,ts}',
978
- ],
979
- theme: { extend: {} },
980
- plugins: [],
981
- }`,
982
- cssSnippet: `/* assets/css/tailwind.css */
983
- @tailwind base;
984
- @tailwind components;
985
- @tailwind utilities;`,
986
- },
987
- contentGlob: './components/**/*.{vue,js,ts}, ./pages/**/*.vue, ./app.vue',
988
- },
989
- sveltekit: {
990
- title: 'SvelteKit',
991
- v4: {
992
- steps: [
993
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
994
- 'Configure o plugin no vite.config.ts',
995
- 'Crie src/app.css com @import "tailwindcss"',
996
- 'Importe em src/routes/+layout.svelte',
997
- ],
998
- configSnippet: `// vite.config.ts
999
- import { sveltekit } from '@sveltejs/kit/vite'
1000
- import tailwindcss from '@tailwindcss/vite'
1001
- import { defineConfig } from 'vite'
1002
-
1003
- export default defineConfig({
1004
- plugins: [tailwindcss(), sveltekit()]
1005
- })`,
1006
- cssSnippet: `/* src/app.css */
1007
- @import "tailwindcss";`,
1008
- },
1009
- v3: {
1010
- steps: [
1011
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1012
- 'Gere config: npx tailwindcss init -p',
1013
- 'Crie src/app.css e importe em +layout.svelte',
1014
- ],
1015
- configSnippet: `// tailwind.config.js
1016
- module.exports = {
1017
- content: ['./src/**/*.{html,js,svelte,ts}'],
1018
- theme: { extend: {} },
1019
- plugins: [],
1020
- }`,
1021
- cssSnippet: `/* src/app.css */
1022
- @tailwind base;
1023
- @tailwind components;
1024
- @tailwind utilities;`,
1025
- },
1026
- contentGlob: './src/**/*.{html,js,svelte,ts}',
1027
- },
1028
- astro: {
1029
- title: 'Astro',
1030
- v4: {
1031
- steps: [
1032
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1033
- 'Configure o plugin no astro.config.mjs',
1034
- 'Crie src/styles/global.css com @import "tailwindcss"',
1035
- 'Importe em layouts/Layout.astro',
1036
- ],
1037
- configSnippet: `// astro.config.mjs
1038
- import { defineConfig } from 'astro/config'
1039
- import tailwindcss from '@tailwindcss/vite'
1040
-
1041
- export default defineConfig({
1042
- vite: {
1043
- plugins: [tailwindcss()]
1044
- }
1045
- })`,
1046
- cssSnippet: `/* src/styles/global.css */
1047
- @import "tailwindcss";`,
1048
- },
1049
- v3: {
1050
- steps: [
1051
- 'Use: npx astro add tailwind (recomendado)',
1052
- 'Ou manual: npm install -D tailwindcss @astrojs/tailwind',
1053
- ],
1054
- configSnippet: `// tailwind.config.js
1055
- module.exports = {
1056
- content: ['./src/**/*.{astro,html,js,jsx,ts,tsx,vue,svelte}'],
1057
- theme: { extend: {} },
1058
- plugins: [],
1059
- }`,
1060
- cssSnippet: `/* src/styles/global.css */
1061
- @tailwind base;
1062
- @tailwind components;
1063
- @tailwind utilities;`,
1064
- },
1065
- contentGlob: './src/**/*.{astro,html,js,jsx,ts,tsx,vue,svelte}',
1066
- },
1067
- remix: {
1068
- title: 'Remix',
1069
- v4: {
1070
- steps: [
1071
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1072
- 'Configure o plugin no vite.config.ts',
1073
- 'Crie app/tailwind.css com @import "tailwindcss"',
1074
- 'Importe em app/root.tsx via links()',
1075
- ],
1076
- configSnippet: `// vite.config.ts
1077
- import { vitePlugin as remix } from '@remix-run/dev'
1078
- import tailwindcss from '@tailwindcss/vite'
1079
- import { defineConfig } from 'vite'
1080
-
1081
- export default defineConfig({
1082
- plugins: [tailwindcss(), remix()]
1083
- })`,
1084
- cssSnippet: `/* app/tailwind.css */
1085
- @import "tailwindcss";`,
1086
- },
1087
- v3: {
1088
- steps: [
1089
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1090
- 'Gere config: npx tailwindcss init -p',
1091
- 'Crie app/tailwind.css e importe em root.tsx',
1092
- ],
1093
- configSnippet: `// tailwind.config.js
1094
- module.exports = {
1095
- content: ['./app/**/*.{ts,tsx,js,jsx}'],
1096
- theme: { extend: {} },
1097
- plugins: [],
1098
- }`,
1099
- cssSnippet: `/* app/tailwind.css */
1100
- @tailwind base;
1101
- @tailwind components;
1102
- @tailwind utilities;`,
1103
- },
1104
- contentGlob: './app/**/*.{ts,tsx,js,jsx}',
1105
- },
1106
- vue: {
1107
- title: 'Vue 3 (Vite)',
1108
- v4: {
1109
- steps: [
1110
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1111
- 'Configure o plugin no vite.config.ts',
1112
- 'Crie src/assets/main.css com @import "tailwindcss"',
1113
- 'Importe em src/main.ts',
1114
- ],
1115
- configSnippet: `// vite.config.ts
1116
- import vue from '@vitejs/plugin-vue'
1117
- import tailwindcss from '@tailwindcss/vite'
1118
- import { defineConfig } from 'vite'
1119
-
1120
- export default defineConfig({
1121
- plugins: [vue(), tailwindcss()]
1122
- })`,
1123
- cssSnippet: `/* src/assets/main.css */
1124
- @import "tailwindcss";`,
1125
- },
1126
- v3: {
1127
- steps: [
1128
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1129
- 'Gere config: npx tailwindcss init -p',
1130
- 'Crie src/assets/tailwind.css e importe em main.ts',
1131
- ],
1132
- configSnippet: `// tailwind.config.js
1133
- module.exports = {
1134
- content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
1135
- theme: { extend: {} },
1136
- plugins: [],
1137
- }`,
1138
- cssSnippet: `/* src/assets/tailwind.css */
1139
- @tailwind base;
1140
- @tailwind components;
1141
- @tailwind utilities;`,
1142
- },
1143
- contentGlob: './index.html, ./src/**/*.{vue,js,ts,jsx,tsx}',
1144
- },
1145
- react: {
1146
- title: 'React (Vite)',
1147
- v4: {
1148
- steps: [
1149
- 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1150
- 'Configure o plugin no vite.config.ts',
1151
- 'Crie src/index.css com @import "tailwindcss"',
1152
- 'Importe em src/main.tsx',
1153
- ],
1154
- configSnippet: `// vite.config.ts
1155
- import react from '@vitejs/plugin-react'
1156
- import tailwindcss from '@tailwindcss/vite'
1157
- import { defineConfig } from 'vite'
1158
-
1159
- export default defineConfig({
1160
- plugins: [react(), tailwindcss()]
1161
- })`,
1162
- cssSnippet: `/* src/index.css */
1163
- @import "tailwindcss";`,
1164
- },
1165
- v3: {
1166
- steps: [
1167
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1168
- 'Gere config: npx tailwindcss init -p',
1169
- 'Crie src/index.css e importe em main.tsx/index.tsx',
1170
- ],
1171
- configSnippet: `// tailwind.config.js
1172
- module.exports = {
1173
- content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
1174
- theme: { extend: {} },
1175
- plugins: [],
1176
- }`,
1177
- cssSnippet: `/* src/index.css */
1178
- @tailwind base;
1179
- @tailwind components;
1180
- @tailwind utilities;`,
1181
- },
1182
- contentGlob: './index.html, ./src/**/*.{js,ts,jsx,tsx}',
1183
- },
1184
- postcss: {
1185
- title: 'PostCSS (Universal)',
1186
- v4: {
1187
- steps: [
1188
- 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
1189
- 'Configure postcss.config.js',
1190
- 'Crie CSS com @import "tailwindcss"',
1191
- ],
1192
- configSnippet: `// postcss.config.js
1193
- export default {
1194
- plugins: {
1195
- '@tailwindcss/postcss': {}
1196
- }
1197
- }`,
1198
- cssSnippet: `/* styles.css */
1199
- @import "tailwindcss";`,
1200
- },
1201
- v3: {
1202
- steps: [
1203
- 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1204
- 'Configure postcss.config.js',
1205
- 'Crie CSS com diretivas @tailwind',
1206
- ],
1207
- configSnippet: `// postcss.config.js
1208
- module.exports = {
1209
- plugins: {
1210
- tailwindcss: {},
1211
- autoprefixer: {},
1212
- }
1213
- }`,
1214
- cssSnippet: `/* styles.css */
1215
- @tailwind base;
1216
- @tailwind components;
1217
- @tailwind utilities;`,
1218
- },
1219
- contentGlob: './src/**/*.{html,js,ts,jsx,tsx}',
1220
- },
1221
- cli: {
1222
- title: 'CLI (Standalone)',
1223
- v4: {
1224
- steps: [
1225
- 'Instale: npm install tailwindcss @tailwindcss/cli',
1226
- 'Execute: npx @tailwindcss/cli -i input.css -o output.css --watch',
1227
- ],
1228
- configSnippet: `# Comando para build
1229
- npx @tailwindcss/cli -i input.css -o output.css
1230
-
1231
- # Comando para watch
1232
- npx @tailwindcss/cli -i input.css -o output.css --watch
1233
-
1234
- # Minificado para produção
1235
- npx @tailwindcss/cli -i input.css -o output.css --minify`,
1236
- cssSnippet: `/* input.css */
1237
- @import "tailwindcss";`,
1238
- },
1239
- v3: {
1240
- steps: [
1241
- 'Instale: npm install -D tailwindcss',
1242
- 'Gere config: npx tailwindcss init',
1243
- 'Execute: npx tailwindcss -i input.css -o output.css --watch',
1244
- ],
1245
- configSnippet: `# Comando para watch
1246
- npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
1247
-
1248
- # Minificado para produção
1249
- npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify`,
1250
- cssSnippet: `/* input.css */
1251
- @tailwind base;
1252
- @tailwind components;
1253
- @tailwind utilities;`,
1254
- },
1255
- contentGlob: './src/**/*.{html,js}',
1256
- },
1257
- };
1258
- const guide = guides[key];
1259
- if (!guide) {
1260
- const available = Object.keys(guides).join(', ');
1261
- return {
1262
- content: [{ type: 'text', text: `❌ Framework não suportado: ${framework}\n\nFrameworks disponíveis: ${available}` }],
1263
- isError: true,
1264
- };
1265
- }
1266
- let result = `# 🚀 Integração Tailwind CSS + ${guide.title}\n\n`;
1267
- result += '---\n\n';
1268
- result += '## ⚡ Tailwind v4 (Recomendado)\n\n';
1269
- result += '**Passos:**\n';
1270
- for (let i = 0; i < guide.v4.steps.length; i++) {
1271
- result += `${i + 1}. ${guide.v4.steps[i]}\n`;
1272
- }
1273
- result += '\n**Configuração:**\n```ts\n' + guide.v4.configSnippet + '\n```\n\n';
1274
- result += '**CSS:**\n```css\n' + guide.v4.cssSnippet + '\n```\n\n';
1275
- result += '---\n\n';
1276
- result += '## 📦 Tailwind v3 (Legado)\n\n';
1277
- result += '**Passos:**\n';
1278
- for (let i = 0; i < guide.v3.steps.length; i++) {
1279
- result += `${i + 1}. ${guide.v3.steps[i]}\n`;
1280
- }
1281
- result += '\n**Configuração:**\n```js\n' + guide.v3.configSnippet + '\n```\n\n';
1282
- result += '**CSS:**\n```css\n' + guide.v3.cssSnippet + '\n```\n\n';
1283
- result += '---\n\n';
1284
- result += `**Content glob recomendado:** \`${guide.contentGlob}\`\n`;
1285
- return {
1286
- content: [{ type: 'text', text: result }],
1287
- };
1288
- }
1289
- case 'tailwind_utilities': {
1290
- const categoria = args?.categoria;
1291
- const utilities = {
1292
- layout: {
1293
- desc: 'Controle de layout e posicionamento',
1294
- classes: [
1295
- { class: 'block', css: 'display: block;' },
1296
- { class: 'inline-block', css: 'display: inline-block;' },
1297
- { class: 'inline', css: 'display: inline;' },
1298
- { class: 'flex', css: 'display: flex;' },
1299
- { class: 'inline-flex', css: 'display: inline-flex;' },
1300
- { class: 'grid', css: 'display: grid;' },
1301
- { class: 'inline-grid', css: 'display: inline-grid;' },
1302
- { class: 'hidden', css: 'display: none;' },
1303
- { class: 'container', css: 'width: 100%; max-width: breakpoint;' },
1304
- { class: 'static', css: 'position: static;' },
1305
- { class: 'fixed', css: 'position: fixed;' },
1306
- { class: 'absolute', css: 'position: absolute;' },
1307
- { class: 'relative', css: 'position: relative;' },
1308
- { class: 'sticky', css: 'position: sticky;' },
1309
- { class: 'inset-{n}', css: 'inset: {value};', desc: 'top, right, bottom, left' },
1310
- { class: 'top-{n}', css: 'top: {value};' },
1311
- { class: 'right-{n}', css: 'right: {value};' },
1312
- { class: 'bottom-{n}', css: 'bottom: {value};' },
1313
- { class: 'left-{n}', css: 'left: {value};' },
1314
- { class: 'z-{n}', css: 'z-index: {n};', desc: '0, 10, 20, 30, 40, 50, auto' },
1315
- { class: 'visible', css: 'visibility: visible;' },
1316
- { class: 'invisible', css: 'visibility: hidden;' },
1317
- { class: 'collapse', css: 'visibility: collapse;' },
1318
- ],
1319
- },
1320
- flexbox: {
1321
- desc: 'Flexbox utilities',
1322
- classes: [
1323
- { class: 'flex-row', css: 'flex-direction: row;' },
1324
- { class: 'flex-row-reverse', css: 'flex-direction: row-reverse;' },
1325
- { class: 'flex-col', css: 'flex-direction: column;' },
1326
- { class: 'flex-col-reverse', css: 'flex-direction: column-reverse;' },
1327
- { class: 'flex-wrap', css: 'flex-wrap: wrap;' },
1328
- { class: 'flex-wrap-reverse', css: 'flex-wrap: wrap-reverse;' },
1329
- { class: 'flex-nowrap', css: 'flex-wrap: nowrap;' },
1330
- { class: 'flex-1', css: 'flex: 1 1 0%;' },
1331
- { class: 'flex-auto', css: 'flex: 1 1 auto;' },
1332
- { class: 'flex-initial', css: 'flex: 0 1 auto;' },
1333
- { class: 'flex-none', css: 'flex: none;' },
1334
- { class: 'grow', css: 'flex-grow: 1;' },
1335
- { class: 'grow-0', css: 'flex-grow: 0;' },
1336
- { class: 'shrink', css: 'flex-shrink: 1;' },
1337
- { class: 'shrink-0', css: 'flex-shrink: 0;' },
1338
- { class: 'basis-{n}', css: 'flex-basis: {value};' },
1339
- { class: 'justify-start', css: 'justify-content: flex-start;' },
1340
- { class: 'justify-end', css: 'justify-content: flex-end;' },
1341
- { class: 'justify-center', css: 'justify-content: center;' },
1342
- { class: 'justify-between', css: 'justify-content: space-between;' },
1343
- { class: 'justify-around', css: 'justify-content: space-around;' },
1344
- { class: 'justify-evenly', css: 'justify-content: space-evenly;' },
1345
- { class: 'items-start', css: 'align-items: flex-start;' },
1346
- { class: 'items-end', css: 'align-items: flex-end;' },
1347
- { class: 'items-center', css: 'align-items: center;' },
1348
- { class: 'items-baseline', css: 'align-items: baseline;' },
1349
- { class: 'items-stretch', css: 'align-items: stretch;' },
1350
- { class: 'gap-{n}', css: 'gap: {value};' },
1351
- { class: 'gap-x-{n}', css: 'column-gap: {value};' },
1352
- { class: 'gap-y-{n}', css: 'row-gap: {value};' },
1353
- ],
1354
- },
1355
- grid: {
1356
- desc: 'Grid utilities',
1357
- classes: [
1358
- { class: 'grid-cols-{n}', css: 'grid-template-columns: repeat({n}, minmax(0, 1fr));', desc: '1-12, none' },
1359
- { class: 'grid-rows-{n}', css: 'grid-template-rows: repeat({n}, minmax(0, 1fr));', desc: '1-12, none' },
1360
- { class: 'col-span-{n}', css: 'grid-column: span {n} / span {n};', desc: '1-12, full' },
1361
- { class: 'col-start-{n}', css: 'grid-column-start: {n};' },
1362
- { class: 'col-end-{n}', css: 'grid-column-end: {n};' },
1363
- { class: 'row-span-{n}', css: 'grid-row: span {n} / span {n};' },
1364
- { class: 'row-start-{n}', css: 'grid-row-start: {n};' },
1365
- { class: 'row-end-{n}', css: 'grid-row-end: {n};' },
1366
- { class: 'grid-flow-row', css: 'grid-auto-flow: row;' },
1367
- { class: 'grid-flow-col', css: 'grid-auto-flow: column;' },
1368
- { class: 'grid-flow-dense', css: 'grid-auto-flow: dense;' },
1369
- { class: 'auto-cols-auto', css: 'grid-auto-columns: auto;' },
1370
- { class: 'auto-cols-min', css: 'grid-auto-columns: min-content;' },
1371
- { class: 'auto-cols-max', css: 'grid-auto-columns: max-content;' },
1372
- { class: 'auto-cols-fr', css: 'grid-auto-columns: minmax(0, 1fr);' },
1373
- { class: 'auto-rows-auto', css: 'grid-auto-rows: auto;' },
1374
- { class: 'auto-rows-min', css: 'grid-auto-rows: min-content;' },
1375
- { class: 'auto-rows-max', css: 'grid-auto-rows: max-content;' },
1376
- { class: 'auto-rows-fr', css: 'grid-auto-rows: minmax(0, 1fr);' },
1377
- ],
1378
- },
1379
- spacing: {
1380
- desc: 'Margin e Padding',
1381
- classes: [
1382
- { class: 'p-{n}', css: 'padding: {value};', desc: '0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96, px' },
1383
- { class: 'px-{n}', css: 'padding-left: {value}; padding-right: {value};' },
1384
- { class: 'py-{n}', css: 'padding-top: {value}; padding-bottom: {value};' },
1385
- { class: 'pt-{n}', css: 'padding-top: {value};' },
1386
- { class: 'pr-{n}', css: 'padding-right: {value};' },
1387
- { class: 'pb-{n}', css: 'padding-bottom: {value};' },
1388
- { class: 'pl-{n}', css: 'padding-left: {value};' },
1389
- { class: 'm-{n}', css: 'margin: {value};' },
1390
- { class: 'mx-{n}', css: 'margin-left: {value}; margin-right: {value};' },
1391
- { class: 'my-{n}', css: 'margin-top: {value}; margin-bottom: {value};' },
1392
- { class: 'mt-{n}', css: 'margin-top: {value};' },
1393
- { class: 'mr-{n}', css: 'margin-right: {value};' },
1394
- { class: 'mb-{n}', css: 'margin-bottom: {value};' },
1395
- { class: 'ml-{n}', css: 'margin-left: {value};' },
1396
- { class: '-m-{n}', css: 'margin: -{value};', desc: 'Negative margin' },
1397
- { class: 'space-x-{n}', css: '> * + * { margin-left: {value}; }' },
1398
- { class: 'space-y-{n}', css: '> * + * { margin-top: {value}; }' },
1399
- { class: 'space-x-reverse', css: '--tw-space-x-reverse: 1;' },
1400
- { class: 'space-y-reverse', css: '--tw-space-y-reverse: 1;' },
1401
- ],
1402
- },
1403
- sizing: {
1404
- desc: 'Width e Height',
1405
- classes: [
1406
- { class: 'w-{n}', css: 'width: {value};', desc: '0-96, auto, full, screen, svw, lvw, dvw, min, max, fit' },
1407
- { class: 'w-1/2', css: 'width: 50%;' },
1408
- { class: 'w-1/3', css: 'width: 33.333333%;' },
1409
- { class: 'w-2/3', css: 'width: 66.666667%;' },
1410
- { class: 'w-1/4', css: 'width: 25%;' },
1411
- { class: 'w-full', css: 'width: 100%;' },
1412
- { class: 'w-screen', css: 'width: 100vw;' },
1413
- { class: 'w-auto', css: 'width: auto;' },
1414
- { class: 'min-w-{n}', css: 'min-width: {value};' },
1415
- { class: 'max-w-{n}', css: 'max-width: {value};', desc: 'xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, full, prose, screen-sm, screen-md, screen-lg, screen-xl, screen-2xl' },
1416
- { class: 'h-{n}', css: 'height: {value};' },
1417
- { class: 'h-full', css: 'height: 100%;' },
1418
- { class: 'h-screen', css: 'height: 100vh;' },
1419
- { class: 'h-svh', css: 'height: 100svh;' },
1420
- { class: 'h-lvh', css: 'height: 100lvh;' },
1421
- { class: 'h-dvh', css: 'height: 100dvh;' },
1422
- { class: 'min-h-{n}', css: 'min-height: {value};' },
1423
- { class: 'min-h-screen', css: 'min-height: 100vh;' },
1424
- { class: 'max-h-{n}', css: 'max-height: {value};' },
1425
- { class: 'size-{n}', css: 'width: {value}; height: {value};', desc: 'v4: shorthand for w + h' },
1426
- ],
1427
- },
1428
- typography: {
1429
- desc: 'Tipografia e texto',
1430
- classes: [
1431
- { class: 'text-xs', css: 'font-size: 0.75rem; line-height: 1rem;' },
1432
- { class: 'text-sm', css: 'font-size: 0.875rem; line-height: 1.25rem;' },
1433
- { class: 'text-base', css: 'font-size: 1rem; line-height: 1.5rem;' },
1434
- { class: 'text-lg', css: 'font-size: 1.125rem; line-height: 1.75rem;' },
1435
- { class: 'text-xl', css: 'font-size: 1.25rem; line-height: 1.75rem;' },
1436
- { class: 'text-2xl', css: 'font-size: 1.5rem; line-height: 2rem;' },
1437
- { class: 'text-3xl', css: 'font-size: 1.875rem; line-height: 2.25rem;' },
1438
- { class: 'text-4xl', css: 'font-size: 2.25rem; line-height: 2.5rem;' },
1439
- { class: 'text-5xl', css: 'font-size: 3rem; line-height: 1;' },
1440
- { class: 'text-6xl', css: 'font-size: 3.75rem; line-height: 1;' },
1441
- { class: 'font-thin', css: 'font-weight: 100;' },
1442
- { class: 'font-light', css: 'font-weight: 300;' },
1443
- { class: 'font-normal', css: 'font-weight: 400;' },
1444
- { class: 'font-medium', css: 'font-weight: 500;' },
1445
- { class: 'font-semibold', css: 'font-weight: 600;' },
1446
- { class: 'font-bold', css: 'font-weight: 700;' },
1447
- { class: 'font-extrabold', css: 'font-weight: 800;' },
1448
- { class: 'font-black', css: 'font-weight: 900;' },
1449
- { class: 'italic', css: 'font-style: italic;' },
1450
- { class: 'not-italic', css: 'font-style: normal;' },
1451
- { class: 'text-left', css: 'text-align: left;' },
1452
- { class: 'text-center', css: 'text-align: center;' },
1453
- { class: 'text-right', css: 'text-align: right;' },
1454
- { class: 'text-justify', css: 'text-align: justify;' },
1455
- { class: 'underline', css: 'text-decoration-line: underline;' },
1456
- { class: 'overline', css: 'text-decoration-line: overline;' },
1457
- { class: 'line-through', css: 'text-decoration-line: line-through;' },
1458
- { class: 'no-underline', css: 'text-decoration-line: none;' },
1459
- { class: 'uppercase', css: 'text-transform: uppercase;' },
1460
- { class: 'lowercase', css: 'text-transform: lowercase;' },
1461
- { class: 'capitalize', css: 'text-transform: capitalize;' },
1462
- { class: 'normal-case', css: 'text-transform: none;' },
1463
- { class: 'truncate', css: 'overflow: hidden; text-overflow: ellipsis; white-space: nowrap;' },
1464
- { class: 'leading-{n}', css: 'line-height: {value};', desc: '3-10, none, tight, snug, normal, relaxed, loose' },
1465
- { class: 'tracking-{n}', css: 'letter-spacing: {value};', desc: 'tighter, tight, normal, wide, wider, widest' },
1466
- ],
1467
- },
1468
- backgrounds: {
1469
- desc: 'Backgrounds e gradientes',
1470
- classes: [
1471
- { class: 'bg-{color}', css: 'background-color: {color};', desc: 'Qualquer cor da paleta' },
1472
- { class: 'bg-transparent', css: 'background-color: transparent;' },
1473
- { class: 'bg-current', css: 'background-color: currentColor;' },
1474
- { class: 'bg-inherit', css: 'background-color: inherit;' },
1475
- { class: 'bg-gradient-to-{dir}', css: 'background-image: linear-gradient(to {dir}, ...);', desc: 't, tr, r, br, b, bl, l, tl' },
1476
- { class: 'from-{color}', css: '--tw-gradient-from: {color};' },
1477
- { class: 'via-{color}', css: '--tw-gradient-via: {color};' },
1478
- { class: 'to-{color}', css: '--tw-gradient-to: {color};' },
1479
- { class: 'bg-none', css: 'background-image: none;' },
1480
- { class: 'bg-cover', css: 'background-size: cover;' },
1481
- { class: 'bg-contain', css: 'background-size: contain;' },
1482
- { class: 'bg-auto', css: 'background-size: auto;' },
1483
- { class: 'bg-fixed', css: 'background-attachment: fixed;' },
1484
- { class: 'bg-local', css: 'background-attachment: local;' },
1485
- { class: 'bg-scroll', css: 'background-attachment: scroll;' },
1486
- { class: 'bg-center', css: 'background-position: center;' },
1487
- { class: 'bg-top', css: 'background-position: top;' },
1488
- { class: 'bg-bottom', css: 'background-position: bottom;' },
1489
- { class: 'bg-repeat', css: 'background-repeat: repeat;' },
1490
- { class: 'bg-no-repeat', css: 'background-repeat: no-repeat;' },
1491
- { class: 'bg-repeat-x', css: 'background-repeat: repeat-x;' },
1492
- { class: 'bg-repeat-y', css: 'background-repeat: repeat-y;' },
1493
- ],
1494
- },
1495
- borders: {
1496
- desc: 'Borders e border-radius',
1497
- classes: [
1498
- { class: 'border', css: 'border-width: 1px;' },
1499
- { class: 'border-0', css: 'border-width: 0px;' },
1500
- { class: 'border-2', css: 'border-width: 2px;' },
1501
- { class: 'border-4', css: 'border-width: 4px;' },
1502
- { class: 'border-8', css: 'border-width: 8px;' },
1503
- { class: 'border-t', css: 'border-top-width: 1px;' },
1504
- { class: 'border-r', css: 'border-right-width: 1px;' },
1505
- { class: 'border-b', css: 'border-bottom-width: 1px;' },
1506
- { class: 'border-l', css: 'border-left-width: 1px;' },
1507
- { class: 'border-{color}', css: 'border-color: {color};' },
1508
- { class: 'border-solid', css: 'border-style: solid;' },
1509
- { class: 'border-dashed', css: 'border-style: dashed;' },
1510
- { class: 'border-dotted', css: 'border-style: dotted;' },
1511
- { class: 'border-double', css: 'border-style: double;' },
1512
- { class: 'border-hidden', css: 'border-style: hidden;' },
1513
- { class: 'border-none', css: 'border-style: none;' },
1514
- { class: 'rounded', css: 'border-radius: 0.25rem;' },
1515
- { class: 'rounded-none', css: 'border-radius: 0px;' },
1516
- { class: 'rounded-sm', css: 'border-radius: 0.125rem;' },
1517
- { class: 'rounded-md', css: 'border-radius: 0.375rem;' },
1518
- { class: 'rounded-lg', css: 'border-radius: 0.5rem;' },
1519
- { class: 'rounded-xl', css: 'border-radius: 0.75rem;' },
1520
- { class: 'rounded-2xl', css: 'border-radius: 1rem;' },
1521
- { class: 'rounded-3xl', css: 'border-radius: 1.5rem;' },
1522
- { class: 'rounded-full', css: 'border-radius: 9999px;' },
1523
- { class: 'divide-x', css: '> * + * { border-left-width: 1px; }' },
1524
- { class: 'divide-y', css: '> * + * { border-top-width: 1px; }' },
1525
- { class: 'divide-{color}', css: '> * + * { border-color: {color}; }' },
1526
- { class: 'ring-{n}', css: 'box-shadow: 0 0 0 {n}px ...;', desc: '0, 1, 2, 4, 8, inset' },
1527
- { class: 'ring-{color}', css: '--tw-ring-color: {color};' },
1528
- { class: 'outline', css: 'outline-style: solid;' },
1529
- { class: 'outline-none', css: 'outline: 2px solid transparent; outline-offset: 2px;' },
1530
- ],
1531
- },
1532
- effects: {
1533
- desc: 'Sombras e opacidade',
1534
- classes: [
1535
- { class: 'shadow-sm', css: 'box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);' },
1536
- { class: 'shadow', css: 'box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);' },
1537
- { class: 'shadow-md', css: 'box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);' },
1538
- { class: 'shadow-lg', css: 'box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);' },
1539
- { class: 'shadow-xl', css: 'box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);' },
1540
- { class: 'shadow-2xl', css: 'box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);' },
1541
- { class: 'shadow-inner', css: 'box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);' },
1542
- { class: 'shadow-none', css: 'box-shadow: 0 0 #0000;' },
1543
- { class: 'shadow-{color}', css: '--tw-shadow-color: {color};' },
1544
- { class: 'opacity-{n}', css: 'opacity: {n/100};', desc: '0, 5, 10, 15, 20, 25, 30, ..., 100' },
1545
- { class: 'mix-blend-{mode}', css: 'mix-blend-mode: {mode};', desc: 'normal, multiply, screen, overlay, darken, lighten, etc.' },
1546
- { class: 'bg-blend-{mode}', css: 'background-blend-mode: {mode};' },
1547
- ],
1548
- },
1549
- filters: {
1550
- desc: 'Filtros CSS',
1551
- classes: [
1552
- { class: 'blur', css: 'filter: blur(8px);' },
1553
- { class: 'blur-sm', css: 'filter: blur(4px);' },
1554
- { class: 'blur-md', css: 'filter: blur(12px);' },
1555
- { class: 'blur-lg', css: 'filter: blur(16px);' },
1556
- { class: 'blur-xl', css: 'filter: blur(24px);' },
1557
- { class: 'blur-2xl', css: 'filter: blur(40px);' },
1558
- { class: 'blur-3xl', css: 'filter: blur(64px);' },
1559
- { class: 'blur-none', css: 'filter: blur(0);' },
1560
- { class: 'brightness-{n}', css: 'filter: brightness({n/100});', desc: '0, 50, 75, 90, 95, 100, 105, 110, 125, 150, 200' },
1561
- { class: 'contrast-{n}', css: 'filter: contrast({n/100});' },
1562
- { class: 'grayscale', css: 'filter: grayscale(100%);' },
1563
- { class: 'grayscale-0', css: 'filter: grayscale(0);' },
1564
- { class: 'hue-rotate-{n}', css: 'filter: hue-rotate({n}deg);', desc: '0, 15, 30, 60, 90, 180' },
1565
- { class: 'invert', css: 'filter: invert(100%);' },
1566
- { class: 'invert-0', css: 'filter: invert(0);' },
1567
- { class: 'saturate-{n}', css: 'filter: saturate({n/100});' },
1568
- { class: 'sepia', css: 'filter: sepia(100%);' },
1569
- { class: 'sepia-0', css: 'filter: sepia(0);' },
1570
- { class: 'backdrop-blur-{n}', css: 'backdrop-filter: blur({value});' },
1571
- { class: 'backdrop-brightness-{n}', css: 'backdrop-filter: brightness({n/100});' },
1572
- { class: 'backdrop-contrast-{n}', css: 'backdrop-filter: contrast({n/100});' },
1573
- { class: 'backdrop-grayscale', css: 'backdrop-filter: grayscale(100%);' },
1574
- { class: 'backdrop-invert', css: 'backdrop-filter: invert(100%);' },
1575
- { class: 'backdrop-opacity-{n}', css: 'backdrop-filter: opacity({n/100});' },
1576
- { class: 'backdrop-saturate-{n}', css: 'backdrop-filter: saturate({n/100});' },
1577
- { class: 'backdrop-sepia', css: 'backdrop-filter: sepia(100%);' },
1578
- ],
1579
- },
1580
- transitions: {
1581
- desc: 'Transições e animações',
1582
- classes: [
1583
- { class: 'transition', css: 'transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms;' },
1584
- { class: 'transition-none', css: 'transition-property: none;' },
1585
- { class: 'transition-all', css: 'transition-property: all;' },
1586
- { class: 'transition-colors', css: 'transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;' },
1587
- { class: 'transition-opacity', css: 'transition-property: opacity;' },
1588
- { class: 'transition-shadow', css: 'transition-property: box-shadow;' },
1589
- { class: 'transition-transform', css: 'transition-property: transform;' },
1590
- { class: 'duration-{n}', css: 'transition-duration: {n}ms;', desc: '0, 75, 100, 150, 200, 300, 500, 700, 1000' },
1591
- { class: 'ease-linear', css: 'transition-timing-function: linear;' },
1592
- { class: 'ease-in', css: 'transition-timing-function: cubic-bezier(0.4, 0, 1, 1);' },
1593
- { class: 'ease-out', css: 'transition-timing-function: cubic-bezier(0, 0, 0.2, 1);' },
1594
- { class: 'ease-in-out', css: 'transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);' },
1595
- { class: 'delay-{n}', css: 'transition-delay: {n}ms;' },
1596
- { class: 'animate-none', css: 'animation: none;' },
1597
- { class: 'animate-spin', css: 'animation: spin 1s linear infinite;' },
1598
- { class: 'animate-ping', css: 'animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;' },
1599
- { class: 'animate-pulse', css: 'animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;' },
1600
- { class: 'animate-bounce', css: 'animation: bounce 1s infinite;' },
1601
- ],
1602
- },
1603
- transforms: {
1604
- desc: 'Transformações CSS',
1605
- classes: [
1606
- { class: 'scale-{n}', css: 'transform: scale({n/100});', desc: '0, 50, 75, 90, 95, 100, 105, 110, 125, 150' },
1607
- { class: 'scale-x-{n}', css: 'transform: scaleX({n/100});' },
1608
- { class: 'scale-y-{n}', css: 'transform: scaleY({n/100});' },
1609
- { class: 'rotate-{n}', css: 'transform: rotate({n}deg);', desc: '0, 1, 2, 3, 6, 12, 45, 90, 180' },
1610
- { class: '-rotate-{n}', css: 'transform: rotate(-{n}deg);' },
1611
- { class: 'translate-x-{n}', css: 'transform: translateX({value});' },
1612
- { class: 'translate-y-{n}', css: 'transform: translateY({value});' },
1613
- { class: '-translate-x-{n}', css: 'transform: translateX(-{value});' },
1614
- { class: '-translate-y-{n}', css: 'transform: translateY(-{value});' },
1615
- { class: 'skew-x-{n}', css: 'transform: skewX({n}deg);', desc: '0, 1, 2, 3, 6, 12' },
1616
- { class: 'skew-y-{n}', css: 'transform: skewY({n}deg);' },
1617
- { class: 'origin-center', css: 'transform-origin: center;' },
1618
- { class: 'origin-top', css: 'transform-origin: top;' },
1619
- { class: 'origin-top-right', css: 'transform-origin: top right;' },
1620
- { class: 'origin-right', css: 'transform-origin: right;' },
1621
- { class: 'origin-bottom-right', css: 'transform-origin: bottom right;' },
1622
- { class: 'origin-bottom', css: 'transform-origin: bottom;' },
1623
- { class: 'origin-bottom-left', css: 'transform-origin: bottom left;' },
1624
- { class: 'origin-left', css: 'transform-origin: left;' },
1625
- { class: 'origin-top-left', css: 'transform-origin: top left;' },
1626
- ],
1627
- },
1628
- interactivity: {
1629
- desc: 'Cursor, scroll, resize',
1630
- classes: [
1631
- { class: 'cursor-auto', css: 'cursor: auto;' },
1632
- { class: 'cursor-default', css: 'cursor: default;' },
1633
- { class: 'cursor-pointer', css: 'cursor: pointer;' },
1634
- { class: 'cursor-wait', css: 'cursor: wait;' },
1635
- { class: 'cursor-text', css: 'cursor: text;' },
1636
- { class: 'cursor-move', css: 'cursor: move;' },
1637
- { class: 'cursor-not-allowed', css: 'cursor: not-allowed;' },
1638
- { class: 'cursor-grab', css: 'cursor: grab;' },
1639
- { class: 'cursor-grabbing', css: 'cursor: grabbing;' },
1640
- { class: 'select-none', css: 'user-select: none;' },
1641
- { class: 'select-text', css: 'user-select: text;' },
1642
- { class: 'select-all', css: 'user-select: all;' },
1643
- { class: 'select-auto', css: 'user-select: auto;' },
1644
- { class: 'resize-none', css: 'resize: none;' },
1645
- { class: 'resize', css: 'resize: both;' },
1646
- { class: 'resize-x', css: 'resize: horizontal;' },
1647
- { class: 'resize-y', css: 'resize: vertical;' },
1648
- { class: 'scroll-auto', css: 'scroll-behavior: auto;' },
1649
- { class: 'scroll-smooth', css: 'scroll-behavior: smooth;' },
1650
- { class: 'snap-start', css: 'scroll-snap-align: start;' },
1651
- { class: 'snap-end', css: 'scroll-snap-align: end;' },
1652
- { class: 'snap-center', css: 'scroll-snap-align: center;' },
1653
- { class: 'snap-none', css: 'scroll-snap-type: none;' },
1654
- { class: 'snap-x', css: 'scroll-snap-type: x var(--tw-scroll-snap-strictness);' },
1655
- { class: 'snap-y', css: 'scroll-snap-type: y var(--tw-scroll-snap-strictness);' },
1656
- { class: 'snap-mandatory', css: '--tw-scroll-snap-strictness: mandatory;' },
1657
- { class: 'snap-proximity', css: '--tw-scroll-snap-strictness: proximity;' },
1658
- { class: 'touch-auto', css: 'touch-action: auto;' },
1659
- { class: 'touch-none', css: 'touch-action: none;' },
1660
- { class: 'touch-manipulation', css: 'touch-action: manipulation;' },
1661
- { class: 'pointer-events-none', css: 'pointer-events: none;' },
1662
- { class: 'pointer-events-auto', css: 'pointer-events: auto;' },
1663
- ],
1664
- },
1665
- svg: {
1666
- desc: 'SVG fill e stroke',
1667
- classes: [
1668
- { class: 'fill-none', css: 'fill: none;' },
1669
- { class: 'fill-inherit', css: 'fill: inherit;' },
1670
- { class: 'fill-current', css: 'fill: currentColor;' },
1671
- { class: 'fill-transparent', css: 'fill: transparent;' },
1672
- { class: 'fill-{color}', css: 'fill: {color};' },
1673
- { class: 'stroke-none', css: 'stroke: none;' },
1674
- { class: 'stroke-inherit', css: 'stroke: inherit;' },
1675
- { class: 'stroke-current', css: 'stroke: currentColor;' },
1676
- { class: 'stroke-transparent', css: 'stroke: transparent;' },
1677
- { class: 'stroke-{color}', css: 'stroke: {color};' },
1678
- { class: 'stroke-{n}', css: 'stroke-width: {n};', desc: '0, 1, 2' },
1679
- ],
1680
- },
1681
- tables: {
1682
- desc: 'Tabelas',
1683
- classes: [
1684
- { class: 'border-collapse', css: 'border-collapse: collapse;' },
1685
- { class: 'border-separate', css: 'border-collapse: separate;' },
1686
- { class: 'border-spacing-{n}', css: 'border-spacing: {value};' },
1687
- { class: 'border-spacing-x-{n}', css: 'border-spacing: {value} 0;' },
1688
- { class: 'border-spacing-y-{n}', css: 'border-spacing: 0 {value};' },
1689
- { class: 'table-auto', css: 'table-layout: auto;' },
1690
- { class: 'table-fixed', css: 'table-layout: fixed;' },
1691
- { class: 'caption-top', css: 'caption-side: top;' },
1692
- { class: 'caption-bottom', css: 'caption-side: bottom;' },
1693
- ],
1694
- },
1695
- accessibility: {
1696
- desc: 'Acessibilidade',
1697
- classes: [
1698
- { class: 'sr-only', css: 'position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;' },
1699
- { class: 'not-sr-only', css: 'position: static; width: auto; height: auto; padding: 0; margin: 0; overflow: visible; clip: auto; white-space: normal;' },
1700
- { class: 'forced-color-adjust-auto', css: 'forced-color-adjust: auto;' },
1701
- { class: 'forced-color-adjust-none', css: 'forced-color-adjust: none;' },
1702
- ],
1703
- },
1704
- };
1705
- if (!categoria) {
1706
- let result = '# 📚 Categorias de Utilities do Tailwind CSS\n\n';
1707
- result += 'Use `tailwind_utilities` com uma categoria específica para ver as classes.\n\n';
1708
- result += '| Categoria | Descrição | Classes |\n';
1709
- result += '|-----------|-----------|--------|\n';
1710
- for (const [key, value] of Object.entries(utilities)) {
1711
- result += `| \`${key}\` | ${value.desc} | ${value.classes.length} |\n`;
1712
- }
1713
- result += '\n**Exemplo:** `tailwind_utilities({ categoria: "flexbox" })`\n';
1714
- return { content: [{ type: 'text', text: result }] };
1715
- }
1716
- const cat = utilities[categoria];
1717
- if (!cat) {
1718
- return {
1719
- content: [{ type: 'text', text: `❌ Categoria não encontrada: ${categoria}\n\nCategorias disponíveis: ${Object.keys(utilities).join(', ')}` }],
1720
- isError: true,
1721
- };
1722
- }
1723
- let result = `# 🎨 Utilities: ${categoria}\n\n`;
1724
- result += `**${cat.desc}**\n\n`;
1725
- result += '| Classe | CSS Gerado | Notas |\n';
1726
- result += '|--------|------------|-------|\n';
1727
- for (const u of cat.classes) {
1728
- const notes = u.desc || '-';
1729
- result += `| \`${u.class}\` | \`${u.css}\` | ${notes} |\n`;
1730
- }
1731
- result += `\n**Total:** ${cat.classes.length} classes\n`;
1732
- return { content: [{ type: 'text', text: result }] };
1733
- }
1734
- case 'tailwind_variants': {
1735
- const tipo = args?.tipo;
1736
- const variants = {
1737
- 'pseudo-classes': {
1738
- desc: 'Estados interativos e de formulário',
1739
- items: [
1740
- { variant: 'hover', desc: 'Mouse sobre o elemento', example: 'hover:bg-blue-500' },
1741
- { variant: 'focus', desc: 'Elemento focado', example: 'focus:ring-2' },
1742
- { variant: 'focus-within', desc: 'Filho tem foco', example: 'focus-within:border-blue-500' },
1743
- { variant: 'focus-visible', desc: 'Foco visível (teclado)', example: 'focus-visible:outline-2' },
1744
- { variant: 'active', desc: 'Clique ativo', example: 'active:bg-blue-700' },
1745
- { variant: 'visited', desc: 'Link visitado', example: 'visited:text-purple-500' },
1746
- { variant: 'target', desc: 'Alvo de âncora', example: 'target:bg-yellow-200' },
1747
- { variant: 'first', desc: 'Primeiro filho', example: 'first:mt-0' },
1748
- { variant: 'last', desc: 'Último filho', example: 'last:mb-0' },
1749
- { variant: 'only', desc: 'Filho único', example: 'only:mx-auto' },
1750
- { variant: 'odd', desc: 'Filhos ímpares', example: 'odd:bg-gray-100' },
1751
- { variant: 'even', desc: 'Filhos pares', example: 'even:bg-gray-50' },
1752
- { variant: 'first-of-type', desc: 'Primeiro do tipo', example: 'first-of-type:pt-0' },
1753
- { variant: 'last-of-type', desc: 'Último do tipo', example: 'last-of-type:pb-0' },
1754
- { variant: 'only-of-type', desc: 'Único do tipo', example: 'only-of-type:mx-auto' },
1755
- { variant: 'empty', desc: 'Sem filhos', example: 'empty:hidden' },
1756
- { variant: 'enabled', desc: 'Input habilitado', example: 'enabled:cursor-pointer' },
1757
- { variant: 'disabled', desc: 'Input desabilitado', example: 'disabled:opacity-50' },
1758
- { variant: 'checked', desc: 'Checkbox/radio marcado', example: 'checked:bg-blue-500' },
1759
- { variant: 'indeterminate', desc: 'Estado indeterminado', example: 'indeterminate:bg-gray-300' },
1760
- { variant: 'default', desc: 'Opção padrão', example: 'default:ring-2' },
1761
- { variant: 'required', desc: 'Campo obrigatório', example: 'required:border-red-500' },
1762
- { variant: 'valid', desc: 'Input válido', example: 'valid:border-green-500' },
1763
- { variant: 'invalid', desc: 'Input inválido', example: 'invalid:border-red-500' },
1764
- { variant: 'in-range', desc: 'Valor no range', example: 'in-range:border-green-500' },
1765
- { variant: 'out-of-range', desc: 'Valor fora do range', example: 'out-of-range:border-red-500' },
1766
- { variant: 'placeholder-shown', desc: 'Placeholder visível', example: 'placeholder-shown:border-gray-300' },
1767
- { variant: 'autofill', desc: 'Preenchido pelo browser', example: 'autofill:bg-yellow-100' },
1768
- { variant: 'read-only', desc: 'Campo somente leitura', example: 'read-only:bg-gray-100' },
1769
- ],
1770
- },
1771
- 'pseudo-elements': {
1772
- desc: 'Pseudo-elementos CSS',
1773
- items: [
1774
- { variant: 'before', desc: 'Pseudo-elemento ::before', example: 'before:content-[""] before:absolute' },
1775
- { variant: 'after', desc: 'Pseudo-elemento ::after', example: 'after:content-["✓"] after:ml-2' },
1776
- { variant: 'placeholder', desc: 'Texto do placeholder', example: 'placeholder:text-gray-400' },
1777
- { variant: 'file', desc: 'Botão de input file', example: 'file:bg-blue-500 file:text-white' },
1778
- { variant: 'marker', desc: 'Marcador de lista', example: 'marker:text-blue-500' },
1779
- { variant: 'selection', desc: 'Texto selecionado', example: 'selection:bg-blue-200' },
1780
- { variant: 'first-line', desc: 'Primeira linha', example: 'first-line:font-bold' },
1781
- { variant: 'first-letter', desc: 'Primeira letra', example: 'first-letter:text-4xl' },
1782
- { variant: 'backdrop', desc: 'Backdrop de dialog', example: 'backdrop:bg-black/50' },
1783
- ],
1784
- },
1785
- responsive: {
1786
- desc: 'Breakpoints responsivos (mobile-first)',
1787
- items: [
1788
- { variant: 'sm', desc: '≥640px', example: 'sm:flex sm:flex-row' },
1789
- { variant: 'md', desc: '≥768px', example: 'md:grid md:grid-cols-2' },
1790
- { variant: 'lg', desc: '≥1024px', example: 'lg:grid-cols-3' },
1791
- { variant: 'xl', desc: '≥1280px', example: 'xl:grid-cols-4' },
1792
- { variant: '2xl', desc: '≥1536px', example: '2xl:max-w-7xl' },
1793
- { variant: 'min-[{n}px]', desc: 'Breakpoint customizado', example: 'min-[320px]:text-sm' },
1794
- { variant: 'max-sm', desc: '<640px', example: 'max-sm:hidden' },
1795
- { variant: 'max-md', desc: '<768px', example: 'max-md:flex-col' },
1796
- { variant: 'max-lg', desc: '<1024px', example: 'max-lg:px-4' },
1797
- { variant: 'max-xl', desc: '<1280px', example: 'max-xl:grid-cols-2' },
1798
- { variant: 'max-2xl', desc: '<1536px', example: 'max-2xl:container' },
1799
- { variant: 'max-[{n}px]', desc: 'Max breakpoint custom', example: 'max-[600px]:text-xs' },
1800
- { variant: '@sm', desc: 'Container query ≥320px', example: '@sm:flex' },
1801
- { variant: '@md', desc: 'Container query ≥384px', example: '@md:grid-cols-2' },
1802
- { variant: '@lg', desc: 'Container query ≥512px', example: '@lg:p-6' },
1803
- { variant: '@xl', desc: 'Container query ≥672px', example: '@xl:text-lg' },
1804
- { variant: '@[{n}px]', desc: 'Container query custom', example: '@[400px]:flex-row' },
1805
- ],
1806
- },
1807
- 'dark-mode': {
1808
- desc: 'Modo escuro e preferências de mídia',
1809
- items: [
1810
- { variant: 'dark', desc: 'Modo escuro', example: 'dark:bg-gray-900 dark:text-white' },
1811
- { variant: 'motion-safe', desc: 'Animações permitidas', example: 'motion-safe:animate-bounce' },
1812
- { variant: 'motion-reduce', desc: 'Animações reduzidas', example: 'motion-reduce:animate-none' },
1813
- { variant: 'contrast-more', desc: 'Alto contraste', example: 'contrast-more:border-2' },
1814
- { variant: 'contrast-less', desc: 'Baixo contraste', example: 'contrast-less:opacity-80' },
1815
- { variant: 'print', desc: 'Impressão', example: 'print:hidden print:text-black' },
1816
- { variant: 'portrait', desc: 'Orientação retrato', example: 'portrait:flex-col' },
1817
- { variant: 'landscape', desc: 'Orientação paisagem', example: 'landscape:flex-row' },
1818
- ],
1819
- },
1820
- state: {
1821
- desc: 'Estados especiais',
1822
- items: [
1823
- { variant: 'open', desc: 'Elemento open (details, dialog)', example: 'open:bg-white open:shadow-lg' },
1824
- { variant: 'closed', desc: 'Elemento fechado', example: 'closed:opacity-0' },
1825
- { variant: 'modal', desc: 'Dialog modal', example: 'modal:backdrop:bg-black/50' },
1826
- { variant: 'fullscreen', desc: 'Modo fullscreen', example: 'fullscreen:p-0' },
1827
- { variant: 'starting', desc: 'Estado inicial (v4)', example: 'starting:opacity-0' },
1828
- { variant: 'inert', desc: 'Elemento inert', example: 'inert:opacity-50' },
1829
- ],
1830
- },
1831
- compound: {
1832
- desc: 'Variants compostos (group, peer, has)',
1833
- items: [
1834
- { variant: 'group-hover', desc: 'Hover no elemento pai .group', example: 'group-hover:text-blue-500' },
1835
- { variant: 'group-focus', desc: 'Focus no elemento pai .group', example: 'group-focus:ring-2' },
1836
- { variant: 'group-active', desc: 'Active no elemento pai .group', example: 'group-active:scale-95' },
1837
- { variant: 'group-[.custom]', desc: 'Seletor custom no group', example: 'group-[.is-open]:block' },
1838
- { variant: 'peer-hover', desc: 'Hover no irmão .peer', example: 'peer-hover:visible' },
1839
- { variant: 'peer-focus', desc: 'Focus no irmão .peer', example: 'peer-focus:ring-2' },
1840
- { variant: 'peer-checked', desc: 'Peer checkbox marcado', example: 'peer-checked:bg-blue-500' },
1841
- { variant: 'peer-invalid', desc: 'Peer input inválido', example: 'peer-invalid:text-red-500' },
1842
- { variant: 'peer-[.custom]', desc: 'Seletor custom no peer', example: 'peer-[.is-active]:font-bold' },
1843
- { variant: 'has-[selector]', desc: 'Contém elemento (v4)', example: 'has-[input:focus]:ring-2' },
1844
- { variant: 'has-checked', desc: 'Contém checkbox marcado', example: 'has-checked:bg-blue-100' },
1845
- { variant: 'in-[selector]', desc: 'Está dentro de (v4)', example: 'in-[.dark]:text-white' },
1846
- { variant: 'not-[selector]', desc: 'Negação (v4)', example: 'not-[.active]:opacity-50' },
1847
- ],
1848
- },
1849
- aria: {
1850
- desc: 'Atributos ARIA para acessibilidade',
1851
- items: [
1852
- { variant: 'aria-checked', desc: 'aria-checked="true"', example: 'aria-checked:bg-blue-500' },
1853
- { variant: 'aria-disabled', desc: 'aria-disabled="true"', example: 'aria-disabled:opacity-50' },
1854
- { variant: 'aria-expanded', desc: 'aria-expanded="true"', example: 'aria-expanded:rotate-180' },
1855
- { variant: 'aria-hidden', desc: 'aria-hidden="true"', example: 'aria-hidden:invisible' },
1856
- { variant: 'aria-pressed', desc: 'aria-pressed="true"', example: 'aria-pressed:bg-gray-700' },
1857
- { variant: 'aria-selected', desc: 'aria-selected="true"', example: 'aria-selected:border-blue-500' },
1858
- { variant: 'aria-required', desc: 'aria-required="true"', example: 'aria-required:border-red-500' },
1859
- { variant: 'aria-invalid', desc: 'aria-invalid="true"', example: 'aria-invalid:border-red-500' },
1860
- { variant: 'aria-busy', desc: 'aria-busy="true"', example: 'aria-busy:animate-pulse' },
1861
- { variant: 'aria-[attr=value]', desc: 'ARIA customizado', example: 'aria-[current=page]:font-bold' },
1862
- ],
1863
- },
1864
- data: {
1865
- desc: 'Atributos data-*',
1866
- items: [
1867
- { variant: 'data-[state=open]', desc: 'data-state="open"', example: 'data-[state=open]:bg-white' },
1868
- { variant: 'data-[state=closed]', desc: 'data-state="closed"', example: 'data-[state=closed]:hidden' },
1869
- { variant: 'data-[active]', desc: 'data-active presente', example: 'data-[active]:font-bold' },
1870
- { variant: 'data-[disabled]', desc: 'data-disabled presente', example: 'data-[disabled]:opacity-50' },
1871
- { variant: 'data-[selected=true]', desc: 'data-selected="true"', example: 'data-[selected=true]:bg-blue-100' },
1872
- { variant: 'data-[orientation=vertical]', desc: 'Orientação vertical', example: 'data-[orientation=vertical]:flex-col' },
1873
- { variant: 'data-[side=left]', desc: 'Posição lado', example: 'data-[side=left]:mr-2' },
1874
- ],
1875
- },
1876
- };
1877
- if (!tipo) {
1878
- let result = '# 🎯 Variants do Tailwind CSS\n\n';
1879
- result += 'Variants são modificadores que aplicam estilos condicionalmente.\n\n';
1880
- result += '**Sintaxe:** `variant:classe` → `hover:bg-blue-500`\n\n';
1881
- result += '**Empilhamento:** `variant1:variant2:classe` → `dark:hover:bg-blue-600`\n\n';
1882
- result += '| Tipo | Descrição | Variants |\n';
1883
- result += '|------|-----------|----------|\n';
1884
- for (const [key, value] of Object.entries(variants)) {
1885
- result += `| \`${key}\` | ${value.desc} | ${value.items.length} |\n`;
1886
- }
1887
- result += '\n**Exemplo:** `tailwind_variants({ tipo: "responsive" })`\n';
1888
- return { content: [{ type: 'text', text: result }] };
1889
- }
1890
- const varType = variants[tipo];
1891
- if (!varType) {
1892
- return {
1893
- content: [{ type: 'text', text: `❌ Tipo não encontrado: ${tipo}\n\nTipos disponíveis: ${Object.keys(variants).join(', ')}` }],
1894
- isError: true,
1895
- };
1896
- }
1897
- let result = `# 🎯 Variants: ${tipo}\n\n`;
1898
- result += `**${varType.desc}**\n\n`;
1899
- result += '| Variant | Descrição | Exemplo |\n';
1900
- result += '|---------|-----------|----------|\n';
1901
- for (const v of varType.items) {
1902
- result += `| \`${v.variant}:\` | ${v.desc} | \`${v.example}\` |\n`;
1903
- }
1904
- result += `\n**Total:** ${varType.items.length} variants\n`;
1905
- return { content: [{ type: 'text', text: result }] };
1906
- }
1907
- case 'tailwind_cores': {
1908
- const corArg = args?.cor;
1909
- const colors = {
1910
- slate: { '50': '#f8fafc', '100': '#f1f5f9', '200': '#e2e8f0', '300': '#cbd5e1', '400': '#94a3b8', '500': '#64748b', '600': '#475569', '700': '#334155', '800': '#1e293b', '900': '#0f172a', '950': '#020617' },
1911
- gray: { '50': '#f9fafb', '100': '#f3f4f6', '200': '#e5e7eb', '300': '#d1d5db', '400': '#9ca3af', '500': '#6b7280', '600': '#4b5563', '700': '#374151', '800': '#1f2937', '900': '#111827', '950': '#030712' },
1912
- zinc: { '50': '#fafafa', '100': '#f4f4f5', '200': '#e4e4e7', '300': '#d4d4d8', '400': '#a1a1aa', '500': '#71717a', '600': '#52525b', '700': '#3f3f46', '800': '#27272a', '900': '#18181b', '950': '#09090b' },
1913
- neutral: { '50': '#fafafa', '100': '#f5f5f5', '200': '#e5e5e5', '300': '#d4d4d4', '400': '#a3a3a3', '500': '#737373', '600': '#525252', '700': '#404040', '800': '#262626', '900': '#171717', '950': '#0a0a0a' },
1914
- stone: { '50': '#fafaf9', '100': '#f5f5f4', '200': '#e7e5e4', '300': '#d6d3d1', '400': '#a8a29e', '500': '#78716c', '600': '#57534e', '700': '#44403c', '800': '#292524', '900': '#1c1917', '950': '#0c0a09' },
1915
- red: { '50': '#fef2f2', '100': '#fee2e2', '200': '#fecaca', '300': '#fca5a5', '400': '#f87171', '500': '#ef4444', '600': '#dc2626', '700': '#b91c1c', '800': '#991b1b', '900': '#7f1d1d', '950': '#450a0a' },
1916
- orange: { '50': '#fff7ed', '100': '#ffedd5', '200': '#fed7aa', '300': '#fdba74', '400': '#fb923c', '500': '#f97316', '600': '#ea580c', '700': '#c2410c', '800': '#9a3412', '900': '#7c2d12', '950': '#431407' },
1917
- amber: { '50': '#fffbeb', '100': '#fef3c7', '200': '#fde68a', '300': '#fcd34d', '400': '#fbbf24', '500': '#f59e0b', '600': '#d97706', '700': '#b45309', '800': '#92400e', '900': '#78350f', '950': '#451a03' },
1918
- yellow: { '50': '#fefce8', '100': '#fef9c3', '200': '#fef08a', '300': '#fde047', '400': '#facc15', '500': '#eab308', '600': '#ca8a04', '700': '#a16207', '800': '#854d0e', '900': '#713f12', '950': '#422006' },
1919
- lime: { '50': '#f7fee7', '100': '#ecfccb', '200': '#d9f99d', '300': '#bef264', '400': '#a3e635', '500': '#84cc16', '600': '#65a30d', '700': '#4d7c0f', '800': '#3f6212', '900': '#365314', '950': '#1a2e05' },
1920
- green: { '50': '#f0fdf4', '100': '#dcfce7', '200': '#bbf7d0', '300': '#86efac', '400': '#4ade80', '500': '#22c55e', '600': '#16a34a', '700': '#15803d', '800': '#166534', '900': '#14532d', '950': '#052e16' },
1921
- emerald: { '50': '#ecfdf5', '100': '#d1fae5', '200': '#a7f3d0', '300': '#6ee7b7', '400': '#34d399', '500': '#10b981', '600': '#059669', '700': '#047857', '800': '#065f46', '900': '#064e3b', '950': '#022c22' },
1922
- teal: { '50': '#f0fdfa', '100': '#ccfbf1', '200': '#99f6e4', '300': '#5eead4', '400': '#2dd4bf', '500': '#14b8a6', '600': '#0d9488', '700': '#0f766e', '800': '#115e59', '900': '#134e4a', '950': '#042f2e' },
1923
- cyan: { '50': '#ecfeff', '100': '#cffafe', '200': '#a5f3fc', '300': '#67e8f9', '400': '#22d3ee', '500': '#06b6d4', '600': '#0891b2', '700': '#0e7490', '800': '#155e75', '900': '#164e63', '950': '#083344' },
1924
- sky: { '50': '#f0f9ff', '100': '#e0f2fe', '200': '#bae6fd', '300': '#7dd3fc', '400': '#38bdf8', '500': '#0ea5e9', '600': '#0284c7', '700': '#0369a1', '800': '#075985', '900': '#0c4a6e', '950': '#082f49' },
1925
- blue: { '50': '#eff6ff', '100': '#dbeafe', '200': '#bfdbfe', '300': '#93c5fd', '400': '#60a5fa', '500': '#3b82f6', '600': '#2563eb', '700': '#1d4ed8', '800': '#1e40af', '900': '#1e3a8a', '950': '#172554' },
1926
- indigo: { '50': '#eef2ff', '100': '#e0e7ff', '200': '#c7d2fe', '300': '#a5b4fc', '400': '#818cf8', '500': '#6366f1', '600': '#4f46e5', '700': '#4338ca', '800': '#3730a3', '900': '#312e81', '950': '#1e1b4b' },
1927
- violet: { '50': '#f5f3ff', '100': '#ede9fe', '200': '#ddd6fe', '300': '#c4b5fd', '400': '#a78bfa', '500': '#8b5cf6', '600': '#7c3aed', '700': '#6d28d9', '800': '#5b21b6', '900': '#4c1d95', '950': '#2e1065' },
1928
- purple: { '50': '#faf5ff', '100': '#f3e8ff', '200': '#e9d5ff', '300': '#d8b4fe', '400': '#c084fc', '500': '#a855f7', '600': '#9333ea', '700': '#7e22ce', '800': '#6b21a8', '900': '#581c87', '950': '#3b0764' },
1929
- fuchsia: { '50': '#fdf4ff', '100': '#fae8ff', '200': '#f5d0fe', '300': '#f0abfc', '400': '#e879f9', '500': '#d946ef', '600': '#c026d3', '700': '#a21caf', '800': '#86198f', '900': '#701a75', '950': '#4a044e' },
1930
- pink: { '50': '#fdf2f8', '100': '#fce7f3', '200': '#fbcfe8', '300': '#f9a8d4', '400': '#f472b6', '500': '#ec4899', '600': '#db2777', '700': '#be185d', '800': '#9d174d', '900': '#831843', '950': '#500724' },
1931
- rose: { '50': '#fff1f2', '100': '#ffe4e6', '200': '#fecdd3', '300': '#fda4af', '400': '#fb7185', '500': '#f43f5e', '600': '#e11d48', '700': '#be123c', '800': '#9f1239', '900': '#881337', '950': '#4c0519' },
1932
- };
1933
- const specialColors = {
1934
- inherit: 'Herda do pai',
1935
- current: 'currentColor',
1936
- transparent: 'transparent',
1937
- black: '#000000',
1938
- white: '#ffffff',
1939
- };
1940
- if (!corArg) {
1941
- let result = '# 🎨 Paleta de Cores do Tailwind CSS\n\n';
1942
- result += '## Cores Especiais\n\n';
1943
- result += '| Classe | Valor |\n';
1944
- result += '|--------|-------|\n';
1945
- for (const [name, value] of Object.entries(specialColors)) {
1946
- result += `| \`{type}-${name}\` | ${value} |\n`;
1947
- }
1948
- result += '\n## Paleta Completa\n\n';
1949
- result += 'Use `tailwind_cores({ cor: "blue" })` para ver uma cor específica.\n\n';
1950
- result += '| Cor | Preview (500) | Escalas |\n';
1951
- result += '|-----|---------------|--------|\n';
1952
- for (const [name, shades] of Object.entries(colors)) {
1953
- result += `| \`${name}\` | ${shades['500']} | 50-950 |\n`;
1954
- }
1955
- result += '\n**Uso:** `text-{cor}-{escala}`, `bg-{cor}-{escala}`, `border-{cor}-{escala}`\n';
1956
- result += '\n**Exemplo:** `bg-blue-500`, `text-gray-900`, `border-red-300`\n';
1957
- return { content: [{ type: 'text', text: result }] };
1958
- }
1959
- const colorShades = colors[corArg];
1960
- if (!colorShades) {
1961
- return {
1962
- content: [{ type: 'text', text: `❌ Cor não encontrada: ${corArg}\n\nCores disponíveis: ${Object.keys(colors).join(', ')}` }],
1963
- isError: true,
1964
- };
1965
- }
1966
- let result = `# 🎨 Cor: ${corArg}\n\n`;
1967
- result += '| Escala | Hex | Classes |\n';
1968
- result += '|--------|-----|--------|\n';
1969
- for (const [shade, hex] of Object.entries(colorShades)) {
1970
- result += `| ${shade} | ${hex} | \`text-${corArg}-${shade}\` \`bg-${corArg}-${shade}\` \`border-${corArg}-${shade}\` |\n`;
1971
- }
1972
- result += `\n**Exemplos de uso:**\n`;
1973
- result += '```html\n';
1974
- result += `<div class="bg-${corArg}-500 text-white">Background</div>\n`;
1975
- result += `<p class="text-${corArg}-700">Texto</p>\n`;
1976
- result += `<div class="border border-${corArg}-300">Border</div>\n`;
1977
- result += `<div class="ring-2 ring-${corArg}-500">Ring</div>\n`;
1978
- result += '```\n';
1979
- return { content: [{ type: 'text', text: result }] };
1980
- }
1981
- case 'tailwind_spacing': {
1982
- const spacing = [
1983
- { key: '0', rem: '0', px: '0px' },
1984
- { key: 'px', rem: '1px', px: '1px' },
1985
- { key: '0.5', rem: '0.125rem', px: '2px' },
1986
- { key: '1', rem: '0.25rem', px: '4px' },
1987
- { key: '1.5', rem: '0.375rem', px: '6px' },
1988
- { key: '2', rem: '0.5rem', px: '8px' },
1989
- { key: '2.5', rem: '0.625rem', px: '10px' },
1990
- { key: '3', rem: '0.75rem', px: '12px' },
1991
- { key: '3.5', rem: '0.875rem', px: '14px' },
1992
- { key: '4', rem: '1rem', px: '16px' },
1993
- { key: '5', rem: '1.25rem', px: '20px' },
1994
- { key: '6', rem: '1.5rem', px: '24px' },
1995
- { key: '7', rem: '1.75rem', px: '28px' },
1996
- { key: '8', rem: '2rem', px: '32px' },
1997
- { key: '9', rem: '2.25rem', px: '36px' },
1998
- { key: '10', rem: '2.5rem', px: '40px' },
1999
- { key: '11', rem: '2.75rem', px: '44px' },
2000
- { key: '12', rem: '3rem', px: '48px' },
2001
- { key: '14', rem: '3.5rem', px: '56px' },
2002
- { key: '16', rem: '4rem', px: '64px' },
2003
- { key: '20', rem: '5rem', px: '80px' },
2004
- { key: '24', rem: '6rem', px: '96px' },
2005
- { key: '28', rem: '7rem', px: '112px' },
2006
- { key: '32', rem: '8rem', px: '128px' },
2007
- { key: '36', rem: '9rem', px: '144px' },
2008
- { key: '40', rem: '10rem', px: '160px' },
2009
- { key: '44', rem: '11rem', px: '176px' },
2010
- { key: '48', rem: '12rem', px: '192px' },
2011
- { key: '52', rem: '13rem', px: '208px' },
2012
- { key: '56', rem: '14rem', px: '224px' },
2013
- { key: '60', rem: '15rem', px: '240px' },
2014
- { key: '64', rem: '16rem', px: '256px' },
2015
- { key: '72', rem: '18rem', px: '288px' },
2016
- { key: '80', rem: '20rem', px: '320px' },
2017
- { key: '96', rem: '24rem', px: '384px' },
2018
- ];
2019
- let result = '# 📏 Escala de Espaçamento do Tailwind CSS\n\n';
2020
- result += 'A escala de spacing é usada para margin, padding, gap, width, height, e outras propriedades.\n\n';
2021
- result += '| Valor | Rem | Pixels | Exemplo Classes |\n';
2022
- result += '|-------|-----|--------|----------------|\n';
2023
- for (const s of spacing) {
2024
- result += `| \`${s.key}\` | ${s.rem} | ${s.px} | \`p-${s.key}\` \`m-${s.key}\` \`gap-${s.key}\` \`w-${s.key}\` |\n`;
2025
- }
2026
- result += '\n## Valores Especiais\n\n';
2027
- result += '| Valor | Descrição | Exemplo |\n';
2028
- result += '|-------|-----------|--------|\n';
2029
- result += '| `auto` | auto | `m-auto`, `ml-auto` |\n';
2030
- result += '| `full` | 100% | `w-full`, `h-full` |\n';
2031
- result += '| `screen` | 100vw/100vh | `w-screen`, `h-screen` |\n';
2032
- result += '| `svh/lvh/dvh` | viewport units | `h-svh`, `h-lvh`, `h-dvh` |\n';
2033
- result += '| `min` | min-content | `w-min`, `h-min` |\n';
2034
- result += '| `max` | max-content | `w-max`, `h-max` |\n';
2035
- result += '| `fit` | fit-content | `w-fit`, `h-fit` |\n';
2036
- result += '\n## Frações (Width/Basis)\n\n';
2037
- result += '| Valor | CSS | Exemplo |\n';
2038
- result += '|-------|-----|--------|\n';
2039
- result += '| `1/2` | 50% | `w-1/2`, `basis-1/2` |\n';
2040
- result += '| `1/3` | 33.333% | `w-1/3`, `basis-1/3` |\n';
2041
- result += '| `2/3` | 66.666% | `w-2/3`, `basis-2/3` |\n';
2042
- result += '| `1/4` | 25% | `w-1/4`, `basis-1/4` |\n';
2043
- result += '| `3/4` | 75% | `w-3/4`, `basis-3/4` |\n';
2044
- result += '| `1/5` | 20% | `w-1/5`, `basis-1/5` |\n';
2045
- result += '| `2/5` | 40% | `w-2/5`, `basis-2/5` |\n';
2046
- result += '| `3/5` | 60% | `w-3/5`, `basis-3/5` |\n';
2047
- result += '| `4/5` | 80% | `w-4/5`, `basis-4/5` |\n';
2048
- result += '| `1/6` | 16.666% | `w-1/6`, `basis-1/6` |\n';
2049
- result += '| `5/6` | 83.333% | `w-5/6`, `basis-5/6` |\n';
2050
- result += '| `1/12` | 8.333% | `w-1/12`, `basis-1/12` |\n';
2051
- return { content: [{ type: 'text', text: result }] };
2052
- }
2053
- case 'tailwind_breakpoints': {
2054
- let result = '# 📱 Breakpoints Responsivos do Tailwind CSS\n\n';
2055
- result += '## Breakpoints Padrão (Mobile-First)\n\n';
2056
- result += '| Prefixo | Min-Width | CSS Media Query |\n';
2057
- result += '|---------|-----------|----------------|\n';
2058
- result += '| `sm:` | 640px | `@media (min-width: 640px)` |\n';
2059
- result += '| `md:` | 768px | `@media (min-width: 768px)` |\n';
2060
- result += '| `lg:` | 1024px | `@media (min-width: 1024px)` |\n';
2061
- result += '| `xl:` | 1280px | `@media (min-width: 1280px)` |\n';
2062
- result += '| `2xl:` | 1536px | `@media (min-width: 1536px)` |\n';
2063
- result += '\n## Max-Width Variants\n\n';
2064
- result += '| Prefixo | Max-Width | CSS Media Query |\n';
2065
- result += '|---------|-----------|----------------|\n';
2066
- result += '| `max-sm:` | <640px | `@media (max-width: 639px)` |\n';
2067
- result += '| `max-md:` | <768px | `@media (max-width: 767px)` |\n';
2068
- result += '| `max-lg:` | <1024px | `@media (max-width: 1023px)` |\n';
2069
- result += '| `max-xl:` | <1280px | `@media (max-width: 1279px)` |\n';
2070
- result += '| `max-2xl:` | <1536px | `@media (max-width: 1535px)` |\n';
2071
- result += '\n## Breakpoints Arbitrários\n\n';
2072
- result += '```html\n';
2073
- result += '<!-- Min-width customizado -->\n';
2074
- result += '<div class="min-[320px]:text-sm min-[480px]:text-base">\n\n';
2075
- result += '<!-- Max-width customizado -->\n';
2076
- result += '<div class="max-[600px]:hidden">\n';
2077
- result += '```\n';
2078
- result += '\n## Container Queries (v4)\n\n';
2079
- result += '| Prefixo | Container Width | Uso |\n';
2080
- result += '|---------|----------------|-----|\n';
2081
- result += '| `@xs:` | ≥320px | `@xs:flex-row` |\n';
2082
- result += '| `@sm:` | ≥384px | `@sm:grid-cols-2` |\n';
2083
- result += '| `@md:` | ≥448px | `@md:p-6` |\n';
2084
- result += '| `@lg:` | ≥512px | `@lg:text-lg` |\n';
2085
- result += '| `@xl:` | ≥576px | `@xl:gap-8` |\n';
2086
- result += '| `@2xl:` | ≥672px | `@2xl:grid-cols-4` |\n';
2087
- result += '\n```html\n';
2088
- result += '<!-- Uso de container queries -->\n';
2089
- result += '<div class="@container">\n';
2090
- result += ' <div class="@sm:flex @lg:grid @lg:grid-cols-2">\n';
2091
- result += ' <!-- Responde ao tamanho do container pai -->\n';
2092
- result += ' </div>\n';
2093
- result += '</div>\n\n';
2094
- result += '<!-- Container query arbitrário -->\n';
2095
- result += '<div class="@[400px]:flex-row">\n';
2096
- result += '```\n';
2097
- result += '\n## Exemplo Responsivo Completo\n\n';
2098
- result += '```html\n';
2099
- result += '<div class="\n';
2100
- result += ' flex flex-col /* Mobile: coluna */\n';
2101
- result += ' sm:flex-row /* ≥640px: linha */\n';
2102
- result += ' gap-2 sm:gap-4 /* Gap responsivo */\n';
2103
- result += ' p-4 md:p-6 lg:p-8 /* Padding responsivo */\n';
2104
- result += '">\n';
2105
- result += ' <div class="w-full sm:w-1/2 lg:w-1/3">Item 1</div>\n';
2106
- result += ' <div class="w-full sm:w-1/2 lg:w-1/3">Item 2</div>\n';
2107
- result += ' <div class="hidden lg:block lg:w-1/3">Item 3</div>\n';
2108
- result += '</div>\n';
2109
- result += '```\n';
2110
- return { content: [{ type: 'text', text: result }] };
2111
- }
2112
- case 'tailwind_receitas': {
2113
- const componente = args?.componente;
2114
- const receitas = {
2115
- button: {
2116
- desc: 'Botões com variantes',
2117
- html: `<!-- Botão Primário -->
2118
- <button class="px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
2119
- Botão Primário
2120
- </button>
2121
-
2122
- <!-- Botão Secundário -->
2123
- <button class="px-4 py-2 bg-gray-200 text-gray-800 font-medium rounded-lg hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors">
2124
- Botão Secundário
2125
- </button>
2126
-
2127
- <!-- Botão Outline -->
2128
- <button class="px-4 py-2 border-2 border-blue-600 text-blue-600 font-medium rounded-lg hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
2129
- Botão Outline
2130
- </button>
2131
-
2132
- <!-- Botão com Ícone -->
2133
- <button class="inline-flex items-center gap-2 px-4 py-2 bg-green-600 text-white font-medium rounded-lg hover:bg-green-700">
2134
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2135
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
2136
- </svg>
2137
- Confirmar
2138
- </button>
2139
-
2140
- <!-- Botão Disabled -->
2141
- <button disabled class="px-4 py-2 bg-gray-400 text-gray-200 font-medium rounded-lg cursor-not-allowed opacity-50">
2142
- Desabilitado
2143
- </button>
2144
-
2145
- <!-- Botão Loading -->
2146
- <button class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg" disabled>
2147
- <svg class="animate-spin h-5 w-5" viewBox="0 0 24 24">
2148
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"/>
2149
- <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
2150
- </svg>
2151
- Carregando...
2152
- </button>`,
2153
- },
2154
- card: {
2155
- desc: 'Cards com imagem, conteúdo e ações',
2156
- html: `<!-- Card Básico -->
2157
- <div class="max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
2158
- <img class="w-full h-48 object-cover" src="image.jpg" alt="Card image">
2159
- <div class="p-6">
2160
- <h3 class="text-xl font-bold text-gray-900 mb-2">Título do Card</h3>
2161
- <p class="text-gray-600 mb-4">Descrição breve do conteúdo do card.</p>
2162
- <a href="#" class="text-blue-600 hover:text-blue-800 font-medium">Saiba mais →</a>
2163
- </div>
2164
- </div>
2165
-
2166
- <!-- Card Horizontal -->
2167
- <div class="flex max-w-2xl bg-white rounded-xl shadow-md overflow-hidden">
2168
- <img class="w-48 object-cover" src="image.jpg" alt="">
2169
- <div class="p-6 flex flex-col justify-between">
2170
- <div>
2171
- <span class="text-sm text-blue-600 font-semibold">Categoria</span>
2172
- <h3 class="text-xl font-bold text-gray-900 mt-1">Título do Card</h3>
2173
- <p class="text-gray-600 mt-2">Descrição do conteúdo.</p>
2174
- </div>
2175
- <div class="flex items-center gap-4 mt-4">
2176
- <button class="px-4 py-2 bg-blue-600 text-white rounded-lg">Ação</button>
2177
- </div>
2178
- </div>
2179
- </div>
2180
-
2181
- <!-- Card com Footer -->
2182
- <div class="max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
2183
- <div class="p-6">
2184
- <h3 class="text-xl font-bold text-gray-900">Título</h3>
2185
- <p class="text-gray-600 mt-2">Conteúdo do card.</p>
2186
- </div>
2187
- <div class="px-6 py-4 bg-gray-50 border-t flex justify-end gap-2">
2188
- <button class="px-4 py-2 text-gray-600 hover:text-gray-800">Cancelar</button>
2189
- <button class="px-4 py-2 bg-blue-600 text-white rounded-lg">Salvar</button>
2190
- </div>
2191
- </div>`,
2192
- },
2193
- form: {
2194
- desc: 'Formulário completo com validação visual',
2195
- html: `<form class="max-w-md mx-auto space-y-6">
2196
- <!-- Input com Label -->
2197
- <div>
2198
- <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
2199
- <input type="email" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors" placeholder="seu@email.com">
2200
- </div>
2201
-
2202
- <!-- Input com Erro -->
2203
- <div>
2204
- <label class="block text-sm font-medium text-gray-700 mb-1">Senha</label>
2205
- <input type="password" class="w-full px-4 py-2 border border-red-500 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 outline-none">
2206
- <p class="mt-1 text-sm text-red-500">Senha deve ter no mínimo 8 caracteres</p>
2207
- </div>
2208
-
2209
- <!-- Select -->
2210
- <div>
2211
- <label class="block text-sm font-medium text-gray-700 mb-1">País</label>
2212
- <select class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none bg-white">
2213
- <option>Brasil</option>
2214
- <option>Portugal</option>
2215
- <option>EUA</option>
2216
- </select>
2217
- </div>
2218
-
2219
- <!-- Checkbox -->
2220
- <div class="flex items-center gap-2">
2221
- <input type="checkbox" id="terms" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
2222
- <label for="terms" class="text-sm text-gray-700">Aceito os termos de uso</label>
2223
- </div>
2224
-
2225
- <!-- Submit -->
2226
- <button type="submit" class="w-full px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors">
2227
- Enviar
2228
- </button>
2229
- </form>`,
2230
- },
2231
- input: {
2232
- desc: 'Campos de input com variantes',
2233
- html: `<!-- Input Padrão -->
2234
- <input type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none" placeholder="Digite aqui...">
2235
-
2236
- <!-- Input com Ícone à Esquerda -->
2237
- <div class="relative">
2238
- <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
2239
- <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2240
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
2241
- </svg>
2242
- </div>
2243
- <input type="search" class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" placeholder="Buscar...">
2244
- </div>
2245
-
2246
- <!-- Input com Botão -->
2247
- <div class="flex">
2248
- <input type="email" class="flex-1 px-4 py-2 border border-r-0 border-gray-300 rounded-l-lg focus:ring-2 focus:ring-blue-500" placeholder="seu@email.com">
2249
- <button class="px-4 py-2 bg-blue-600 text-white rounded-r-lg hover:bg-blue-700">Inscrever</button>
2250
- </div>
2251
-
2252
- <!-- Textarea -->
2253
- <textarea rows="4" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 resize-none" placeholder="Sua mensagem..."></textarea>`,
2254
- },
2255
- modal: {
2256
- desc: 'Modal/Dialog com backdrop',
2257
- html: `<!-- Modal Container -->
2258
- <div class="fixed inset-0 z-50 flex items-center justify-center">
2259
- <!-- Backdrop -->
2260
- <div class="fixed inset-0 bg-black/50 backdrop-blur-sm"></div>
2261
-
2262
- <!-- Modal -->
2263
- <div class="relative bg-white rounded-xl shadow-2xl w-full max-w-md mx-4 overflow-hidden">
2264
- <!-- Header -->
2265
- <div class="flex items-center justify-between px-6 py-4 border-b">
2266
- <h3 class="text-lg font-semibold text-gray-900">Título do Modal</h3>
2267
- <button class="p-1 hover:bg-gray-100 rounded-lg">
2268
- <svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2269
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
2270
- </svg>
2271
- </button>
2272
- </div>
2273
-
2274
- <!-- Body -->
2275
- <div class="px-6 py-4">
2276
- <p class="text-gray-600">Conteúdo do modal aqui...</p>
2277
- </div>
2278
-
2279
- <!-- Footer -->
2280
- <div class="flex justify-end gap-2 px-6 py-4 bg-gray-50 border-t">
2281
- <button class="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg">Cancelar</button>
2282
- <button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Confirmar</button>
2283
- </div>
2284
- </div>
2285
- </div>`,
2286
- },
2287
- navbar: {
2288
- desc: 'Navbar responsiva',
2289
- html: `<nav class="bg-white shadow-md">
2290
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
2291
- <div class="flex justify-between h-16">
2292
- <!-- Logo -->
2293
- <div class="flex items-center">
2294
- <a href="#" class="text-xl font-bold text-blue-600">Logo</a>
2295
- </div>
2296
-
2297
- <!-- Desktop Menu -->
2298
- <div class="hidden md:flex items-center gap-8">
2299
- <a href="#" class="text-gray-600 hover:text-blue-600">Home</a>
2300
- <a href="#" class="text-gray-600 hover:text-blue-600">Sobre</a>
2301
- <a href="#" class="text-gray-600 hover:text-blue-600">Serviços</a>
2302
- <a href="#" class="text-gray-600 hover:text-blue-600">Contato</a>
2303
- <button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Login</button>
2304
- </div>
2305
-
2306
- <!-- Mobile Menu Button -->
2307
- <div class="md:hidden flex items-center">
2308
- <button class="p-2 rounded-lg hover:bg-gray-100">
2309
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2310
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
2311
- </svg>
2312
- </button>
2313
- </div>
2314
- </div>
2315
- </div>
2316
-
2317
- <!-- Mobile Menu (toggle com JS) -->
2318
- <div class="md:hidden border-t">
2319
- <div class="px-4 py-2 space-y-1">
2320
- <a href="#" class="block py-2 text-gray-600">Home</a>
2321
- <a href="#" class="block py-2 text-gray-600">Sobre</a>
2322
- <a href="#" class="block py-2 text-gray-600">Serviços</a>
2323
- <a href="#" class="block py-2 text-gray-600">Contato</a>
2324
- </div>
2325
- </div>
2326
- </nav>`,
2327
- },
2328
- footer: {
2329
- desc: 'Footer com múltiplas colunas',
2330
- html: `<footer class="bg-gray-900 text-gray-300">
2331
- <div class="max-w-7xl mx-auto px-4 py-12 sm:px-6 lg:px-8">
2332
- <div class="grid grid-cols-1 md:grid-cols-4 gap-8">
2333
- <!-- Brand -->
2334
- <div>
2335
- <h3 class="text-white text-lg font-bold mb-4">Empresa</h3>
2336
- <p class="text-sm">Descrição breve da empresa ou produto.</p>
2337
- </div>
2338
-
2339
- <!-- Links -->
2340
- <div>
2341
- <h4 class="text-white font-semibold mb-4">Produto</h4>
2342
- <ul class="space-y-2 text-sm">
2343
- <li><a href="#" class="hover:text-white">Features</a></li>
2344
- <li><a href="#" class="hover:text-white">Preços</a></li>
2345
- <li><a href="#" class="hover:text-white">FAQ</a></li>
2346
- </ul>
2347
- </div>
2348
-
2349
- <div>
2350
- <h4 class="text-white font-semibold mb-4">Empresa</h4>
2351
- <ul class="space-y-2 text-sm">
2352
- <li><a href="#" class="hover:text-white">Sobre</a></li>
2353
- <li><a href="#" class="hover:text-white">Blog</a></li>
2354
- <li><a href="#" class="hover:text-white">Carreiras</a></li>
2355
- </ul>
2356
- </div>
2357
-
2358
- <div>
2359
- <h4 class="text-white font-semibold mb-4">Legal</h4>
2360
- <ul class="space-y-2 text-sm">
2361
- <li><a href="#" class="hover:text-white">Privacidade</a></li>
2362
- <li><a href="#" class="hover:text-white">Termos</a></li>
2363
- </ul>
2364
- </div>
2365
- </div>
2366
-
2367
- <div class="border-t border-gray-800 mt-8 pt-8 flex flex-col md:flex-row justify-between items-center">
2368
- <p class="text-sm">© 2024 Empresa. Todos os direitos reservados.</p>
2369
- <div class="flex gap-4 mt-4 md:mt-0">
2370
- <a href="#" class="hover:text-white">Twitter</a>
2371
- <a href="#" class="hover:text-white">GitHub</a>
2372
- <a href="#" class="hover:text-white">LinkedIn</a>
2373
- </div>
2374
- </div>
2375
- </div>
2376
- </footer>`,
2377
- },
2378
- hero: {
2379
- desc: 'Hero section para landing pages',
2380
- html: `<!-- Hero com Background -->
2381
- <section class="relative bg-gradient-to-br from-blue-600 to-purple-700 text-white">
2382
- <div class="max-w-7xl mx-auto px-4 py-24 sm:px-6 lg:px-8">
2383
- <div class="text-center">
2384
- <h1 class="text-4xl md:text-6xl font-bold mb-6">
2385
- Título Impactante
2386
- </h1>
2387
- <p class="text-xl md:text-2xl text-blue-100 mb-8 max-w-2xl mx-auto">
2388
- Subtítulo explicando o valor do seu produto ou serviço.
2389
- </p>
2390
- <div class="flex flex-col sm:flex-row gap-4 justify-center">
2391
- <button class="px-8 py-3 bg-white text-blue-600 font-semibold rounded-lg hover:bg-blue-50">
2392
- Começar Agora
2393
- </button>
2394
- <button class="px-8 py-3 border-2 border-white text-white font-semibold rounded-lg hover:bg-white/10">
2395
- Saiba Mais
2396
- </button>
2397
- </div>
2398
- </div>
2399
- </div>
2400
- </section>
2401
-
2402
- <!-- Hero com Imagem -->
2403
- <section class="bg-white">
2404
- <div class="max-w-7xl mx-auto px-4 py-16 sm:px-6 lg:px-8">
2405
- <div class="grid md:grid-cols-2 gap-12 items-center">
2406
- <div>
2407
- <h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
2408
- Título Principal
2409
- </h1>
2410
- <p class="text-xl text-gray-600 mb-8">
2411
- Descrição do produto com benefícios claros para o usuário.
2412
- </p>
2413
- <button class="px-8 py-3 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700">
2414
- Call to Action
2415
- </button>
2416
- </div>
2417
- <div>
2418
- <img src="hero-image.png" alt="Hero" class="rounded-xl shadow-2xl">
2419
- </div>
2420
- </div>
2421
- </div>
2422
- </section>`,
2423
- },
2424
- grid: {
2425
- desc: 'Grid responsivo para layouts',
2426
- html: `<!-- Grid de 3 colunas responsivo -->
2427
- <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
2428
- <div class="p-6 bg-white rounded-lg shadow">Item 1</div>
2429
- <div class="p-6 bg-white rounded-lg shadow">Item 2</div>
2430
- <div class="p-6 bg-white rounded-lg shadow">Item 3</div>
2431
- </div>
2432
-
2433
- <!-- Grid de 4 colunas com span -->
2434
- <div class="grid grid-cols-4 gap-4">
2435
- <div class="col-span-4 md:col-span-2 lg:col-span-1 p-4 bg-blue-100 rounded">1</div>
2436
- <div class="col-span-4 md:col-span-2 lg:col-span-1 p-4 bg-blue-200 rounded">2</div>
2437
- <div class="col-span-4 md:col-span-2 lg:col-span-1 p-4 bg-blue-300 rounded">3</div>
2438
- <div class="col-span-4 md:col-span-2 lg:col-span-1 p-4 bg-blue-400 rounded">4</div>
2439
- </div>
2440
-
2441
- <!-- Grid de 12 colunas (dashboard) -->
2442
- <div class="grid grid-cols-12 gap-4">
2443
- <div class="col-span-12 lg:col-span-8 p-6 bg-white rounded-lg shadow">Conteúdo Principal</div>
2444
- <div class="col-span-12 lg:col-span-4 p-6 bg-white rounded-lg shadow">Sidebar</div>
2445
- <div class="col-span-12 md:col-span-6 lg:col-span-4 p-6 bg-white rounded-lg shadow">Card 1</div>
2446
- <div class="col-span-12 md:col-span-6 lg:col-span-4 p-6 bg-white rounded-lg shadow">Card 2</div>
2447
- <div class="col-span-12 md:col-span-12 lg:col-span-4 p-6 bg-white rounded-lg shadow">Card 3</div>
2448
- </div>
2449
-
2450
- <!-- Auto-fit Grid -->
2451
- <div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
2452
- <div class="p-6 bg-white rounded-lg shadow">Auto 1</div>
2453
- <div class="p-6 bg-white rounded-lg shadow">Auto 2</div>
2454
- <div class="p-6 bg-white rounded-lg shadow">Auto 3</div>
2455
- <div class="p-6 bg-white rounded-lg shadow">Auto 4</div>
2456
- </div>`,
2457
- },
2458
- alert: {
2459
- desc: 'Alertas e notificações',
2460
- html: `<!-- Alert Info -->
2461
- <div class="flex items-center gap-3 p-4 bg-blue-50 border border-blue-200 text-blue-800 rounded-lg">
2462
- <svg class="w-5 h-5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
2463
- <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
2464
- </svg>
2465
- <p>Informação importante para o usuário.</p>
2466
- </div>
2467
-
2468
- <!-- Alert Success -->
2469
- <div class="flex items-center gap-3 p-4 bg-green-50 border border-green-200 text-green-800 rounded-lg">
2470
- <svg class="w-5 h-5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
2471
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
2472
- </svg>
2473
- <p>Operação realizada com sucesso!</p>
2474
- </div>
2475
-
2476
- <!-- Alert Warning -->
2477
- <div class="flex items-center gap-3 p-4 bg-yellow-50 border border-yellow-200 text-yellow-800 rounded-lg">
2478
- <svg class="w-5 h-5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
2479
- <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
2480
- </svg>
2481
- <p>Atenção! Verifique os dados antes de continuar.</p>
2482
- </div>
2483
-
2484
- <!-- Alert Error -->
2485
- <div class="flex items-center gap-3 p-4 bg-red-50 border border-red-200 text-red-800 rounded-lg">
2486
- <svg class="w-5 h-5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
2487
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
2488
- </svg>
2489
- <p>Erro! Algo deu errado. Tente novamente.</p>
2490
- </div>
2491
-
2492
- <!-- Alert Dismissible -->
2493
- <div class="flex items-center justify-between gap-3 p-4 bg-blue-50 border border-blue-200 text-blue-800 rounded-lg">
2494
- <p>Notificação que pode ser fechada.</p>
2495
- <button class="p-1 hover:bg-blue-100 rounded">
2496
- <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
2497
- <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
2498
- </svg>
2499
- </button>
2500
- </div>`,
2501
- },
2502
- badge: {
2503
- desc: 'Badges e tags',
2504
- html: `<!-- Badges Coloridos -->
2505
- <span class="px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-full">Novo</span>
2506
- <span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">Ativo</span>
2507
- <span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">Pendente</span>
2508
- <span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded-full">Urgente</span>
2509
- <span class="px-2 py-1 text-xs font-medium bg-gray-100 text-gray-800 rounded-full">Default</span>
2510
-
2511
- <!-- Badge com Dot -->
2512
- <span class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">
2513
- <span class="w-2 h-2 bg-green-500 rounded-full"></span>
2514
- Online
2515
- </span>
2516
-
2517
- <!-- Badge Pill -->
2518
- <span class="px-3 py-1 text-sm font-semibold bg-purple-600 text-white rounded-full">PRO</span>
2519
-
2520
- <!-- Badge com Ícone -->
2521
- <span class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded">
2522
- <svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
2523
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
2524
- </svg>
2525
- Verificado
2526
- </span>`,
2527
- },
2528
- avatar: {
2529
- desc: 'Avatares e fotos de perfil',
2530
- html: `<!-- Avatar Circular -->
2531
- <img class="w-12 h-12 rounded-full object-cover" src="avatar.jpg" alt="Avatar">
2532
-
2533
- <!-- Avatar com Iniciais -->
2534
- <div class="w-12 h-12 rounded-full bg-blue-500 flex items-center justify-center text-white font-semibold">
2535
- JD
2536
- </div>
2537
-
2538
- <!-- Avatar com Status -->
2539
- <div class="relative">
2540
- <img class="w-12 h-12 rounded-full object-cover" src="avatar.jpg" alt="">
2541
- <span class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 border-2 border-white rounded-full"></span>
2542
- </div>
2543
-
2544
- <!-- Avatar Group -->
2545
- <div class="flex -space-x-2">
2546
- <img class="w-10 h-10 rounded-full border-2 border-white" src="avatar1.jpg" alt="">
2547
- <img class="w-10 h-10 rounded-full border-2 border-white" src="avatar2.jpg" alt="">
2548
- <img class="w-10 h-10 rounded-full border-2 border-white" src="avatar3.jpg" alt="">
2549
- <div class="w-10 h-10 rounded-full border-2 border-white bg-gray-200 flex items-center justify-center text-sm text-gray-600">+5</div>
2550
- </div>
2551
-
2552
- <!-- Avatar Tamanhos -->
2553
- <img class="w-8 h-8 rounded-full" src="avatar.jpg" alt="XS">
2554
- <img class="w-10 h-10 rounded-full" src="avatar.jpg" alt="SM">
2555
- <img class="w-12 h-12 rounded-full" src="avatar.jpg" alt="MD">
2556
- <img class="w-16 h-16 rounded-full" src="avatar.jpg" alt="LG">
2557
- <img class="w-20 h-20 rounded-full" src="avatar.jpg" alt="XL">`,
2558
- },
2559
- dropdown: {
2560
- desc: 'Dropdown menu',
2561
- html: `<!-- Dropdown Container -->
2562
- <div class="relative inline-block">
2563
- <!-- Trigger Button -->
2564
- <button class="inline-flex items-center gap-2 px-4 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">
2565
- Opções
2566
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2567
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
2568
- </svg>
2569
- </button>
2570
-
2571
- <!-- Dropdown Menu -->
2572
- <div class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1 z-10">
2573
- <a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">Editar</a>
2574
- <a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">Duplicar</a>
2575
- <a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">Arquivar</a>
2576
- <hr class="my-1 border-gray-200">
2577
- <a href="#" class="block px-4 py-2 text-red-600 hover:bg-red-50">Excluir</a>
2578
- </div>
2579
- </div>
2580
-
2581
- <!-- Dropdown com Ícones -->
2582
- <div class="w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1">
2583
- <a href="#" class="flex items-center gap-3 px-4 py-2 text-gray-700 hover:bg-gray-100">
2584
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2585
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
2586
- </svg>
2587
- Editar
2588
- </a>
2589
- <a href="#" class="flex items-center gap-3 px-4 py-2 text-gray-700 hover:bg-gray-100">
2590
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2591
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
2592
- </svg>
2593
- Duplicar
2594
- </a>
2595
- </div>`,
2596
- },
2597
- tabs: {
2598
- desc: 'Abas de navegação',
2599
- html: `<!-- Tabs Underline -->
2600
- <div class="border-b border-gray-200">
2601
- <nav class="flex gap-8">
2602
- <a href="#" class="py-4 px-1 border-b-2 border-blue-500 text-blue-600 font-medium">Tab Ativa</a>
2603
- <a href="#" class="py-4 px-1 border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">Tab 2</a>
2604
- <a href="#" class="py-4 px-1 border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">Tab 3</a>
2605
- </nav>
2606
- </div>
2607
-
2608
- <!-- Tabs Pills -->
2609
- <div class="flex gap-2 bg-gray-100 p-1 rounded-lg">
2610
- <button class="px-4 py-2 bg-white text-gray-900 rounded-md shadow-sm font-medium">Tab Ativa</button>
2611
- <button class="px-4 py-2 text-gray-600 hover:text-gray-900 rounded-md font-medium">Tab 2</button>
2612
- <button class="px-4 py-2 text-gray-600 hover:text-gray-900 rounded-md font-medium">Tab 3</button>
2613
- </div>
2614
-
2615
- <!-- Tabs com Ícones -->
2616
- <div class="flex border-b border-gray-200">
2617
- <a href="#" class="flex items-center gap-2 py-4 px-4 border-b-2 border-blue-500 text-blue-600">
2618
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2619
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
2620
- </svg>
2621
- Home
2622
- </a>
2623
- <a href="#" class="flex items-center gap-2 py-4 px-4 text-gray-500 hover:text-gray-700">
2624
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2625
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
2626
- </svg>
2627
- Perfil
2628
- </a>
2629
- </div>`,
2630
- },
2631
- breadcrumb: {
2632
- desc: 'Breadcrumb de navegação',
2633
- html: `<!-- Breadcrumb Simples -->
2634
- <nav class="flex" aria-label="Breadcrumb">
2635
- <ol class="flex items-center gap-2">
2636
- <li>
2637
- <a href="#" class="text-gray-500 hover:text-gray-700">Home</a>
2638
- </li>
2639
- <li class="text-gray-400">/</li>
2640
- <li>
2641
- <a href="#" class="text-gray-500 hover:text-gray-700">Produtos</a>
2642
- </li>
2643
- <li class="text-gray-400">/</li>
2644
- <li>
2645
- <span class="text-gray-900 font-medium">Detalhes</span>
2646
- </li>
2647
- </ol>
2648
- </nav>
2649
-
2650
- <!-- Breadcrumb com Chevron -->
2651
- <nav class="flex" aria-label="Breadcrumb">
2652
- <ol class="flex items-center">
2653
- <li>
2654
- <a href="#" class="text-gray-500 hover:text-gray-700">
2655
- <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
2656
- <path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/>
2657
- </svg>
2658
- </a>
2659
- </li>
2660
- <li class="flex items-center">
2661
- <svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
2662
- <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
2663
- </svg>
2664
- <a href="#" class="ml-2 text-gray-500 hover:text-gray-700">Categoria</a>
2665
- </li>
2666
- <li class="flex items-center">
2667
- <svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
2668
- <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
2669
- </svg>
2670
- <span class="ml-2 text-gray-900 font-medium">Página Atual</span>
2671
- </li>
2672
- </ol>
2673
- </nav>`,
2674
- },
2675
- pagination: {
2676
- desc: 'Paginação',
2677
- html: `<!-- Paginação Simples -->
2678
- <nav class="flex items-center gap-1">
2679
- <button class="px-3 py-2 text-gray-500 hover:bg-gray-100 rounded-lg disabled:opacity-50" disabled>
2680
- Anterior
2681
- </button>
2682
- <button class="px-3 py-2 bg-blue-600 text-white rounded-lg">1</button>
2683
- <button class="px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-lg">2</button>
2684
- <button class="px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-lg">3</button>
2685
- <span class="px-3 py-2 text-gray-500">...</span>
2686
- <button class="px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-lg">10</button>
2687
- <button class="px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-lg">
2688
- Próximo
2689
- </button>
2690
- </nav>
2691
-
2692
- <!-- Paginação com Ícones -->
2693
- <nav class="flex items-center gap-1">
2694
- <button class="p-2 text-gray-500 hover:bg-gray-100 rounded-lg">
2695
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2696
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
2697
- </svg>
2698
- </button>
2699
- <button class="w-10 h-10 bg-blue-600 text-white rounded-lg">1</button>
2700
- <button class="w-10 h-10 text-gray-700 hover:bg-gray-100 rounded-lg">2</button>
2701
- <button class="w-10 h-10 text-gray-700 hover:bg-gray-100 rounded-lg">3</button>
2702
- <button class="p-2 text-gray-500 hover:bg-gray-100 rounded-lg">
2703
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2704
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
2705
- </svg>
2706
- </button>
2707
- </nav>`,
2708
- },
2709
- skeleton: {
2710
- desc: 'Skeleton loaders',
2711
- html: `<!-- Skeleton de Texto -->
2712
- <div class="animate-pulse space-y-3">
2713
- <div class="h-4 bg-gray-200 rounded w-3/4"></div>
2714
- <div class="h-4 bg-gray-200 rounded"></div>
2715
- <div class="h-4 bg-gray-200 rounded w-5/6"></div>
2716
- </div>
2717
-
2718
- <!-- Skeleton de Card -->
2719
- <div class="animate-pulse">
2720
- <div class="bg-gray-200 h-48 rounded-t-lg"></div>
2721
- <div class="p-4 space-y-3">
2722
- <div class="h-4 bg-gray-200 rounded w-3/4"></div>
2723
- <div class="h-4 bg-gray-200 rounded"></div>
2724
- <div class="h-4 bg-gray-200 rounded w-1/2"></div>
2725
- </div>
2726
- </div>
2727
-
2728
- <!-- Skeleton de Avatar + Texto -->
2729
- <div class="animate-pulse flex items-center gap-4">
2730
- <div class="w-12 h-12 bg-gray-200 rounded-full"></div>
2731
- <div class="flex-1 space-y-2">
2732
- <div class="h-4 bg-gray-200 rounded w-1/4"></div>
2733
- <div class="h-3 bg-gray-200 rounded w-1/2"></div>
2734
- </div>
2735
- </div>
2736
-
2737
- <!-- Skeleton de Lista -->
2738
- <div class="animate-pulse space-y-4">
2739
- <div class="flex items-center gap-4">
2740
- <div class="w-10 h-10 bg-gray-200 rounded"></div>
2741
- <div class="flex-1 space-y-2">
2742
- <div class="h-4 bg-gray-200 rounded w-3/4"></div>
2743
- <div class="h-3 bg-gray-200 rounded w-1/2"></div>
2744
- </div>
2745
- </div>
2746
- <div class="flex items-center gap-4">
2747
- <div class="w-10 h-10 bg-gray-200 rounded"></div>
2748
- <div class="flex-1 space-y-2">
2749
- <div class="h-4 bg-gray-200 rounded w-2/3"></div>
2750
- <div class="h-3 bg-gray-200 rounded w-1/3"></div>
2751
- </div>
2752
- </div>
2753
- </div>`,
2754
- },
2755
- };
2756
- if (!componente) {
2757
- return {
2758
- content: [{ type: 'text', text: `❌ Parâmetro 'componente' é obrigatório.\n\nComponentes disponíveis: ${Object.keys(receitas).join(', ')}` }],
2759
- isError: true,
2760
- };
2761
- }
2762
- const receita = receitas[componente];
2763
- if (!receita) {
2764
- return {
2765
- content: [{ type: 'text', text: `❌ Componente não encontrado: ${componente}\n\nComponentes disponíveis: ${Object.keys(receitas).join(', ')}` }],
2766
- isError: true,
2767
- };
2768
- }
2769
- let result = `# 🍳 Receita: ${componente}\n\n`;
2770
- result += `**${receita.desc}**\n\n`;
2771
- result += '```html\n';
2772
- result += receita.html;
2773
- result += '\n```\n';
2774
- return { content: [{ type: 'text', text: result }] };
2775
- }
2776
- case 'tailwind_migracao_v4': {
2777
- const topico = args?.topico;
2778
- const migracaoContent = {
2779
- overview: `# 🚀 Migração Tailwind CSS v3 → v4
2780
-
2781
- ## Principais Mudanças
2782
-
2783
- ### 1. CSS-First Configuration
2784
- O Tailwind v4 usa configuração via CSS ao invés de JavaScript:
2785
-
2786
- \`\`\`css
2787
- /* v4: Configuração em CSS */
2788
- @import "tailwindcss";
2789
-
2790
- @theme {
2791
- --color-primary: oklch(0.6 0.2 250);
2792
- --font-display: "Inter", sans-serif;
2793
- }
2794
- \`\`\`
2795
-
2796
- ### 2. Nova Sintaxe de Import
2797
- \`\`\`css
2798
- /* v3 */
2799
- @tailwind base;
2800
- @tailwind components;
2801
- @tailwind utilities;
2802
-
2803
- /* v4 */
2804
- @import "tailwindcss";
2805
- \`\`\`
2806
-
2807
- ### 3. Plugins via CSS
2808
- \`\`\`css
2809
- /* v4 */
2810
- @import "tailwindcss";
2811
- @plugin "@tailwindcss/typography";
2812
- @plugin "@tailwindcss/forms";
2813
- \`\`\`
2814
-
2815
- ### 4. Novas Features
2816
- - Container Queries nativas
2817
- - \`@starting-style\` para animações
2818
- - Variantes \`in-*\`, \`has-*\`, \`not-*\`
2819
- - Cores em OKLCH
2820
- - Performance 10x mais rápida
2821
-
2822
- ### 5. Breaking Changes Importantes
2823
- - \`text-opacity-*\` → usar modificador de cor \`/opacity\`
2824
- - \`bg-opacity-*\` → usar modificador de cor \`/opacity\`
2825
- - Algumas classes renomeadas`,
2826
- 'css-first': `# 📝 CSS-First Configuration (v4)
2827
-
2828
- ## Configuração no CSS
2829
-
2830
- O v4 elimina o \`tailwind.config.js\` para a maioria dos casos:
2831
-
2832
- \`\`\`css
2833
- @import "tailwindcss";
2834
-
2835
- /* Customização de tema */
2836
- @theme {
2837
- /* Cores customizadas */
2838
- --color-brand: oklch(0.6 0.2 250);
2839
- --color-accent: oklch(0.7 0.15 150);
2840
-
2841
- /* Fontes */
2842
- --font-display: "Cal Sans", sans-serif;
2843
- --font-body: "Inter", sans-serif;
2844
-
2845
- /* Spacing customizado */
2846
- --spacing-18: 4.5rem;
2847
- --spacing-88: 22rem;
2848
-
2849
- /* Breakpoints customizados */
2850
- --breakpoint-3xl: 1920px;
2851
-
2852
- /* Border radius */
2853
- --radius-4xl: 2rem;
2854
-
2855
- /* Shadows */
2856
- --shadow-glow: 0 0 20px oklch(0.6 0.2 250 / 0.5);
2857
- }
2858
- \`\`\`
2859
-
2860
- ## Vantagens
2861
- - Tipagem automática das variáveis CSS
2862
- - Intellisense melhorado
2863
- - Menor bundle size
2864
- - Mais rápido para compilar`,
2865
- 'theme-config': `# 🎨 Configuração de Tema (v4)
2866
-
2867
- ## Variáveis de Tema
2868
-
2869
- \`\`\`css
2870
- @theme {
2871
- /* === CORES === */
2872
- /* Substitui colors no config JS */
2873
- --color-*: valor;
2874
-
2875
- /* Exemplo */
2876
- --color-primary-50: oklch(0.97 0.01 250);
2877
- --color-primary-500: oklch(0.6 0.2 250);
2878
- --color-primary-900: oklch(0.3 0.1 250);
2879
-
2880
- /* === TIPOGRAFIA === */
2881
- --font-sans: "Inter", system-ui, sans-serif;
2882
- --font-mono: "Fira Code", monospace;
2883
-
2884
- --text-xs: 0.75rem;
2885
- --text-xs--line-height: 1rem;
2886
-
2887
- /* === SPACING === */
2888
- --spacing-*: valor;
2889
- --spacing-13: 3.25rem;
2890
-
2891
- /* === BREAKPOINTS === */
2892
- --breakpoint-sm: 640px;
2893
- --breakpoint-md: 768px;
2894
- --breakpoint-3xl: 1920px;
2895
-
2896
- /* === RADIUS === */
2897
- --radius-sm: 0.25rem;
2898
- --radius-xl: 1rem;
2899
-
2900
- /* === SHADOWS === */
2901
- --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
2902
- --shadow-xl: 0 20px 25px rgb(0 0 0 / 0.1);
2903
-
2904
- /* === ANIMAÇÕES === */
2905
- --animate-spin: spin 1s linear infinite;
2906
- --animate-custom: myAnimation 2s ease-in-out;
2907
- }
2908
-
2909
- @keyframes myAnimation {
2910
- from { opacity: 0; }
2911
- to { opacity: 1; }
2912
- }
2913
- \`\`\``,
2914
- utilities: `# 🔧 Mudanças em Utilities (v4)
2915
-
2916
- ## Classes Renomeadas
2917
-
2918
- | v3 | v4 | Motivo |
2919
- |----|----|--------|
2920
- | \`shadow-sm\` | \`shadow-xs\` | Mais consistente |
2921
- | \`shadow\` | \`shadow-sm\` | Escala ajustada |
2922
- | \`drop-shadow-sm\` | \`drop-shadow-xs\` | Consistência |
2923
- | \`blur-sm\` | \`blur-xs\` | Consistência |
2924
- | \`rounded-sm\` | \`rounded-xs\` | Consistência |
2925
-
2926
- ## Opacidade Inline
2927
-
2928
- \`\`\`html
2929
- <!-- v3 (deprecated) -->
2930
- <div class="bg-blue-500 bg-opacity-50">
2931
-
2932
- <!-- v4 (novo) -->
2933
- <div class="bg-blue-500/50">
2934
- \`\`\`
2935
-
2936
- ## Novas Utilities
2937
-
2938
- \`\`\`html
2939
- <!-- Size (width + height) -->
2940
- <div class="size-10"> <!-- w-10 h-10 -->
2941
-
2942
- <!-- Inset shortcuts -->
2943
- <div class="inset-x-4"> <!-- left-4 right-4 -->
2944
- <div class="inset-y-4"> <!-- top-4 bottom-4 -->
2945
-
2946
- <!-- Logical properties -->
2947
- <div class="ps-4"> <!-- padding-inline-start -->
2948
- <div class="pe-4"> <!-- padding-inline-end -->
2949
- <div class="ms-4"> <!-- margin-inline-start -->
2950
- <div class="me-4"> <!-- margin-inline-end -->
2951
- \`\`\``,
2952
- variants: `# 🎯 Novos Variants (v4)
2953
-
2954
- ## Container Queries
2955
-
2956
- \`\`\`html
2957
- <div class="@container">
2958
- <div class="@sm:flex @lg:grid @lg:grid-cols-2">
2959
- <!-- Responde ao tamanho do container -->
2960
- </div>
2961
- </div>
2962
-
2963
- <!-- Named containers -->
2964
- <div class="@container/sidebar">
2965
- <div class="@lg/sidebar:block">
2966
- \`\`\`
2967
-
2968
- ## Variants Compostos
2969
-
2970
- \`\`\`html
2971
- <!-- has-* (parent has child) -->
2972
- <div class="has-[input:focus]:ring-2">
2973
- <input type="text">
2974
- </div>
2975
-
2976
- <!-- in-* (is inside) -->
2977
- <div class="in-[.dark]:text-white">
2978
-
2979
- <!-- not-* (negation) -->
2980
- <div class="not-[.active]:opacity-50">
2981
- \`\`\`
2982
-
2983
- ## Starting Style
2984
-
2985
- \`\`\`html
2986
- <!-- Animação de entrada -->
2987
- <div class="
2988
- opacity-100 transition-opacity
2989
- starting:opacity-0
2990
- ">
2991
- \`\`\`
2992
-
2993
- ## Novos State Variants
2994
-
2995
- \`\`\`html
2996
- <!-- Inert state -->
2997
- <div class="inert:opacity-50" inert>
2998
-
2999
- <!-- Open/closed (details, dialog) -->
3000
- <details class="open:bg-white">
3001
- <summary>Click me</summary>
3002
- </details>
3003
- \`\`\``,
3004
- plugins: `# 🔌 Plugins no v4
3005
-
3006
- ## Import via CSS
3007
-
3008
- \`\`\`css
3009
- @import "tailwindcss";
3010
-
3011
- /* Plugins oficiais */
3012
- @plugin "@tailwindcss/typography";
3013
- @plugin "@tailwindcss/forms";
3014
- @plugin "@tailwindcss/aspect-ratio";
3015
- @plugin "@tailwindcss/container-queries";
3016
-
3017
- /* Plugin customizado local */
3018
- @plugin "./my-plugin.js";
3019
- \`\`\`
3020
-
3021
- ## Criando Plugin (v4)
3022
-
3023
- \`\`\`js
3024
- // my-plugin.js
3025
- export default function({ addUtilities, theme }) {
3026
- addUtilities({
3027
- '.text-shadow': {
3028
- 'text-shadow': '2px 2px 4px rgb(0 0 0 / 0.1)',
3029
- },
3030
- '.text-shadow-lg': {
3031
- 'text-shadow': '4px 4px 8px rgb(0 0 0 / 0.2)',
3032
- },
3033
- })
3034
- }
3035
- \`\`\`
3036
-
3037
- ## Diferenças do v3
3038
-
3039
- | v3 | v4 |
3040
- |----|----|
3041
- | \`plugins: [require(...)]\` | \`@plugin "..."\` |
3042
- | CommonJS | ES Modules |
3043
- | \`tailwind.config.js\` | CSS direto |`,
3044
- 'breaking-changes': `# ⚠️ Breaking Changes (v3 → v4)
3045
-
3046
- ## Classes Removidas/Alteradas
3047
-
3048
- ### Opacidade Separada (REMOVIDO)
3049
- \`\`\`html
3050
- <!-- ❌ NÃO funciona no v4 -->
3051
- <div class="bg-blue-500 bg-opacity-50">
3052
- <div class="text-red-500 text-opacity-75">
3053
-
3054
- <!-- ✅ Use modificador inline -->
3055
- <div class="bg-blue-500/50">
3056
- <div class="text-red-500/75">
3057
- \`\`\`
3058
-
3059
- ### Transform Utilities
3060
- \`\`\`html
3061
- <!-- ❌ v3 (removido) -->
3062
- <div class="transform scale-50">
3063
-
3064
- <!-- ✅ v4 (automático) -->
3065
- <div class="scale-50">
3066
- \`\`\`
3067
-
3068
- ### Filter Utilities
3069
- \`\`\`html
3070
- <!-- ❌ v3 (removido) -->
3071
- <div class="filter blur-sm">
3072
-
3073
- <!-- ✅ v4 (automático) -->
3074
- <div class="blur-sm">
3075
- \`\`\`
3076
-
3077
- ### Ring Width Default
3078
- \`\`\`html
3079
- <!-- v3: ring = 3px -->
3080
- <!-- v4: ring = 1px -->
3081
-
3082
- <!-- Para manter 3px no v4 -->
3083
- <div class="ring-3">
3084
- \`\`\`
3085
-
3086
- ## Configuração
3087
-
3088
- \`\`\`js
3089
- // ❌ v3 tailwind.config.js (não necessário no v4)
3090
- module.exports = {
3091
- content: ['./src/**/*.{html,js}'],
3092
- theme: { extend: {} },
3093
- plugins: [],
3094
- }
3095
- \`\`\`
3096
-
3097
- \`\`\`css
3098
- /* ✅ v4 - tudo no CSS */
3099
- @import "tailwindcss";
3100
- @source "./src/**/*.{html,js}";
3101
- \`\`\``,
3102
- 'postcss-vite': `# 🛠️ Setup PostCSS e Vite (v4)
3103
-
3104
- ## Vite (Recomendado)
3105
-
3106
- \`\`\`bash
3107
- npm install tailwindcss @tailwindcss/vite
3108
- \`\`\`
3109
-
3110
- \`\`\`js
3111
- // vite.config.js
3112
- import tailwindcss from '@tailwindcss/vite'
3113
-
3114
- export default {
3115
- plugins: [tailwindcss()],
3116
- }
3117
- \`\`\`
3118
-
3119
- \`\`\`css
3120
- /* main.css */
3121
- @import "tailwindcss";
3122
- \`\`\`
3123
-
3124
- ## PostCSS
3125
-
3126
- \`\`\`bash
3127
- npm install tailwindcss @tailwindcss/postcss
3128
- \`\`\`
3129
-
3130
- \`\`\`js
3131
- // postcss.config.js
3132
- export default {
3133
- plugins: {
3134
- '@tailwindcss/postcss': {},
3135
- },
3136
- }
3137
- \`\`\`
3138
-
3139
- ## CLI Standalone
3140
-
3141
- \`\`\`bash
3142
- npm install tailwindcss @tailwindcss/cli
3143
- npx @tailwindcss/cli -i input.css -o output.css --watch
3144
- \`\`\`
3145
-
3146
- ## Content Sources
3147
-
3148
- \`\`\`css
3149
- /* Detecta automaticamente, mas pode especificar */
3150
- @import "tailwindcss";
3151
-
3152
- /* Adicionar sources explícitos */
3153
- @source "./src/**/*.{html,js,jsx,ts,tsx}";
3154
- @source "./components/**/*.vue";
3155
-
3156
- /* Ignorar paths */
3157
- @source not "./src/legacy/**";
3158
- \`\`\``,
3159
- };
3160
- if (!topico) {
3161
- let result = '# 📚 Guia de Migração Tailwind CSS v3 → v4\n\n';
3162
- result += 'Escolha um tópico para ver detalhes:\n\n';
3163
- result += '| Tópico | Descrição |\n';
3164
- result += '|--------|----------|\n';
3165
- result += '| `overview` | Visão geral das mudanças |\n';
3166
- result += '| `css-first` | Nova configuração via CSS |\n';
3167
- result += '| `theme-config` | Customização de tema |\n';
3168
- result += '| `utilities` | Mudanças em classes |\n';
3169
- result += '| `variants` | Novos variants |\n';
3170
- result += '| `plugins` | Plugins no v4 |\n';
3171
- result += '| `breaking-changes` | O que quebra |\n';
3172
- result += '| `postcss-vite` | Setup do build |\n';
3173
- result += '\n**Exemplo:** `tailwind_migracao_v4({ topico: "breaking-changes" })`\n';
3174
- return { content: [{ type: 'text', text: result }] };
3175
- }
3176
- const content = migracaoContent[topico];
3177
- if (!content) {
3178
- return {
3179
- content: [{ type: 'text', text: `❌ Tópico não encontrado: ${topico}\n\nTópicos disponíveis: ${Object.keys(migracaoContent).join(', ')}` }],
3180
- isError: true,
3181
- };
3182
- }
3183
- return { content: [{ type: 'text', text: content }] };
3184
- }
3185
- case 'tailwind_boas_praticas': {
3186
- const topico = args?.topico;
3187
- const boasPraticas = {
3188
- organizacao: `# 📋 Organização de Classes
3189
-
3190
- ## Ordem Recomendada
3191
-
3192
- Organize classes nesta ordem para consistência:
3193
-
3194
- 1. **Layout** (display, position, flexbox/grid)
3195
- 2. **Sizing** (width, height)
3196
- 3. **Spacing** (margin, padding)
3197
- 4. **Typography** (font, text)
3198
- 5. **Visual** (background, border, shadow)
3199
- 6. **Effects** (opacity, filters)
3200
- 7. **Transitions/Animations**
3201
- 8. **Variants** (hover, focus, responsive)
3202
-
3203
- \`\`\`html
3204
- <button class="
3205
- flex items-center justify-center /* Layout */
3206
- w-full h-12 /* Sizing */
3207
- px-4 py-2 /* Spacing */
3208
- text-sm font-medium text-white /* Typography */
3209
- bg-blue-600 rounded-lg shadow /* Visual */
3210
- transition-colors /* Transitions */
3211
- hover:bg-blue-700 focus:ring-2 /* Variants */
3212
- ">
3213
- Botão
3214
- </button>
3215
- \`\`\`
3216
-
3217
- ## Multi-line para Legibilidade
3218
-
3219
- \`\`\`html
3220
- <!-- ❌ Difícil de ler -->
3221
- <div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow">
3222
-
3223
- <!-- ✅ Mais legível -->
3224
- <div class="
3225
- flex items-center justify-between
3226
- p-4
3227
- bg-white rounded-lg
3228
- shadow-md hover:shadow-lg
3229
- transition-shadow
3230
- ">
3231
- \`\`\``,
3232
- componentes: `# 🧩 Extração de Componentes
3233
-
3234
- ## Quando Extrair
3235
-
3236
- Extraia quando:
3237
- - Mesmo conjunto de classes usado 3+ vezes
3238
- - Componente tem lógica complexa
3239
- - Precisa de variantes (primary, secondary)
3240
-
3241
- ## React/Vue Components
3242
-
3243
- \`\`\`jsx
3244
- // ✅ Componente React
3245
- function Button({ variant = 'primary', children }) {
3246
- const variants = {
3247
- primary: 'bg-blue-600 text-white hover:bg-blue-700',
3248
- secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
3249
- outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50',
3250
- }
3251
-
3252
- return (
3253
- <button className={\`
3254
- px-4 py-2 font-medium rounded-lg
3255
- transition-colors focus:outline-none focus:ring-2
3256
- \${variants[variant]}
3257
- \`}>
3258
- {children}
3259
- </button>
3260
- )
3261
- }
3262
- \`\`\`
3263
-
3264
- ## @apply (Usar com Moderação)
3265
-
3266
- \`\`\`css
3267
- /* ⚠️ Use apenas quando necessário */
3268
- @layer components {
3269
- .btn {
3270
- @apply px-4 py-2 font-medium rounded-lg transition-colors;
3271
- }
3272
-
3273
- .btn-primary {
3274
- @apply bg-blue-600 text-white hover:bg-blue-700;
3275
- }
3276
- }
3277
- \`\`\`
3278
-
3279
- ## Tailwind Merge (recomendado)
3280
-
3281
- \`\`\`jsx
3282
- import { twMerge } from 'tailwind-merge'
3283
-
3284
- // Resolve conflitos de classes
3285
- <div className={twMerge('px-4 py-2', className)}>
3286
- \`\`\``,
3287
- performance: `# ⚡ Performance
3288
-
3289
- ## Content Configuration
3290
-
3291
- \`\`\`css
3292
- /* v4: Seja específico nos sources */
3293
- @import "tailwindcss";
3294
- @source "./src/**/*.{js,jsx,ts,tsx}";
3295
- @source "./components/**/*.vue";
3296
- @source not "./node_modules/**";
3297
- \`\`\`
3298
-
3299
- ## Evite Classes Dinâmicas
3300
-
3301
- \`\`\`jsx
3302
- // ❌ Tailwind não detecta
3303
- <div className={\`bg-\${color}-500\`}>
3304
-
3305
- // ✅ Use objeto de mapeamento
3306
- const colors = {
3307
- blue: 'bg-blue-500',
3308
- red: 'bg-red-500',
3309
- green: 'bg-green-500',
3310
- }
3311
- <div className={colors[color]}>
3312
- \`\`\`
3313
-
3314
- ## Safelist (quando necessário)
3315
-
3316
- \`\`\`css
3317
- /* v4: Forçar inclusão de classes */
3318
- @import "tailwindcss";
3319
- @utility bg-brand-* {
3320
- /* Garante que bg-brand-{any} seja incluído */
3321
- }
3322
- \`\`\`
3323
-
3324
- ## Minificação
3325
-
3326
- \`\`\`bash
3327
- # CLI com minificação
3328
- npx @tailwindcss/cli -i input.css -o output.css --minify
3329
-
3330
- # Vite faz automaticamente em build
3331
- \`\`\`
3332
-
3333
- ## Cache
3334
-
3335
- - Use cache do bundler (Vite/Webpack)
3336
- - Tailwind v4 é 10x mais rápido que v3`,
3337
- acessibilidade: `# ♿ Acessibilidade
3338
-
3339
- ## Focus Visible
3340
-
3341
- \`\`\`html
3342
- <!-- Foco apenas para navegação por teclado -->
3343
- <button class="
3344
- focus:outline-none
3345
- focus-visible:ring-2 focus-visible:ring-blue-500
3346
- ">
3347
- Botão Acessível
3348
- </button>
3349
- \`\`\`
3350
-
3351
- ## Screen Reader Only
3352
-
3353
- \`\`\`html
3354
- <!-- Texto só para leitores de tela -->
3355
- <span class="sr-only">Fechar menu</span>
3356
-
3357
- <!-- Ícone com label acessível -->
3358
- <button aria-label="Fechar">
3359
- <svg class="w-5 h-5" aria-hidden="true">...</svg>
3360
- </button>
3361
- \`\`\`
3362
-
3363
- ## Motion Reduce
3364
-
3365
- \`\`\`html
3366
- <!-- Respeitar preferências do usuário -->
3367
- <div class="
3368
- animate-bounce
3369
- motion-reduce:animate-none
3370
- ">
3371
- \`\`\`
3372
-
3373
- ## Contraste
3374
-
3375
- \`\`\`html
3376
- <!-- Alto contraste quando necessário -->
3377
- <div class="
3378
- text-gray-600
3379
- contrast-more:text-gray-900
3380
- contrast-more:border-2
3381
- ">
3382
- \`\`\`
3383
-
3384
- ## ARIA Variants
3385
-
3386
- \`\`\`html
3387
- <!-- Estilos baseados em ARIA -->
3388
- <button
3389
- aria-expanded="true"
3390
- class="aria-expanded:rotate-180"
3391
- >
3392
- <svg>...</svg>
3393
- </button>
3394
- \`\`\``,
3395
- responsivo: `# 📱 Design Responsivo
3396
-
3397
- ## Mobile-First
3398
-
3399
- \`\`\`html
3400
- <!-- Base = mobile, depois aumenta -->
3401
- <div class="
3402
- flex flex-col /* Mobile: coluna */
3403
- md:flex-row /* Tablet+: linha */
3404
- ">
3405
- \`\`\`
3406
-
3407
- ## Container Queries (v4)
3408
-
3409
- \`\`\`html
3410
- <!-- Responde ao container, não à viewport -->
3411
- <div class="@container">
3412
- <div class="
3413
- @sm:flex
3414
- @lg:grid @lg:grid-cols-2
3415
- ">
3416
- \`\`\`
3417
-
3418
- ## Breakpoints Úteis
3419
-
3420
- \`\`\`html
3421
- <div class="
3422
- grid grid-cols-1 /* < 640px */
3423
- sm:grid-cols-2 /* ≥ 640px */
3424
- md:grid-cols-3 /* ≥ 768px */
3425
- lg:grid-cols-4 /* ≥ 1024px */
3426
- xl:grid-cols-5 /* ≥ 1280px */
3427
- ">
3428
- \`\`\`
3429
-
3430
- ## Max-Width Variants
3431
-
3432
- \`\`\`html
3433
- <!-- Esconder apenas em mobile -->
3434
- <div class="hidden sm:block">Desktop only</div>
3435
-
3436
- <!-- Mostrar apenas em mobile -->
3437
- <div class="sm:hidden">Mobile only</div>
3438
- \`\`\`
3439
-
3440
- ## Layout Responsivo Completo
3441
-
3442
- \`\`\`html
3443
- <div class="min-h-screen flex flex-col">
3444
- <header class="h-16 px-4 md:px-6 lg:px-8">
3445
- Nav
3446
- </header>
3447
-
3448
- <main class="flex-1 container mx-auto px-4 py-6">
3449
- <div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
3450
- <!-- Cards -->
3451
- </div>
3452
- </main>
3453
-
3454
- <footer class="h-20">
3455
- Footer
3456
- </footer>
3457
- </div>
3458
- \`\`\``,
3459
- 'dark-mode': `# 🌙 Dark Mode
3460
-
3461
- ## Setup Básico
3462
-
3463
- \`\`\`html
3464
- <!-- Classe no html ou body -->
3465
- <html class="dark">
3466
- <body class="bg-white dark:bg-gray-900">
3467
- \`\`\`
3468
-
3469
- ## Padrões Comuns
3470
-
3471
- \`\`\`html
3472
- <!-- Texto -->
3473
- <p class="text-gray-900 dark:text-white">
3474
- <p class="text-gray-600 dark:text-gray-400">
3475
-
3476
- <!-- Backgrounds -->
3477
- <div class="bg-white dark:bg-gray-800">
3478
- <div class="bg-gray-50 dark:bg-gray-900">
3479
-
3480
- <!-- Borders -->
3481
- <div class="border-gray-200 dark:border-gray-700">
3482
-
3483
- <!-- Shadows -->
3484
- <div class="shadow-lg dark:shadow-gray-900/20">
3485
- \`\`\`
3486
-
3487
- ## Toggle com JavaScript
3488
-
3489
- \`\`\`js
3490
- // Alternar dark mode
3491
- document.documentElement.classList.toggle('dark')
3492
-
3493
- // Persistir preferência
3494
- localStorage.setItem('theme', 'dark')
3495
-
3496
- // Detectar preferência do sistema
3497
- if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
3498
- document.documentElement.classList.add('dark')
3499
- }
3500
- \`\`\`
3501
-
3502
- ## Componente Dark Mode Aware
3503
-
3504
- \`\`\`html
3505
- <div class="
3506
- bg-white dark:bg-gray-800
3507
- text-gray-900 dark:text-white
3508
- border border-gray-200 dark:border-gray-700
3509
- shadow-lg dark:shadow-none
3510
- rounded-lg p-6
3511
- ">
3512
- <h2 class="text-xl font-bold">Título</h2>
3513
- <p class="text-gray-600 dark:text-gray-400">
3514
- Conteúdo que funciona nos dois modos.
3515
- </p>
3516
- </div>
3517
- \`\`\``,
3518
- animacoes: `# 🎬 Animações e Transições
3519
-
3520
- ## Transições Básicas
3521
-
3522
- \`\`\`html
3523
- <!-- Transição suave -->
3524
- <button class="
3525
- bg-blue-500
3526
- transition-colors duration-200
3527
- hover:bg-blue-600
3528
- ">
3529
-
3530
- <!-- Transição completa -->
3531
- <div class="
3532
- transform transition-all duration-300 ease-out
3533
- hover:scale-105 hover:shadow-lg
3534
- ">
3535
- \`\`\`
3536
-
3537
- ## Animações Built-in
3538
-
3539
- \`\`\`html
3540
- <!-- Spin (loading) -->
3541
- <svg class="animate-spin h-5 w-5">
3542
-
3543
- <!-- Pulse -->
3544
- <div class="animate-pulse">
3545
-
3546
- <!-- Bounce -->
3547
- <div class="animate-bounce">
3548
-
3549
- <!-- Ping (notification) -->
3550
- <span class="animate-ping">
3551
- \`\`\`
3552
-
3553
- ## Animação Customizada
3554
-
3555
- \`\`\`css
3556
- @theme {
3557
- --animate-fade-in: fadeIn 0.3s ease-out;
3558
- --animate-slide-up: slideUp 0.4s ease-out;
3559
- }
3560
-
3561
- @keyframes fadeIn {
3562
- from { opacity: 0; }
3563
- to { opacity: 1; }
3564
- }
3565
-
3566
- @keyframes slideUp {
3567
- from {
3568
- opacity: 0;
3569
- transform: translateY(10px);
3570
- }
3571
- to {
3572
- opacity: 1;
3573
- transform: translateY(0);
3574
- }
3575
- }
3576
- \`\`\`
3577
-
3578
- ## Starting Style (v4)
3579
-
3580
- \`\`\`html
3581
- <!-- Animação de entrada automática -->
3582
- <div class="
3583
- opacity-100 transition-opacity duration-300
3584
- starting:opacity-0
3585
- ">
3586
- Aparece com fade
3587
- </div>
3588
- \`\`\`
3589
-
3590
- ## Motion Safe/Reduce
3591
-
3592
- \`\`\`html
3593
- <div class="
3594
- animate-bounce
3595
- motion-reduce:animate-none
3596
- motion-safe:transition-transform
3597
- ">
3598
- \`\`\``,
3599
- forms: `# 📝 Formulários
3600
-
3601
- ## Input Estilizado
3602
-
3603
- \`\`\`html
3604
- <input
3605
- type="text"
3606
- class="
3607
- w-full px-4 py-2
3608
- border border-gray-300 rounded-lg
3609
- focus:ring-2 focus:ring-blue-500 focus:border-blue-500
3610
- placeholder:text-gray-400
3611
- disabled:bg-gray-100 disabled:cursor-not-allowed
3612
- "
3613
- placeholder="Digite aqui..."
3614
- >
3615
- \`\`\`
3616
-
3617
- ## Estados de Validação
3618
-
3619
- \`\`\`html
3620
- <!-- Input válido -->
3621
- <input class="
3622
- border-green-500
3623
- focus:ring-green-500
3624
- valid:border-green-500
3625
- ">
3626
-
3627
- <!-- Input inválido -->
3628
- <input class="
3629
- border-red-500
3630
- focus:ring-red-500
3631
- invalid:border-red-500
3632
- ">
3633
- \`\`\`
3634
-
3635
- ## Checkbox Customizado
3636
-
3637
- \`\`\`html
3638
- <label class="flex items-center gap-2 cursor-pointer">
3639
- <input
3640
- type="checkbox"
3641
- class="
3642
- w-5 h-5 rounded
3643
- text-blue-600
3644
- border-gray-300
3645
- focus:ring-blue-500
3646
- "
3647
- >
3648
- <span class="text-gray-700">Aceito os termos</span>
3649
- </label>
3650
- \`\`\`
3651
-
3652
- ## Select Estilizado
3653
-
3654
- \`\`\`html
3655
- <select class="
3656
- w-full px-4 py-2
3657
- border border-gray-300 rounded-lg
3658
- bg-white
3659
- focus:ring-2 focus:ring-blue-500
3660
- ">
3661
- <option>Opção 1</option>
3662
- <option>Opção 2</option>
3663
- </select>
3664
- \`\`\`
3665
-
3666
- ## Plugin Forms (Recomendado)
3667
-
3668
- \`\`\`css
3669
- @import "tailwindcss";
3670
- @plugin "@tailwindcss/forms";
3671
- \`\`\`
3672
-
3673
- Aplica estilos base automaticamente a todos os inputs.`,
3674
- };
3675
- if (!topico) {
3676
- let result = '# 💡 Boas Práticas Tailwind CSS\n\n';
3677
- result += 'Escolha um tópico:\n\n';
3678
- result += '| Tópico | Descrição |\n';
3679
- result += '|--------|----------|\n';
3680
- result += '| `organizacao` | Ordem e organização de classes |\n';
3681
- result += '| `componentes` | Extração e reutilização |\n';
3682
- result += '| `performance` | Otimização de bundle |\n';
3683
- result += '| `acessibilidade` | A11y com Tailwind |\n';
3684
- result += '| `responsivo` | Design responsivo |\n';
3685
- result += '| `dark-mode` | Implementação de dark mode |\n';
3686
- result += '| `animacoes` | Transições e animações |\n';
3687
- result += '| `forms` | Estilização de formulários |\n';
3688
- result += '\n**Exemplo:** `tailwind_boas_praticas({ topico: "responsivo" })`\n';
3689
- return { content: [{ type: 'text', text: result }] };
3690
- }
3691
- const content = boasPraticas[topico];
3692
- if (!content) {
3693
- return {
3694
- content: [{ type: 'text', text: `❌ Tópico não encontrado: ${topico}\n\nTópicos disponíveis: ${Object.keys(boasPraticas).join(', ')}` }],
3695
- isError: true,
3696
- };
3697
- }
3698
- return { content: [{ type: 'text', text: content }] };
3699
- }
3700
- case 'tailwind_check_updates': {
3701
- const updateInfo = await checkForUpdates();
3702
- let result = '# 🔍 Verificação de Atualizações\n\n';
3703
- if (updateInfo.hasUpdate) {
3704
- result += '⚠️ **Atualização disponível!**\n\n';
3705
- result += `**Commit local:** \`${updateInfo.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
3706
- result += `**Commit remoto:** \`${updateInfo.latestSha?.substring(0, 7) || 'N/A'}\`\n\n`;
3707
- if (updateInfo.latestCommit) {
3708
- result += `**Último commit:**\n`;
3709
- result += `- Mensagem: ${updateInfo.latestCommit.message}\n`;
3710
- result += `- Autor: ${updateInfo.latestCommit.author}\n`;
3711
- result += `- Data: ${updateInfo.latestCommit.date}\n\n`;
3712
- }
3713
- result += '> Use `tailwind_update` para atualizar o repositório.\n';
3714
- }
3715
- else {
3716
- result += '✅ **Repositório está atualizado!**\n\n';
3717
- result += `**Commit atual:** \`${updateInfo.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
3718
- }
3719
- return {
3720
- content: [{ type: 'text', text: result }],
3721
- };
3722
- }
3723
- case 'tailwind_update': {
3724
- const updateResult = await checkAndUpdate();
3725
- let result = '# 🔄 Atualização do Repositório\n\n';
3726
- if (updateResult.updated) {
3727
- result += '✅ **Repositório atualizado com sucesso!**\n\n';
3728
- if (updateResult.previousSha) {
3729
- result += `**De:** \`${updateResult.previousSha.substring(0, 7)}\`\n`;
3730
- }
3731
- result += `**Para:** \`${updateResult.currentSha?.substring(0, 7) || 'N/A'}\`\n\n`;
3732
- if (updateResult.commitMessage) {
3733
- result += `**Commit:** ${updateResult.commitMessage}\n`;
3734
- }
3735
- if (updateResult.commitDate) {
3736
- result += `**Data:** ${updateResult.commitDate}\n`;
3737
- }
3738
- result += '\n> ⚡ O contexto da biblioteca foi atualizado automaticamente.\n';
3739
- }
3740
- else if (updateResult.error) {
3741
- result += '❌ **Erro ao atualizar:**\n\n';
3742
- result += `\`\`\`\n${updateResult.error}\n\`\`\`\n`;
3743
- }
3744
- else {
3745
- result += '✅ **Já está na versão mais recente!**\n\n';
3746
- result += `**Commit atual:** \`${updateResult.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
3747
- }
3748
- return {
3749
- content: [{ type: 'text', text: result }],
3750
- };
3751
- }
3752
- case 'tailwind_status': {
3753
- const status = await getRepositoryStatus();
3754
- let result = '# 📊 Status do Repositório Tailwind CSS\n\n';
3755
- result += `**Repositório válido:** ${status.isValid ? '✅ Sim' : '❌ Não'}\n`;
3756
- result += `**Caminho:** \`${status.repoPath}\`\n\n`;
3757
- result += `**Commit local:** \`${status.localSha?.substring(0, 7) || 'N/A'}\`\n`;
3758
- result += `**Commit remoto:** \`${status.remoteSha?.substring(0, 7) || 'N/A'}\`\n\n`;
3759
- if (status.hasUpdates) {
3760
- result += '⚠️ **Há atualizações disponíveis!**\n\n';
3761
- result += '> Use `tailwind_update` para atualizar.\n';
3762
- }
3763
- else {
3764
- result += '✅ **Repositório está sincronizado com o GitHub.**\n';
3765
- }
3766
- result += `\n**Última verificação:** ${status.lastCheck}\n`;
3767
- return {
3768
- content: [{ type: 'text', text: result }],
3769
- };
3770
- }
3771
- default:
3772
- return {
3773
- content: [{ type: 'text', text: `❌ Ferramenta desconhecida: ${name}` }],
3774
- isError: true,
3775
- };
3776
- }
3777
- }
3778
- catch (error) {
3779
- return {
3780
- content: [
3781
- {
3782
- type: 'text',
3783
- text: `❌ Erro: ${error instanceof Error ? error.message : String(error)}`,
3784
- },
3785
- ],
3786
- isError: true,
3787
- };
3788
- }
3789
- });
3790
- mcpServer.server.setRequestHandler(ListResourcesRequestSchema, async () => {
3791
- return {
3792
- resources: [
3793
- {
3794
- uri: 'tailwind://readme',
3795
- name: 'Tailwind CSS README',
3796
- description: 'Documentação principal da biblioteca Tailwind CSS',
3797
- mimeType: 'text/markdown',
3798
- },
3799
- {
3800
- uri: 'tailwind://types',
3801
- name: 'Types Index',
3802
- description: 'Tipos principais expostos pelo Tailwind',
3803
- mimeType: 'text/markdown',
3804
- },
3805
- {
3806
- uri: 'tailwind://statistics',
3807
- name: 'Library Statistics',
3808
- description: 'Estatísticas completas da biblioteca',
3809
- mimeType: 'text/markdown',
3810
- },
3811
- ],
3812
- };
3813
- });
3814
- mcpServer.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
3815
- const uri = request.params.uri;
3816
- if (uri === 'tailwind://readme') {
3817
- const readmePath = path.join(TAILWIND_SRC_PATH, '..', 'README.md');
3818
- if (fs.existsSync(readmePath)) {
3819
- const content = fs.readFileSync(readmePath, 'utf-8');
3820
- return { contents: [{ uri, mimeType: 'text/markdown', text: content }] };
3821
- }
3822
- }
3823
- if (uri === 'tailwind://types') {
3824
- const indexPath = path.join(TAILWIND_SRC_PATH, 'types.ts');
3825
- if (fs.existsSync(indexPath)) {
3826
- const content = fs.readFileSync(indexPath, 'utf-8');
3827
- return {
3828
- contents: [
3829
- {
3830
- uri,
3831
- mimeType: 'text/markdown',
3832
- text: `# Types Index\n\n\`\`\`typescript\n${content}\n\`\`\``,
3833
- },
3834
- ],
3835
- };
3836
- }
3837
- }
3838
- if (uri === 'tailwind://statistics') {
3839
- const parser = new AstParser(TAILWIND_SRC_PATH);
3840
- const stats = parser.getStatistics();
3841
- return {
3842
- contents: [
3843
- {
3844
- uri,
3845
- mimeType: 'text/markdown',
3846
- text: formatStatistics(stats),
3847
- },
3848
- ],
3849
- };
3850
- }
3851
- return { contents: [{ uri, mimeType: 'text/plain', text: 'Resource not found' }] };
3852
- });
3853
- const AUTO_UPDATE_INTERVAL = parseInt(process.env.AUTO_UPDATE_INTERVAL || '3600000', 10);
3854
- const AUTO_UPDATE_ENABLED = process.env.AUTO_UPDATE_ENABLED !== 'false';
3855
22
  async function main() {
3856
23
  const repoResult = await ensureRepository();
3857
24
  if (!repoResult.success) {
3858
25
  console.error(`❌ ${repoResult.error}`);
3859
26
  process.exit(1);
3860
27
  }
3861
- TAILWIND_SRC_PATH = repoResult.path;
3862
- console.error(`📁 Usando Tailwind CSS: ${TAILWIND_SRC_PATH}`);
28
+ const srcPath = repoResult.path;
29
+ console.error(`📁 Usando Tailwind CSS: ${srcPath}`);
30
+ // Register all tools and resources
31
+ registerAstTools(mcpServer, srcPath);
32
+ registerRepoTools(mcpServer, srcPath, APP_VERSION);
33
+ registerContentTools(mcpServer, srcPath);
34
+ registerResources(mcpServer, srcPath);
35
+ // Connect transport
3863
36
  const transport = new StdioServerTransport();
3864
37
  await mcpServer.connect(transport);
3865
38
  console.error(`MCP Tailwind CSS server v${APP_VERSION} running on stdio`);
39
+ // Auto-update check (repositório Tailwind)
3866
40
  if (AUTO_UPDATE_ENABLED) {
3867
41
  const initialCheck = await checkForUpdates();
3868
42
  if (initialCheck.hasUpdate) {
3869
- console.error(`⚠️ Atualização disponível: ${initialCheck.latestCommit?.message}`);
43
+ console.error(`⚠️ Atualização do repositório disponível: ${initialCheck.latestCommit?.message}`);
3870
44
  }
3871
45
  scheduleUpdateCheck(AUTO_UPDATE_INTERVAL);
3872
46
  }
47
+ // Self-update check (pacote mcp-tailwindcss no npm)
48
+ const packageCheck = await checkPackageUpdate(APP_VERSION);
49
+ if (packageCheck.hasUpdate) {
50
+ console.error(`\n⚠️ Nova versão do mcp-tailwindcss: v${packageCheck.latestVersion} (atual: v${APP_VERSION})`);
51
+ console.error(` Atualize: npm install -g mcp-tailwindcss@latest\n`);
52
+ }
53
+ schedulePackageUpdateCheck(APP_VERSION);
3873
54
  }
3874
55
  main().catch((error) => {
3875
56
  console.error('Fatal error:', error);