summaryrefslogtreecommitdiff
path: root/ui/tailwindcss/.claude/hooks/pre-commit
diff options
context:
space:
mode:
Diffstat (limited to 'ui/tailwindcss/.claude/hooks/pre-commit')
-rwxr-xr-xui/tailwindcss/.claude/hooks/pre-commit214
1 files changed, 214 insertions, 0 deletions
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