From 3fbb9a18372f2b6a675dd6c039ba52be76f3eeb4 Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Fri, 16 Jan 2026 08:30:14 +0900 Subject: updates --- ui/tailwindcss/.claude/commands/analyze-usage.md | 545 +++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 ui/tailwindcss/.claude/commands/analyze-usage.md (limited to 'ui/tailwindcss/.claude/commands/analyze-usage.md') diff --git a/ui/tailwindcss/.claude/commands/analyze-usage.md b/ui/tailwindcss/.claude/commands/analyze-usage.md new file mode 100644 index 0000000..18d5f0f --- /dev/null +++ b/ui/tailwindcss/.claude/commands/analyze-usage.md @@ -0,0 +1,545 @@ +--- +name: analyze-usage +description: Analyze TailwindCSS utility usage patterns, identify optimization opportunities, and generate usage reports +tools: Read, Bash, Grep, Glob, Write +--- + +# Analyze TailwindCSS Usage + +This command analyzes your TailwindCSS usage patterns across your codebase to identify optimization opportunities, unused utilities, and usage statistics. + +## What This Command Does + +1. **Usage Pattern Analysis** + - Scans all template files for TailwindCSS class usage + - Identifies most and least used utility patterns + - Generates usage frequency reports + - Detects potential optimization opportunities + +2. **Bundle Size Analysis** + - Analyzes generated CSS bundle size + - Identifies largest utility categories + - Compares before/after optimization results + - Tracks bundle size over time + +3. **Code Quality Insights** + - Identifies overly complex utility combinations + - Suggests component extraction opportunities + - Detects inconsistent utility usage patterns + - Highlights potential refactoring opportunities + +4. **Performance Recommendations** + - Suggests safelist optimizations + - Identifies unused CSS that can be purged + - Recommends content path improvements + - Provides bundle optimization suggestions + +## Usage Examples + +### Basic Usage Analysis + +```bash +# Analyze utility usage in all template files +grep -r "class[Name]*=" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" | \ +sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \ +tr ' ' '\n' | \ +sort | uniq -c | sort -nr > tailwind-usage-report.txt + +# View top 20 most used utilities +head -20 tailwind-usage-report.txt + +# View least used utilities +tail -20 tailwind-usage-report.txt +``` + +### Advanced Pattern Analysis + +```bash +# Find all TailwindCSS classes in codebase +find src -name "*.{js,jsx,ts,tsx,vue,html}" -exec grep -l "class" {} \; | \ +xargs grep -o "class[Name]*=['\"][^'\"]*['\"]" | \ +sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \ +tr ' ' '\n' | \ +grep -E '^[a-zA-Z]' | \ +sort | uniq -c | sort -nr +``` + +### Component Complexity Analysis + +```bash +# Find components with many utility classes (potential extraction candidates) +find src/components -name "*.{jsx,tsx}" -exec sh -c ' + for file do + count=$(grep -o "class[Name]*=['\"][^'\"]*['\"]" "$file" | \ + sed -E "s/.*class[Name]*=[\"\'\`]([^\"\'\`]*)[\"\'\`].*/\1/" | \ + tr " " "\n" | wc -l) + echo "$count $file" + done +' sh {} + | sort -nr | head -10 +``` + +## Analysis Scripts + +### Comprehensive Usage Analyzer + +```javascript +// scripts/analyze-tailwind-usage.js +const fs = require('fs') +const path = require('path') +const glob = require('glob') + +class TailwindUsageAnalyzer { + constructor(options = {}) { + this.srcPaths = options.srcPaths || ['src/**/*.{js,jsx,ts,tsx,vue,html}'] + this.outputPath = options.outputPath || './tailwind-analysis.json' + this.classPattern = /(?:class|className)(?:Name)?[`:=]\s*[`"']([^`"']*)[`"']/g + } + + async analyze() { + const files = this.getTemplateFiles() + const results = { + totalFiles: files.length, + totalClasses: 0, + utilityStats: {}, + fileStats: {}, + categoryStats: {}, + complexityStats: {}, + timestamp: new Date().toISOString() + } + + for (const file of files) { + const content = fs.readFileSync(file, 'utf8') + const fileClasses = this.extractClasses(content) + + results.fileStats[file] = { + classCount: fileClasses.length, + uniqueClasses: [...new Set(fileClasses)].length, + complexity: this.calculateComplexity(fileClasses) + } + + // Update utility stats + fileClasses.forEach(className => { + results.utilityStats[className] = (results.utilityStats[className] || 0) + 1 + results.totalClasses++ + + // Categorize utility + const category = this.categorizeUtility(className) + results.categoryStats[category] = (results.categoryStats[category] || 0) + 1 + }) + } + + // Calculate additional insights + results.insights = this.generateInsights(results) + results.recommendations = this.generateRecommendations(results) + + // Save results + fs.writeFileSync(this.outputPath, JSON.stringify(results, null, 2)) + + return results + } + + getTemplateFiles() { + const files = [] + this.srcPaths.forEach(pattern => { + files.push(...glob.sync(pattern)) + }) + return files + } + + extractClasses(content) { + const classes = [] + let match + + while ((match = this.classPattern.exec(content)) !== null) { + const classString = match[1] + const classList = classString.split(/\s+/).filter(cls => cls.length > 0) + classes.push(...classList) + } + + return classes + } + + categorizeUtility(className) { + const categories = { + layout: /^(block|inline|flex|grid|table|hidden|container)/, + spacing: /^(p|m|space)[trblxy]?-/, + sizing: /^(w|h|max-w|max-h|min-w|min-h)-/, + typography: /^(text|font|leading|tracking|whitespace)/, + colors: /^(bg|text|border|ring)-.+-(50|100|200|300|400|500|600|700|800|900|950)$/, + borders: /^(border|rounded|ring|divide)/, + effects: /^(shadow|opacity|blur)/, + filters: /^(filter|backdrop|brightness|contrast|grayscale)/, + animation: /^(animate|transition|duration|ease|delay)/, + transforms: /^(transform|scale|rotate|translate|skew)/, + interactivity: /^(cursor|select|resize|outline|appearance)/, + responsive: /^(sm|md|lg|xl|2xl):/, + state: /^(hover|focus|active|disabled|group|peer):/, + } + + for (const [category, pattern] of Object.entries(categories)) { + if (pattern.test(className)) { + return category + } + } + + return 'other' + } + + calculateComplexity(classes) { + const uniqueClasses = new Set(classes) + const responsiveClasses = classes.filter(c => /^(sm|md|lg|xl|2xl):/.test(c)) + const stateClasses = classes.filter(c => /^(hover|focus|active|group|peer):/.test(c)) + + return { + total: classes.length, + unique: uniqueClasses.size, + responsive: responsiveClasses.length, + interactive: stateClasses.length, + ratio: classes.length / uniqueClasses.size + } + } + + generateInsights(results) { + const sortedUtilities = Object.entries(results.utilityStats) + .sort(([,a], [,b]) => b - a) + + const sortedCategories = Object.entries(results.categoryStats) + .sort(([,a], [,b]) => b - a) + + const complexFiles = Object.entries(results.fileStats) + .sort(([,a], [,b]) => b.complexity.total - a.complexity.total) + .slice(0, 10) + + return { + mostUsedUtilities: sortedUtilities.slice(0, 20), + leastUsedUtilities: sortedUtilities.slice(-20), + topCategories: sortedCategories, + mostComplexFiles: complexFiles, + averageClassesPerFile: results.totalClasses / results.totalFiles, + uniqueUtilityCount: Object.keys(results.utilityStats).length + } + } + + generateRecommendations(results) { + const recommendations = [] + + // Check for overused utilities + const overusedUtilities = results.insights.mostUsedUtilities + .filter(([,count]) => count > results.totalFiles * 0.8) + + if (overusedUtilities.length > 0) { + recommendations.push({ + type: 'component-extraction', + message: 'Consider extracting components for frequently used utility combinations', + utilities: overusedUtilities.slice(0, 5).map(([name]) => name) + }) + } + + // Check for complex files + const complexFiles = results.insights.mostComplexFiles + .filter(([,stats]) => stats.complexity.total > 50) + + if (complexFiles.length > 0) { + recommendations.push({ + type: 'complexity-reduction', + message: 'These files have high utility complexity and may benefit from refactoring', + files: complexFiles.slice(0, 5).map(([file]) => file) + }) + } + + // Check for unused categories + const lowUsageCategories = Object.entries(results.categoryStats) + .filter(([,count]) => count < results.totalClasses * 0.01) + + if (lowUsageCategories.length > 0) { + recommendations.push({ + type: 'config-optimization', + message: 'Consider removing unused utility categories from your build', + categories: lowUsageCategories.map(([name]) => name) + }) + } + + return recommendations + } +} + +// Usage +const analyzer = new TailwindUsageAnalyzer({ + srcPaths: ['src/**/*.{jsx,tsx}', 'pages/**/*.{jsx,tsx}'], + outputPath: './reports/tailwind-usage.json' +}) + +analyzer.analyze().then(results => { + console.log('TailwindCSS Usage Analysis Complete!') + console.log(`Analyzed ${results.totalFiles} files`) + console.log(`Found ${results.totalClasses} utility class usages`) + console.log(`${results.insights.uniqueUtilityCount} unique utilities`) + console.log(`Average ${results.insights.averageClassesPerFile.toFixed(1)} classes per file`) + + console.log('\nTop 10 Most Used Utilities:') + results.insights.mostUsedUtilities.slice(0, 10).forEach(([name, count]) => { + console.log(` ${name}: ${count} usages`) + }) + + console.log('\nRecommendations:') + results.recommendations.forEach(rec => { + console.log(` ${rec.type}: ${rec.message}`) + }) +}) +``` + +### Bundle Size Analyzer + +```javascript +// scripts/analyze-bundle-size.js +const fs = require('fs') +const gzipSize = require('gzip-size') +const brotliSize = require('brotli-size') + +async function analyzeBundleSize(cssFilePath) { + const css = fs.readFileSync(cssFilePath, 'utf8') + const originalSize = Buffer.byteLength(css, 'utf8') + + const gzipped = await gzipSize(css) + const brotlied = await brotliSize(css) + + // Extract utility classes + const utilities = css.match(/\.[a-zA-Z][a-zA-Z0-9_-]*(?::[\w-]+)*(?:,\s*\.[a-zA-Z][a-zA-Z0-9_-]*(?::[\w-]+)*)*\s*{[^}]+}/g) || [] + + // Categorize utilities + const categories = { + layout: 0, spacing: 0, typography: 0, colors: 0, + borders: 0, effects: 0, animations: 0, responsive: 0 + } + + let categorySize = { ...categories } + + utilities.forEach(rule => { + const size = Buffer.byteLength(rule, 'utf8') + + if (/\.(flex|grid|block|inline)/.test(rule)) { + categorySize.layout += size + } else if (/\.(p|m|space)-/.test(rule)) { + categorySize.spacing += size + } else if (/\.(text|font)-/.test(rule)) { + categorySize.typography += size + } else if (/\.(bg|text|border)-.+-(50|100|200|300|400|500|600|700|800|900)/.test(rule)) { + categorySize.colors += size + } else if (/\.(border|rounded|ring)/.test(rule)) { + categorySize.borders += size + } else if (/\.(shadow|opacity|blur)/.test(rule)) { + categorySize.effects += size + } else if (/\.(animate|transition)/.test(rule)) { + categorySize.animations += size + } else if (/@media/.test(rule)) { + categorySize.responsive += size + } + }) + + return { + original: originalSize, + gzipped, + brotlied, + utilityCount: utilities.length, + categoryBreakdown: categorySize, + compressionRatio: { + gzip: (originalSize / gzipped).toFixed(2), + brotli: (originalSize / brotlied).toFixed(2) + } + } +} + +// Generate size report +async function generateSizeReport(cssPath) { + const analysis = await analyzeBundleSize(cssPath) + + console.log('CSS Bundle Size Analysis') + console.log('========================') + console.log(`Original size: ${(analysis.original / 1024).toFixed(2)} KB`) + console.log(`Gzipped size: ${(analysis.gzipped / 1024).toFixed(2)} KB (${analysis.compressionRatio.gzip}x compression)`) + console.log(`Brotli size: ${(analysis.brotlied / 1024).toFixed(2)} KB (${analysis.compressionRatio.brotli}x compression)`) + console.log(`Utility rules: ${analysis.utilityCount}`) + + console.log('\nSize by Category:') + Object.entries(analysis.categoryBreakdown) + .sort(([,a], [,b]) => b - a) + .forEach(([category, size]) => { + const percentage = ((size / analysis.original) * 100).toFixed(1) + console.log(` ${category}: ${(size / 1024).toFixed(2)} KB (${percentage}%)`) + }) +} + +// Usage: node scripts/analyze-bundle-size.js dist/styles.css +generateSizeReport(process.argv[2]) +``` + +## Usage Reports + +### HTML Report Generator + +```javascript +// scripts/generate-usage-report.js +function generateHTMLReport(analysisData) { + const html = ` + + + + TailwindCSS Usage Report + + + +

