diff options
Diffstat (limited to 'ui/tailwindcss/.claude/hooks')
| -rwxr-xr-x | ui/tailwindcss/.claude/hooks/post-install | 338 | ||||
| -rwxr-xr-x | ui/tailwindcss/.claude/hooks/pre-commit | 214 | ||||
| -rwxr-xr-x | ui/tailwindcss/.claude/hooks/pre-push | 353 |
3 files changed, 905 insertions, 0 deletions
diff --git a/ui/tailwindcss/.claude/hooks/post-install b/ui/tailwindcss/.claude/hooks/post-install new file mode 100755 index 0000000..b25dfcc --- /dev/null +++ b/ui/tailwindcss/.claude/hooks/post-install @@ -0,0 +1,338 @@ +#!/bin/bash + +# TailwindCSS Post-install Hook +# Runs after dependencies are installed to ensure optimal TailwindCSS setup + +set -e + +echo "🎨 Running TailwindCSS post-install setup..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + local color=$1 + local message=$2 + echo -e "${color}${message}${NC}" +} + +# Check TailwindCSS installation +check_tailwind_installation() { + print_status $BLUE "Checking TailwindCSS installation..." + + if npm list tailwindcss >/dev/null 2>&1; then + local version=$(npm list tailwindcss --depth=0 2>/dev/null | grep tailwindcss | sed -E 's/.*tailwindcss@([0-9.]+).*/\1/') + print_status $GREEN "✅ TailwindCSS v${version} installed" + + # Check for v3+ features + if [[ "$(echo "$version" | cut -d. -f1)" -ge 3 ]]; then + print_status $GREEN "✅ Using TailwindCSS v3+ with modern features" + else + print_status $YELLOW "⚠️ Consider upgrading to TailwindCSS v3+ for better performance" + fi + else + print_status $RED "❌ TailwindCSS not found in dependencies" + print_status $YELLOW "Run: npm install -D tailwindcss" + exit 1 + fi +} + +# Verify essential plugins +verify_recommended_plugins() { + print_status $BLUE "Checking for recommended plugins..." + + local plugins=( + "@tailwindcss/typography:Typography support" + "@tailwindcss/forms:Enhanced form styling" + "@tailwindcss/aspect-ratio:Aspect ratio utilities" + "autoprefixer:CSS vendor prefixes" + "postcss:CSS processing" + ) + + for plugin_info in "${plugins[@]}"; do + local plugin=$(echo "$plugin_info" | cut -d: -f1) + local description=$(echo "$plugin_info" | cut -d: -f2) + + if npm list "$plugin" >/dev/null 2>&1; then + print_status $GREEN "✅ $plugin installed" + else + print_status $YELLOW "⚠️ Consider installing $plugin for $description" + fi + done +} + +# Initialize configuration if missing +initialize_config() { + print_status $BLUE "Checking TailwindCSS configuration..." + + if [[ ! -f "tailwind.config.js" && ! -f "tailwind.config.ts" ]]; then + print_status $YELLOW "⚠️ No TailwindCSS config found. Initializing..." + + if command -v npx >/dev/null 2>&1; then + npx tailwindcss init -p + print_status $GREEN "✅ Created tailwind.config.js and postcss.config.js" + else + print_status $RED "❌ npx not available. Please run 'npx tailwindcss init -p' manually" + fi + else + print_status $GREEN "✅ TailwindCSS configuration exists" + fi +} + +# Check PostCSS configuration +verify_postcss_config() { + print_status $BLUE "Verifying PostCSS configuration..." + + if [[ -f "postcss.config.js" ]]; then + if grep -q "tailwindcss" postcss.config.js; then + print_status $GREEN "✅ PostCSS configured with TailwindCSS" + else + print_status $YELLOW "⚠️ PostCSS config exists but may not include TailwindCSS" + fi + else + print_status $YELLOW "⚠️ No PostCSS config found. Consider creating one for optimal build setup" + + # Create basic PostCSS config + cat > postcss.config.js << EOF +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} +EOF + print_status $GREEN "✅ Created basic postcss.config.js" + fi +} + +# Optimize package.json scripts +optimize_package_scripts() { + print_status $BLUE "Checking package.json scripts..." + + if [[ -f "package.json" ]]; then + local has_build_css=$(npm run --silent 2>/dev/null | grep -q "build:css" && echo "true" || echo "false") + local has_watch_css=$(npm run --silent 2>/dev/null | grep -q "watch:css" && echo "true" || echo "false") + + if [[ "$has_build_css" == "false" ]]; then + print_status $YELLOW "⚠️ Consider adding a build:css script to package.json" + print_status $BLUE "Example: \"build:css\": \"tailwindcss -i ./src/input.css -o ./dist/output.css --minify\"" + else + print_status $GREEN "✅ Build CSS script available" + fi + + if [[ "$has_watch_css" == "false" ]]; then + print_status $YELLOW "⚠️ Consider adding a watch:css script for development" + print_status $BLUE "Example: \"watch:css\": \"tailwindcss -i ./src/input.css -o ./dist/output.css --watch\"" + else + print_status $GREEN "✅ Watch CSS script available" + fi + fi +} + +# Create default CSS entry point +create_css_entry() { + print_status $BLUE "Checking CSS entry point..." + + local css_files=("src/styles.css" "src/input.css" "src/globals.css" "styles/globals.css") + local css_exists=false + + for css_file in "${css_files[@]}"; do + if [[ -f "$css_file" ]]; then + css_exists=true + print_status $GREEN "✅ CSS entry point found: $css_file" + break + fi + done + + if [[ "$css_exists" == "false" ]]; then + print_status $YELLOW "⚠️ No CSS entry point found. Creating src/styles.css..." + + mkdir -p src + cat > src/styles.css << EOF +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html { + font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11'; + } + + body { + @apply bg-background text-foreground; + } +} + +@layer components { + .btn { + @apply inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50; + } + + .btn-primary { + @apply bg-primary text-primary-foreground hover:bg-primary/90; + } + + .btn-secondary { + @apply bg-secondary text-secondary-foreground hover:bg-secondary/80; + } + + .card { + @apply rounded-lg border bg-card text-card-foreground shadow-sm; + } +} + +@layer utilities { + .text-balance { + text-wrap: balance; + } +} +EOF + print_status $GREEN "✅ Created src/styles.css with TailwindCSS directives" + fi +} + +# Optimize TailwindCSS configuration +optimize_config() { + print_status $BLUE "Checking TailwindCSS configuration optimization..." + + local config_file="tailwind.config.js" + if [[ -f "tailwind.config.ts" ]]; then + config_file="tailwind.config.ts" + fi + + if [[ -f "$config_file" ]]; then + # Check for content configuration + if ! grep -q "content:" "$config_file"; then + print_status $YELLOW "⚠️ No content configuration found in $config_file" + print_status $YELLOW "Add content paths for proper CSS purging" + fi + + # Check for dark mode configuration + if ! grep -q "darkMode" "$config_file"; then + print_status $YELLOW "⚠️ Consider adding dark mode support" + print_status $BLUE "Add: darkMode: 'class'" + fi + + print_status $GREEN "✅ Configuration file checked" + fi +} + +# Set up development environment +setup_dev_environment() { + print_status $BLUE "Setting up development environment..." + + # Create .gitignore entries if needed + if [[ -f ".gitignore" ]]; then + if ! grep -q "# TailwindCSS" .gitignore; then + echo "" >> .gitignore + echo "# TailwindCSS" >> .gitignore + echo "dist/" >> .gitignore + echo "build/" >> .gitignore + print_status $GREEN "✅ Added TailwindCSS entries to .gitignore" + fi + fi + + # Create VSCode settings for better TailwindCSS support + if [[ ! -d ".vscode" ]]; then + mkdir -p .vscode + fi + + if [[ ! -f ".vscode/settings.json" ]]; then + cat > .vscode/settings.json << 'EOF' +{ + "tailwindCSS.includeLanguages": { + "javascript": "javascript", + "typescript": "typescript" + }, + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], + ["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ], + "css.validate": false, + "scss.validate": false, + "editor.quickSuggestions": { + "strings": true + } +} +EOF + print_status $GREEN "✅ Created .vscode/settings.json for TailwindCSS support" + fi +} + +# Generate usage report +generate_usage_report() { + print_status $BLUE "Generating TailwindCSS setup report..." + + local report_file=".tailwindcss-setup-report.txt" + + cat > "$report_file" << EOF +TailwindCSS Setup Report +======================== +Generated: $(date) + +Installation Status: +- TailwindCSS: $(npm list tailwindcss --depth=0 2>/dev/null | grep tailwindcss || echo "Not installed") +- PostCSS: $(npm list postcss --depth=0 2>/dev/null | grep postcss || echo "Not installed") +- Autoprefixer: $(npm list autoprefixer --depth=0 2>/dev/null | grep autoprefixer || echo "Not installed") + +Configuration Files: +- tailwind.config.js: $([ -f "tailwind.config.js" ] && echo "✅ Present" || echo "❌ Missing") +- postcss.config.js: $([ -f "postcss.config.js" ] && echo "✅ Present" || echo "❌ Missing") +- CSS Entry Point: $(ls src/*.css styles/*.css 2>/dev/null | head -1 || echo "❌ Not found") + +Recommended Plugins: +- @tailwindcss/typography: $(npm list @tailwindcss/typography >/dev/null 2>&1 && echo "✅ Installed" || echo "⚠️ Not installed") +- @tailwindcss/forms: $(npm list @tailwindcss/forms >/dev/null 2>&1 && echo "✅ Installed" || echo "⚠️ Not installed") +- @tailwindcss/aspect-ratio: $(npm list @tailwindcss/aspect-ratio >/dev/null 2>&1 && echo "✅ Installed" || echo "⚠️ Not installed") + +Package Scripts: +$(npm run --silent 2>/dev/null | grep -E "(build|css|watch)" | sed 's/^/- /' || echo "- No relevant scripts found") + +Next Steps: +1. Configure content paths in tailwind.config.js +2. Set up your design system tokens +3. Add dark mode support if needed +4. Install recommended plugins as needed +5. Set up build/watch scripts in package.json + +For detailed configuration examples, check the TailwindCSS documentation: +https://tailwindcss.com/docs/installation +EOF + + print_status $GREEN "✅ Setup report saved to $report_file" +} + +# Main execution +main() { + local start_time=$(date +%s) + + print_status $BLUE "🎨 TailwindCSS Post-Install Setup" + print_status $BLUE "==================================" + + # Run all setup tasks + check_tailwind_installation + verify_recommended_plugins + initialize_config + verify_postcss_config + optimize_package_scripts + create_css_entry + optimize_config + setup_dev_environment + generate_usage_report + + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + + print_status $GREEN "✅ TailwindCSS post-install setup completed in ${duration}s" + print_status $BLUE "🚀 You're ready to start building with TailwindCSS!" + print_status $YELLOW "💡 Run 'cat .tailwindcss-setup-report.txt' to see your setup summary" +} + +# Run the main function +main
\ No newline at end of file diff --git a/ui/tailwindcss/.claude/hooks/pre-commit b/ui/tailwindcss/.claude/hooks/pre-commit new file mode 100755 index 0000000..c7e85b2 --- /dev/null +++ b/ui/tailwindcss/.claude/hooks/pre-commit @@ -0,0 +1,214 @@ +#!/bin/bash + +# TailwindCSS Pre-commit Hook +# Validates TailwindCSS usage and optimizations before commits + +set -e + +echo "🎨 Running TailwindCSS pre-commit checks..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + local color=$1 + local message=$2 + echo -e "${color}${message}${NC}" +} + +# Check if TailwindCSS config exists +check_tailwind_config() { + print_status $BLUE "Checking TailwindCSS configuration..." + + if [[ ! -f "tailwind.config.js" && ! -f "tailwind.config.ts" ]]; then + print_status $RED "❌ No TailwindCSS configuration file found" + exit 1 + fi + + print_status $GREEN "✅ TailwindCSS configuration found" +} + +# Validate CSS utility usage patterns +validate_utility_patterns() { + print_status $BLUE "Validating TailwindCSS utility patterns..." + + # Check for overly long class strings (potential refactoring candidates) + local long_classes=$(grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | \ + sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \ + awk 'length($0) > 150 { print FILENAME ":" FNR ":" $0 }' || true) + + if [[ -n "$long_classes" ]]; then + print_status $YELLOW "⚠️ Found potentially complex utility combinations (>150 characters):" + echo "$long_classes" + print_status $YELLOW "Consider extracting these into components or using @apply directive" + fi + + # Check for hardcoded colors (should use design tokens) + local hardcoded_colors=$(grep -r "bg-\(red\|blue\|green\|yellow\|purple\|pink\|indigo\)-[0-9]" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null || true) + + if [[ -n "$hardcoded_colors" ]]; then + print_status $YELLOW "⚠️ Found hardcoded color utilities. Consider using semantic color tokens:" + echo "$hardcoded_colors" | head -5 + fi + + print_status $GREEN "✅ Utility patterns validated" +} + +# Check for responsive design patterns +validate_responsive_patterns() { + print_status $BLUE "Checking responsive design patterns..." + + # Look for mobile-first violations (desktop-first patterns) + local desktop_first=$(grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | \ + sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \ + grep -E "(^| )(block|flex|grid|hidden)" | \ + grep -E "(lg|xl|2xl):(block|flex|grid|hidden)" | \ + grep -vE "(sm|md):" | head -5 || true) + + if [[ -n "$desktop_first" ]]; then + print_status $YELLOW "⚠️ Potential desktop-first patterns detected. Consider mobile-first approach:" + echo "$desktop_first" + fi + + print_status $GREEN "✅ Responsive patterns checked" +} + +# Build and analyze CSS bundle size +analyze_bundle_size() { + print_status $BLUE "Analyzing CSS bundle size..." + + # Check if build script exists + if npm run --silent 2>/dev/null | grep -q "build\|build:css"; then + # Build CSS + npm run build:css >/dev/null 2>&1 || npm run build >/dev/null 2>&1 || { + print_status $YELLOW "⚠️ Could not run CSS build command" + return 0 + } + + # Find the generated CSS file + local css_file=$(find . -name "*.css" -path "*/dist/*" -o -path "*/build/*" -o -path "*/.next/static/css/*" 2>/dev/null | head -1) + + if [[ -n "$css_file" && -f "$css_file" ]]; then + local size=$(wc -c < "$css_file") + local size_kb=$((size / 1024)) + + print_status $GREEN "📊 CSS bundle size: ${size_kb}KB" + + # Warn if bundle is large + if [[ $size_kb -gt 100 ]]; then + print_status $YELLOW "⚠️ CSS bundle is large (${size_kb}KB). Consider optimization:" + print_status $YELLOW " - Review unused utilities" + print_status $YELLOW " - Optimize content paths in tailwind.config.js" + print_status $YELLOW " - Use CSS purging effectively" + fi + else + print_status $YELLOW "⚠️ Could not find generated CSS file" + fi + else + print_status $YELLOW "⚠️ No build script found in package.json" + fi +} + +# Check for accessibility considerations +validate_accessibility() { + print_status $BLUE "Checking accessibility patterns..." + + # Check for focus states on interactive elements + local missing_focus=$(grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | \ + grep -E "(button|input|select|textarea)" | \ + grep -v "focus:" | head -3 || true) + + if [[ -n "$missing_focus" ]]; then + print_status $YELLOW "⚠️ Interactive elements without focus states detected:" + echo "$missing_focus" + print_status $YELLOW "Consider adding focus: states for accessibility" + fi + + # Check for proper contrast utilities + local low_contrast=$(grep -r "text-gray-[123]00" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null || true) + + if [[ -n "$low_contrast" ]]; then + print_status $YELLOW "⚠️ Potentially low contrast text colors found:" + echo "$low_contrast" | head -3 + print_status $YELLOW "Verify accessibility contrast ratios" + fi + + print_status $GREEN "✅ Accessibility patterns checked" +} + +# Check for performance anti-patterns +validate_performance() { + print_status $BLUE "Checking performance patterns..." + + # Check for layout-shifting animations + local layout_animations=$(grep -r "transition-\(width\|height\|top\|left\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null || true) + + if [[ -n "$layout_animations" ]]; then + print_status $YELLOW "⚠️ Layout-affecting transitions found (may cause performance issues):" + echo "$layout_animations" | head -3 + print_status $YELLOW "Consider using transform-based animations instead" + fi + + # Check for excessive arbitrary values + local arbitrary_values=$(grep -r "\[\w*\]" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $arbitrary_values -gt 10 ]]; then + print_status $YELLOW "⚠️ High usage of arbitrary values ($arbitrary_values instances)" + print_status $YELLOW "Consider adding values to your TailwindCSS configuration" + fi + + print_status $GREEN "✅ Performance patterns checked" +} + +# Validate content configuration +validate_content_config() { + print_status $BLUE "Validating content configuration..." + + local config_file="tailwind.config.js" + if [[ -f "tailwind.config.ts" ]]; then + config_file="tailwind.config.ts" + fi + + # Check if content paths are specific enough + if ! grep -q "components" "$config_file" 2>/dev/null; then + print_status $YELLOW "⚠️ Consider adding specific content paths for better purging" + fi + + # Check for safelist configuration for dynamic classes + if grep -r "class[Name]*=.*\${" src/ --include="*.jsx" --include="*.tsx" >/dev/null 2>&1; then + if ! grep -q "safelist" "$config_file" 2>/dev/null; then + print_status $YELLOW "⚠️ Dynamic class generation detected but no safelist configured" + print_status $YELLOW "Consider adding a safelist to prevent CSS purging of dynamic classes" + fi + fi + + print_status $GREEN "✅ Content configuration validated" +} + +# Main execution +main() { + local start_time=$(date +%s) + + # Run all checks + check_tailwind_config + validate_utility_patterns + validate_responsive_patterns + validate_accessibility + validate_performance + validate_content_config + analyze_bundle_size + + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + + print_status $GREEN "✅ All TailwindCSS checks completed in ${duration}s" + print_status $BLUE "Ready to commit! 🚀" +} + +# Run the main function +main
\ No newline at end of file diff --git a/ui/tailwindcss/.claude/hooks/pre-push b/ui/tailwindcss/.claude/hooks/pre-push new file mode 100755 index 0000000..7520ac6 --- /dev/null +++ b/ui/tailwindcss/.claude/hooks/pre-push @@ -0,0 +1,353 @@ +#!/bin/bash + +# TailwindCSS Pre-push Hook +# Final checks before pushing code to ensure production-ready TailwindCSS usage + +set -e + +echo "🎨 Running TailwindCSS pre-push validation..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + local color=$1 + local message=$2 + echo -e "${color}${message}${NC}" +} + +# Production build test +test_production_build() { + print_status $BLUE "Testing production build..." + + # Check if build script exists + if npm run --silent 2>/dev/null | grep -q "build"; then + print_status $BLUE "Running production build test..." + + # Create a backup of current built files + if [[ -d "dist" ]]; then + mv dist dist.backup + fi + if [[ -d "build" ]]; then + mv build build.backup + fi + if [[ -d ".next" ]]; then + mv .next .next.backup + fi + + # Run build + if npm run build >/dev/null 2>&1; then + print_status $GREEN "✅ Production build successful" + + # Analyze build output + analyze_build_output + else + print_status $RED "❌ Production build failed" + + # Restore backups + restore_backups + exit 1 + fi + + # Restore backups + restore_backups + else + print_status $YELLOW "⚠️ No build script found. Skipping production build test" + fi +} + +# Restore backup directories +restore_backups() { + [[ -d "dist.backup" ]] && rm -rf dist && mv dist.backup dist + [[ -d "build.backup" ]] && rm -rf build && mv build.backup build + [[ -d ".next.backup" ]] && rm -rf .next && mv .next.backup .next +} + +# Analyze build output for CSS optimization +analyze_build_output() { + print_status $BLUE "Analyzing CSS build output..." + + # Find CSS files in build output + local css_files=$(find dist build .next 2>/dev/null -name "*.css" -type f | head -5) + + if [[ -n "$css_files" ]]; then + local total_size=0 + local file_count=0 + + while IFS= read -r file; do + if [[ -f "$file" ]]; then + local size=$(wc -c < "$file") + local size_kb=$((size / 1024)) + total_size=$((total_size + size)) + file_count=$((file_count + 1)) + + print_status $BLUE "📄 $(basename "$file"): ${size_kb}KB" + + # Warn about large CSS files + if [[ $size_kb -gt 200 ]]; then + print_status $YELLOW "⚠️ Large CSS file detected (${size_kb}KB)" + print_status $YELLOW " Consider optimizing TailwindCSS configuration" + fi + fi + done <<< "$css_files" + + local total_kb=$((total_size / 1024)) + print_status $GREEN "📊 Total CSS size: ${total_kb}KB across ${file_count} files" + + # Overall size warning + if [[ $total_kb -gt 500 ]]; then + print_status $RED "❌ CSS bundle too large (${total_kb}KB > 500KB)" + print_status $RED " Optimize before pushing to production" + exit 1 + elif [[ $total_kb -gt 300 ]]; then + print_status $YELLOW "⚠️ CSS bundle size is high (${total_kb}KB)" + print_status $YELLOW " Consider optimization for better performance" + fi + else + print_status $YELLOW "⚠️ No CSS files found in build output" + fi +} + +# Validate CSS purging effectiveness +validate_purging() { + print_status $BLUE "Validating CSS purging effectiveness..." + + # Build CSS for analysis + if command -v npx >/dev/null 2>&1 && [[ -f "tailwind.config.js" ]]; then + # Create temporary input file + echo "@tailwind base; @tailwind components; @tailwind utilities;" > temp-input.css + + # Generate full CSS (no purging) + if npx tailwindcss -i temp-input.css -o temp-full.css >/dev/null 2>&1; then + local full_size=$(wc -c < temp-full.css) + + # Generate purged CSS (with content) + if npx tailwindcss -i temp-input.css -o temp-purged.css --minify >/dev/null 2>&1; then + local purged_size=$(wc -c < temp-purged.css) + local reduction_percent=$(( (full_size - purged_size) * 100 / full_size )) + + print_status $GREEN "✅ CSS purging reduces bundle by ${reduction_percent}%" + print_status $BLUE " Full: $((full_size / 1024))KB → Purged: $((purged_size / 1024))KB" + + # Warn about ineffective purging + if [[ $reduction_percent -lt 70 ]]; then + print_status $YELLOW "⚠️ Low purging effectiveness (${reduction_percent}%)" + print_status $YELLOW " Check content paths in tailwind.config.js" + fi + fi + fi + + # Cleanup temporary files + rm -f temp-input.css temp-full.css temp-purged.css + fi +} + +# Security and best practices validation +validate_security() { + print_status $BLUE "Validating security and best practices..." + + # Check for hardcoded values that might contain sensitive data + local suspicious_patterns=$(grep -r "class[Name]*=.*\(password\|token\|key\|secret\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | head -3 || true) + + if [[ -n "$suspicious_patterns" ]]; then + print_status $YELLOW "⚠️ Suspicious patterns in class names:" + echo "$suspicious_patterns" + fi + + # Check for XSS-prone dynamic class generation + local dynamic_classes=$(grep -r "class[Name]*=.*\${.*}" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l) + + if [[ $dynamic_classes -gt 20 ]]; then + print_status $YELLOW "⚠️ High usage of dynamic class generation (${dynamic_classes} instances)" + print_status $YELLOW " Ensure proper sanitization of user input" + fi + + print_status $GREEN "✅ Security validation completed" +} + +# Performance impact analysis +analyze_performance_impact() { + print_status $BLUE "Analyzing performance impact..." + + # Check for performance-impacting patterns + local heavy_animations=$(grep -r "animate-\(bounce\|ping\|pulse\|spin\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $heavy_animations -gt 20 ]]; then + print_status $YELLOW "⚠️ High usage of animations (${heavy_animations} instances)" + print_status $YELLOW " Consider performance impact on low-end devices" + fi + + # Check for layout-shifting utilities + local layout_shifts=$(grep -r "transition-\(width\|height\|padding\|margin\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $layout_shifts -gt 10 ]]; then + print_status $YELLOW "⚠️ Layout-shifting transitions detected (${layout_shifts} instances)" + print_status $YELLOW " May cause poor Cumulative Layout Shift (CLS) scores" + fi + + # Check for excessive gradient usage + local gradients=$(grep -r "gradient-to-\|from-\|via-\|to-" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $gradients -gt 50 ]]; then + print_status $YELLOW "⚠️ Heavy gradient usage (${gradients} instances)" + print_status $YELLOW " Consider performance impact and CSS bundle size" + fi + + print_status $GREEN "✅ Performance analysis completed" +} + +# Browser compatibility check +check_browser_compatibility() { + print_status $BLUE "Checking browser compatibility..." + + local config_file="tailwind.config.js" + if [[ -f "tailwind.config.ts" ]]; then + config_file="tailwind.config.ts" + fi + + # Check for modern CSS features that might need fallbacks + local modern_features=$(grep -r "\(backdrop-\|container\|aspect-\)" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $modern_features -gt 0 ]]; then + print_status $YELLOW "⚠️ Modern CSS features detected (${modern_features} instances)" + print_status $YELLOW " Verify browser support requirements" + + # Check for autoprefixer + if npm list autoprefixer >/dev/null 2>&1; then + print_status $GREEN "✅ Autoprefixer installed for vendor prefixes" + else + print_status $YELLOW "⚠️ Consider installing autoprefixer for better browser support" + fi + fi + + print_status $GREEN "✅ Browser compatibility check completed" +} + +# Final accessibility audit +final_accessibility_audit() { + print_status $BLUE "Running final accessibility audit..." + + # Check for proper focus management + local focus_traps=$(grep -r "focus-trap\|focus-within\|focus-visible" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $focus_traps -eq 0 ]]; then + print_status $YELLOW "⚠️ No focus management utilities detected" + print_status $YELLOW " Ensure proper keyboard navigation support" + else + print_status $GREEN "✅ Focus management utilities found" + fi + + # Check for color contrast considerations + local contrast_utilities=$(grep -r "contrast-\|brightness-" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $contrast_utilities -gt 0 ]]; then + print_status $GREEN "✅ Color contrast utilities in use" + fi + + # Check for screen reader utilities + local sr_utilities=$(grep -r "sr-only\|not-sr-only" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" 2>/dev/null | wc -l) + + if [[ $sr_utilities -eq 0 ]]; then + print_status $YELLOW "⚠️ No screen reader utilities detected" + print_status $YELLOW " Consider accessibility for screen reader users" + else + print_status $GREEN "✅ Screen reader utilities found" + fi + + print_status $GREEN "✅ Accessibility audit completed" +} + +# Generate pre-push report +generate_push_report() { + print_status $BLUE "Generating pre-push report..." + + local report_file=".tailwindcss-push-report.txt" + local timestamp=$(date) + + cat > "$report_file" << EOF +TailwindCSS Pre-Push Report +=========================== +Generated: $timestamp +Branch: $(git branch --show-current 2>/dev/null || echo "unknown") +Commit: $(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + +Build Status: +$(npm run build >/dev/null 2>&1 && echo "✅ Build successful" || echo "❌ Build failed") + +CSS Bundle Analysis: +$(find dist build .next 2>/dev/null -name "*.css" -type f | while read file; do + if [[ -f "$file" ]]; then + echo "- $(basename "$file"): $(($(wc -c < "$file") / 1024))KB" + fi +done | head -5 || echo "- No CSS files found") + +Code Quality Checks: +- Long class strings: $(grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | awk 'length($0) > 150' | wc -l | tr -d ' ') +- Dynamic classes: $(grep -r "class[Name]*=.*\${.*}" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ') +- Arbitrary values: $(grep -r "\[\w*\]" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ') + +Performance Metrics: +- Animation utilities: $(grep -r "animate-" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ') +- Layout transitions: $(grep -r "transition-\(width\|height\|padding\|margin\)" src/ 2>/dev/null | wc -l | tr -d ' ') +- Gradient usage: $(grep -r "gradient-to-\|from-\|via-\|to-" src/ 2>/dev/null | wc -l | tr -d ' ') + +Accessibility Features: +- Focus utilities: $(grep -r "focus-" src/ --include="*.jsx" --include="*.tsx" 2>/dev/null | wc -l | tr -d ' ') +- Screen reader utilities: $(grep -r "sr-only\|not-sr-only" src/ 2>/dev/null | wc -l | tr -d ' ') + +Recommendations: +$(if grep -r "class[Name]*=['\"][^'\"]*['\"]" src/ 2>/dev/null | sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | awk 'length($0) > 150' | head -1 >/dev/null 2>&1; then echo "- Consider component extraction for long utility combinations"; fi) +$(if [[ $(grep -r "\[\w*\]" src/ 2>/dev/null | wc -l) -gt 10 ]]; then echo "- Consider adding custom utilities to config instead of arbitrary values"; fi) +$(if [[ $(grep -r "animate-" src/ 2>/dev/null | wc -l) -gt 20 ]]; then echo "- Review animation usage for performance impact"; fi) + +Status: $(if npm run build >/dev/null 2>&1; then echo "✅ Ready for production"; else echo "❌ Issues detected - review before pushing"; fi) +EOF + + print_status $GREEN "✅ Pre-push report saved to $report_file" + + # Show critical issues in console + if ! npm run build >/dev/null 2>&1; then + print_status $RED "❌ Build failures detected - see report for details" + return 1 + fi + + return 0 +} + +# Main execution +main() { + local start_time=$(date +%s) + + print_status $BLUE "🎨 TailwindCSS Pre-Push Validation" + print_status $BLUE "====================================" + + # Run all validation tasks + test_production_build + validate_purging + validate_security + analyze_performance_impact + check_browser_compatibility + final_accessibility_audit + + # Generate final report + if generate_push_report; then + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + + print_status $GREEN "✅ All pre-push validations completed in ${duration}s" + print_status $BLUE "🚀 Code is ready for production push!" + print_status $YELLOW "📄 See .tailwindcss-push-report.txt for detailed analysis" + else + print_status $RED "❌ Pre-push validation failed" + print_status $RED "Fix issues before pushing to production" + exit 1 + fi +} + +# Run the main function +main
\ No newline at end of file |
