upskill-event-manager/css-analysis.js
bengizmo 993a820a84 feat: Add comprehensive development artifacts to repository
- Add 26 documentation files including test reports, deployment guides, and troubleshooting documentation
- Include 3 CSV data files for trainer imports and user registration tracking
- Add 43 JavaScript test files covering mobile optimization, Safari compatibility, and E2E testing
- Include 18 PHP utility files for debugging, geocoding, and data analysis
- Add 12 shell scripts for deployment verification, user management, and database operations
- Update .gitignore with whitelist patterns for development files, documentation, and CSV data

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 12:26:11 -03:00

355 lines
No EOL
13 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs');
const path = require('path');
class CSSAnalyzer {
constructor() {
this.issues = [];
this.warnings = [];
this.recommendations = [];
this.browserSupport = {
customProperties: { ie: false, edge: '16+', chrome: '49+', firefox: '31+', safari: '9.1+' },
gridLayout: { ie: '10+ (partial)', edge: '16+', chrome: '57+', firefox: '52+', safari: '10.1+' },
flexbox: { ie: '11+', edge: '12+', chrome: '29+', firefox: '28+', safari: '9+' },
transforms: { ie: '9+', edge: '12+', chrome: '36+', firefox: '16+', safari: '9+' },
transitions: { ie: '10+', edge: '12+', chrome: '26+', firefox: '16+', safari: '6.1+' },
calc: { ie: '9+', edge: '12+', chrome: '26+', firefox: '16+', safari: '7+' }
};
}
analyzeFile(filePath) {
console.log(`\n🔍 Analyzing: ${path.basename(filePath)}`);
console.log('='.repeat(50));
try {
const content = fs.readFileSync(filePath, 'utf8');
const lines = content.split('\n');
this.checkCustomProperties(content, filePath);
this.checkResponsiveDesign(content, filePath);
this.checkAccessibility(content, filePath);
this.checkBrowserCompatibility(content, filePath);
this.checkPerformance(content, filePath);
this.checkCodeQuality(content, filePath);
} catch (error) {
console.error(`❌ Error reading ${filePath}:`, error.message);
}
}
checkCustomProperties(content, filePath) {
const customProps = content.match(/--[\w-]+:/g);
const useCustomProps = content.match(/var\(--[\w-]+\)/g);
if (customProps) {
console.log(`✅ CSS Custom Properties: ${customProps.length} defined`);
// Check for fallbacks
const withFallbacks = content.match(/var\(--[\w-]+,\s*[^)]+\)/g);
if (withFallbacks) {
console.log(`✅ Fallbacks provided: ${withFallbacks.length}`);
} else if (useCustomProps) {
this.warnings.push({
file: filePath,
issue: 'CSS Custom Properties used without fallbacks',
impact: 'Will break in IE and older browsers',
recommendation: 'Add fallback values: var(--color-primary, #0073aa)'
});
console.log(`⚠️ No fallbacks for custom properties (${useCustomProps.length} uses)`);
}
}
}
checkResponsiveDesign(content, filePath) {
const mediaQueries = content.match(/@media[^{]*{/g);
const breakpoints = content.match(/\(max-width:\s*(\d+(?:\.\d+)?)(px|em|rem)\)/g);
if (mediaQueries) {
console.log(`✅ Media Queries: ${mediaQueries.length} found`);
if (breakpoints) {
const uniqueBreakpoints = [...new Set(breakpoints)];
console.log(`📱 Breakpoints: ${uniqueBreakpoints.join(', ')}`);
// Check for common breakpoints
const commonBreakpoints = ['768px', '480px', '1024px', '767px'];
const hasStandardBreakpoints = commonBreakpoints.some(bp =>
content.includes(bp)
);
if (hasStandardBreakpoints) {
console.log(`✅ Uses standard breakpoints`);
} else {
this.recommendations.push({
file: filePath,
recommendation: 'Consider using standard breakpoints (768px, 1024px) for better consistency'
});
}
}
} else {
this.warnings.push({
file: filePath,
issue: 'No responsive design detected',
impact: 'May not work well on mobile devices'
});
console.log(`⚠️ No media queries found`);
}
}
checkAccessibility(content, filePath) {
const focusStyles = content.match(/:focus[^{]*{/g);
const skipLinks = content.includes('skip-link');
const highContrastSupport = content.includes('prefers-color-scheme') ||
content.includes('high-contrast');
if (focusStyles) {
console.log(`✅ Focus Styles: ${focusStyles.length} found`);
} else {
this.issues.push({
file: filePath,
issue: 'No focus styles defined',
impact: 'Poor keyboard navigation accessibility',
severity: 'high'
});
console.log(`❌ No focus styles found`);
}
if (skipLinks) {
console.log(`✅ Skip links implemented`);
}
if (highContrastSupport) {
console.log(`✅ High contrast support detected`);
}
// Check for sufficient color contrast (basic check)
const colorValues = content.match(/#[0-9a-fA-F]{3,6}/g);
if (colorValues) {
console.log(`🎨 Color values: ${[...new Set(colorValues)].length} unique colors`);
}
}
checkBrowserCompatibility(content, filePath) {
const features = {
'grid': /display:\s*grid/g,
'flexbox': /display:\s*flex/g,
'transforms': /transform:/g,
'transitions': /transition:/g,
'calc': /calc\(/g,
'customProperties': /var\(/g
};
console.log(`🌐 Browser Compatibility Check:`);
Object.entries(features).forEach(([feature, regex]) => {
const matches = content.match(regex);
if (matches) {
const support = this.browserSupport[feature];
console.log(` ${feature}: ${matches.length} uses - ${JSON.stringify(support)}`);
if (feature === 'customProperties' && !content.includes('var(--')) {
// This is a false positive, skip
return;
}
if (support.ie === false || support.ie.includes('partial')) {
this.warnings.push({
file: filePath,
issue: `${feature} has limited IE support`,
recommendation: 'Consider progressive enhancement or fallbacks'
});
}
}
});
}
checkPerformance(content, filePath) {
const selectors = content.match(/[^{}]+{/g);
const universalSelectors = content.match(/\*[^{]*/g);
const deepSelectors = content.match(/[^{]+>\s*[^{]+>\s*[^{]+{/g);
if (selectors) {
console.log(`⚡ Performance Analysis:`);
console.log(` Total selectors: ${selectors.length}`);
if (universalSelectors) {
console.log(` ⚠️ Universal selectors: ${universalSelectors.length}`);
this.warnings.push({
file: filePath,
issue: 'Universal selectors detected',
impact: 'May impact performance',
recommendation: 'Use more specific selectors when possible'
});
}
if (deepSelectors) {
console.log(` Deep selectors (3+ levels): ${deepSelectors.length}`);
if (deepSelectors.length > 10) {
this.recommendations.push({
file: filePath,
recommendation: 'Consider reducing selector depth for better performance'
});
}
}
}
// Check file size
const sizeKB = Math.round(content.length / 1024);
console.log(` File size: ${sizeKB}KB`);
if (sizeKB > 50) {
this.recommendations.push({
file: filePath,
recommendation: 'Consider minification and compression for production'
});
}
}
checkCodeQuality(content, filePath) {
const duplicateProperties = this.findDuplicateProperties(content);
const unusedVariables = this.findUnusedVariables(content);
const inconsistentNaming = this.checkNamingConsistency(content);
console.log(`🧹 Code Quality:`);
if (duplicateProperties.length > 0) {
console.log(` ⚠️ Duplicate properties: ${duplicateProperties.length}`);
this.issues.push({
file: filePath,
issue: 'Duplicate CSS properties found',
details: duplicateProperties
});
} else {
console.log(` ✅ No duplicate properties`);
}
if (unusedVariables.length > 0) {
console.log(` ⚠️ Potentially unused variables: ${unusedVariables.length}`);
}
// Check for vendor prefixes
const vendorPrefixes = content.match(/-webkit-|-moz-|-ms-|-o-/g);
if (vendorPrefixes) {
console.log(` 🔧 Vendor prefixes: ${vendorPrefixes.length}`);
}
}
findDuplicateProperties(content) {
// This is a simplified check - in reality, we'd need a CSS parser
const rules = content.match(/{[^}]+}/g) || [];
const duplicates = [];
rules.forEach(rule => {
const properties = rule.match(/[\w-]+\s*:/g) || [];
const propertyNames = properties.map(p => p.replace(/\s*:$/, ''));
const seen = new Set();
propertyNames.forEach(prop => {
if (seen.has(prop)) {
duplicates.push(prop);
}
seen.add(prop);
});
});
return [...new Set(duplicates)];
}
findUnusedVariables(content) {
const defined = content.match(/--[\w-]+/g) || [];
const used = content.match(/var\(--[\w-]+/g) || [];
const definedClean = defined.map(v => v.replace('--', ''));
const usedClean = used.map(v => v.replace('var(--', ''));
return definedClean.filter(v => !usedClean.includes(v));
}
checkNamingConsistency(content) {
const variables = content.match(/--[\w-]+/g) || [];
const classes = content.match(/\.[\w-]+/g) || [];
// Check for consistent naming patterns
const kebabCase = /^[a-z][a-z0-9-]*$/;
const camelCase = /^[a-z][a-zA-Z0-9]*$/;
const inconsistent = [];
[...variables, ...classes].forEach(name => {
const clean = name.replace(/^(--|\.)/g, '');
if (!kebabCase.test(clean) && !camelCase.test(clean)) {
inconsistent.push(name);
}
});
return inconsistent;
}
generateReport() {
console.log('\n' + '='.repeat(80));
console.log('📋 COMPREHENSIVE CSS ANALYSIS REPORT');
console.log('='.repeat(80));
if (this.issues.length > 0) {
console.log('\n❌ CRITICAL ISSUES:');
this.issues.forEach((issue, i) => {
console.log(`${i + 1}. ${issue.issue}`);
console.log(` File: ${path.basename(issue.file)}`);
if (issue.impact) console.log(` Impact: ${issue.impact}`);
if (issue.recommendation) console.log(` Fix: ${issue.recommendation}`);
console.log('');
});
}
if (this.warnings.length > 0) {
console.log('\n⚠ WARNINGS:');
this.warnings.forEach((warning, i) => {
console.log(`${i + 1}. ${warning.issue}`);
console.log(` File: ${path.basename(warning.file)}`);
if (warning.impact) console.log(` Impact: ${warning.impact}`);
if (warning.recommendation) console.log(` Recommendation: ${warning.recommendation}`);
console.log('');
});
}
if (this.recommendations.length > 0) {
console.log('\n💡 RECOMMENDATIONS:');
this.recommendations.forEach((rec, i) => {
console.log(`${i + 1}. ${rec.recommendation}`);
console.log(` File: ${path.basename(rec.file)}`);
console.log('');
});
}
console.log('\n✅ SUMMARY:');
console.log(`Total Issues: ${this.issues.length}`);
console.log(`Total Warnings: ${this.warnings.length}`);
console.log(`Total Recommendations: ${this.recommendations.length}`);
}
}
// Main execution
const analyzer = new CSSAnalyzer();
const cssFiles = [
'./assets/css/hvac-common.css',
'./assets/css/hvac-dashboard.css',
'./assets/css/hvac-registration.css',
'./assets/css/hvac-certificates.css',
'./assets/css/hvac-email-attendees.css',
'./assets/css/hvac-event-summary.css',
'./assets/css/hvac-attendee-profile.css',
'./assets/css/hvac-mobile-nav.css',
'./assets/css/hvac-animations.css',
'./assets/css/hvac-print.css'
];
console.log('🔬 HVAC COMMUNITY EVENTS - CSS DEEP ANALYSIS');
console.log('Starting comprehensive CSS investigation...\n');
cssFiles.forEach(file => {
if (fs.existsSync(file)) {
analyzer.analyzeFile(file);
} else {
console.log(`⚠️ File not found: ${file}`);
}
});
analyzer.generateReport();