TailwindCSS Usage Analysis Report

+

Generated on: ${analysisData.timestamp}

+ +
+

Overview

+
${analysisData.totalFiles} files analyzed
+
${analysisData.totalClasses} utility usages
+
${analysisData.insights.uniqueUtilityCount} unique utilities
+
${analysisData.insights.averageClassesPerFile.toFixed(1)} avg classes/file
+
+ +
+

Top Utility Categories

+ + + ${analysisData.insights.topCategories.slice(0, 10).map(([cat, count]) => ` + + + + + + `).join('')} +
CategoryUsage CountPercentage
${cat}${count}${((count / analysisData.totalClasses) * 100).toFixed(1)}%
+
+ +
+

Most Used Utilities

+ + + ${analysisData.insights.mostUsedUtilities.slice(0, 20).map(([util, count]) => ` + + + + + + `).join('')} +
UtilityUsage CountFiles
${util}${count}${Math.round((count / analysisData.totalFiles) * 100)}%
+
+ +
+

Most Complex Files

+ + + ${analysisData.insights.mostComplexFiles.slice(0, 10).map(([file, stats]) => ` + + + + + + + `).join('')} +
FileTotal ClassesUnique ClassesComplexity Ratio
${file}${stats.complexity.total}${stats.complexity.unique}${stats.complexity.ratio.toFixed(2)}
+
+ +
+

Recommendations

+ +
+ + +` + + fs.writeFileSync('./reports/tailwind-usage-report.html', html) + console.log('HTML report generated: ./reports/tailwind-usage-report.html') +} +``` + +## Automation and Monitoring + +### CI/CD Integration + +```yaml +# .github/workflows/tailwind-analysis.yml +name: TailwindCSS Usage Analysis + +on: + pull_request: + paths: + - 'src/**/*.{js,jsx,ts,tsx}' + - 'tailwind.config.js' + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run TailwindCSS usage analysis + run: node scripts/analyze-tailwind-usage.js + + - name: Generate size analysis + run: | + npm run build:css + node scripts/analyze-bundle-size.js dist/styles.css > bundle-size-report.txt + + - name: Comment PR with analysis + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + const analysis = JSON.parse(fs.readFileSync('./reports/tailwind-usage.json', 'utf8')); + const sizeReport = fs.readFileSync('bundle-size-report.txt', 'utf8'); + + const body = `## 📊 TailwindCSS Analysis + + **Usage Statistics:** + - Files analyzed: ${analysis.totalFiles} + - Total utility usages: ${analysis.totalClasses} + - Unique utilities: ${analysis.insights.uniqueUtilityCount} + - Average classes per file: ${analysis.insights.averageClassesPerFile.toFixed(1)} + + **Bundle Size:** + \`\`\` + ${sizeReport} + \`\`\` + + **Top Recommendations:** + ${analysis.recommendations.slice(0, 3).map(rec => `- ${rec.message}`).join('\n')} + `; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); +``` + +Remember: **Regular analysis helps maintain optimal TailwindCSS usage and identifies optimization opportunities early!** -- cgit v1.2.3