- 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>
301 lines
No EOL
9 KiB
JavaScript
301 lines
No EOL
9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* HVAC Community Events CSS Focus Management Fixes
|
|
*
|
|
* This script adds proper focus management styles to ensure WCAG 2.1 compliance
|
|
* and keyboard accessibility across all CSS files.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const CSS_DIR = './assets/css';
|
|
const focusRules = [];
|
|
|
|
// Focus styles to add for different element types
|
|
const FOCUS_PATTERNS = {
|
|
// Interactive elements that need focus indicators
|
|
buttons: [
|
|
'.hvac-button:focus',
|
|
'.hvac-content .button:focus',
|
|
'.hvac-content button:focus',
|
|
'.hvac-content input[type="submit"]:focus',
|
|
'.hvac-email-submit:focus',
|
|
'.hvac-filter-submit:focus',
|
|
'.hvac-certificate-actions button:focus',
|
|
'.hvac-certificate-actions a:focus'
|
|
],
|
|
|
|
// Form inputs
|
|
inputs: [
|
|
'.hvac-form-input:focus',
|
|
'.hvac-content input[type="text"]:focus',
|
|
'.hvac-content input[type="email"]:focus',
|
|
'.hvac-content input[type="password"]:focus',
|
|
'.hvac-content input[type="url"]:focus',
|
|
'.hvac-content textarea:focus',
|
|
'.hvac-content select:focus',
|
|
'.hvac-email-form-row input:focus',
|
|
'.hvac-email-form-row textarea:focus',
|
|
'.hvac-filter-group input:focus',
|
|
'.hvac-filter-group select:focus'
|
|
],
|
|
|
|
// Links and navigation
|
|
links: [
|
|
'.hvac-content a:focus',
|
|
'.hvac-event-link:focus',
|
|
'.hvac-certificate-link:focus',
|
|
'.hvac-attendee-profile-icon:focus',
|
|
'.hvac-dashboard-nav a:focus',
|
|
'.hvac-email-navigation a:focus'
|
|
],
|
|
|
|
// Interactive elements
|
|
interactive: [
|
|
'.hvac-attendee-checkbox:focus',
|
|
'.hvac-select-all-container input[type="checkbox"]:focus',
|
|
'.hvac-modal-close:focus',
|
|
'.hvac-certificate-table tr:focus'
|
|
]
|
|
};
|
|
|
|
// Focus styles definitions
|
|
const FOCUS_STYLES = {
|
|
buttons: `
|
|
outline: 2px solid #005fcc;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);
|
|
border-radius: 4px;`,
|
|
|
|
inputs: `
|
|
outline: 2px solid #005fcc;
|
|
outline-offset: 2px;
|
|
border-color: #005fcc;
|
|
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);`,
|
|
|
|
links: `
|
|
outline: 2px solid #005fcc;
|
|
outline-offset: 2px;
|
|
text-decoration: underline;
|
|
background-color: rgba(0, 95, 204, 0.1);
|
|
border-radius: 2px;`,
|
|
|
|
interactive: `
|
|
outline: 2px solid #005fcc;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);`
|
|
};
|
|
|
|
// Skip focus outline for mouse users (but keep for keyboard)
|
|
const MOUSE_FOCUS_RESET = `
|
|
/* Reset focus for mouse users while preserving keyboard accessibility */
|
|
.js-focus-visible :focus:not(.focus-visible) {
|
|
outline: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* Ensure focus is visible for keyboard users */
|
|
.js-focus-visible .focus-visible {
|
|
outline: 2px solid #005fcc;
|
|
outline-offset: 2px;
|
|
}`;
|
|
|
|
function addFocusStylesToFile(filePath) {
|
|
try {
|
|
let content = fs.readFileSync(filePath, 'utf8');
|
|
let modifications = 0;
|
|
|
|
console.log(`\nProcessing: ${path.basename(filePath)}`);
|
|
|
|
// Check if focus styles already exist
|
|
if (content.includes('/* Focus Management Styles */')) {
|
|
console.log(' ✓ Focus styles already exist, skipping');
|
|
return 0;
|
|
}
|
|
|
|
// Add focus styles section
|
|
const focusSection = `
|
|
|
|
/* Focus Management Styles - WCAG 2.1 Compliance */
|
|
/* Added for keyboard accessibility and screen reader support */
|
|
|
|
/* Button Focus Styles */
|
|
${FOCUS_PATTERNS.buttons.join(',\n')} {${FOCUS_STYLES.buttons}
|
|
}
|
|
|
|
/* Input Focus Styles */
|
|
${FOCUS_PATTERNS.inputs.join(',\n')} {${FOCUS_STYLES.inputs}
|
|
}
|
|
|
|
/* Link Focus Styles */
|
|
${FOCUS_PATTERNS.links.join(',\n')} {${FOCUS_STYLES.links}
|
|
}
|
|
|
|
/* Interactive Element Focus Styles */
|
|
${FOCUS_PATTERNS.interactive.join(',\n')} {${FOCUS_STYLES.interactive}
|
|
}
|
|
|
|
/* High Contrast Mode Support */
|
|
@media (prefers-contrast: high) {
|
|
.hvac-content *:focus {
|
|
outline: 3px solid #000000;
|
|
outline-offset: 2px;
|
|
background-color: #ffff00;
|
|
color: #000000;
|
|
}
|
|
}
|
|
|
|
/* Focus-visible polyfill support */
|
|
${MOUSE_FOCUS_RESET}
|
|
`;
|
|
|
|
// Add the focus section before the last closing brace or at the end
|
|
if (content.includes('@media print')) {
|
|
// Insert before print styles
|
|
content = content.replace('@media print', focusSection + '\n@media print');
|
|
} else {
|
|
// Add at the end
|
|
content += focusSection;
|
|
}
|
|
|
|
modifications++;
|
|
|
|
// Write the updated content
|
|
fs.writeFileSync(filePath, content, 'utf8');
|
|
|
|
console.log(` ✓ Added ${modifications} focus management sections`);
|
|
focusRules.push({
|
|
file: path.basename(filePath),
|
|
modifications: modifications
|
|
});
|
|
|
|
return modifications;
|
|
|
|
} catch (error) {
|
|
console.error(`Error processing ${filePath}:`, error.message);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function addFocusIndicatorsToAnimations() {
|
|
const animationsPath = path.join(CSS_DIR, 'hvac-animations.css');
|
|
|
|
try {
|
|
let content = fs.readFileSync(animationsPath, 'utf8');
|
|
|
|
// Check if focus-specific animations already exist
|
|
if (content.includes('/* Focus Animation Styles */')) {
|
|
console.log(' ✓ Animations file already has focus styles');
|
|
return 0;
|
|
}
|
|
|
|
const focusAnimations = `
|
|
|
|
/* Focus Animation Styles */
|
|
/* Smooth transitions for focus indicators */
|
|
|
|
.hvac-content *:focus {
|
|
transition: outline 0.2s ease-out,
|
|
box-shadow 0.2s ease-out,
|
|
background-color 0.2s ease-out;
|
|
}
|
|
|
|
/* Focus indicator animation for better visibility */
|
|
@keyframes focus-pulse {
|
|
0% { box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.3); }
|
|
50% { box-shadow: 0 0 0 5px rgba(0, 95, 204, 0.2); }
|
|
100% { box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.3); }
|
|
}
|
|
|
|
/* Apply focus pulse to critical interactive elements */
|
|
.hvac-button:focus,
|
|
.hvac-email-submit:focus,
|
|
.hvac-content button[type="submit"]:focus {
|
|
animation: focus-pulse 2s ease-in-out infinite;
|
|
}
|
|
|
|
/* Disable focus animations for reduced motion users */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.hvac-content *:focus {
|
|
transition: none;
|
|
animation: none;
|
|
}
|
|
}`;
|
|
|
|
// Add before the reduced motion section
|
|
content = content.replace(
|
|
'/* Disable animations for users who prefer reduced motion */',
|
|
focusAnimations + '\n\n/* Disable animations for users who prefer reduced motion */'
|
|
);
|
|
|
|
fs.writeFileSync(animationsPath, content, 'utf8');
|
|
console.log(' ✓ Added focus animations to hvac-animations.css');
|
|
|
|
return 1;
|
|
} catch (error) {
|
|
console.error(`Error updating animations file:`, error.message);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
console.log('HVAC Community Events - CSS Focus Management Fixes');
|
|
console.log('='.repeat(60));
|
|
|
|
if (!fs.existsSync(CSS_DIR)) {
|
|
console.error(`CSS directory not found: ${CSS_DIR}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const cssFiles = fs.readdirSync(CSS_DIR)
|
|
.filter(file => file.endsWith('.css'))
|
|
.map(file => path.join(CSS_DIR, file));
|
|
|
|
let totalModifications = 0;
|
|
|
|
// Process each CSS file
|
|
cssFiles.forEach(filePath => {
|
|
totalModifications += addFocusStylesToFile(filePath);
|
|
});
|
|
|
|
// Add focus-specific animations
|
|
totalModifications += addFocusIndicatorsToAnimations();
|
|
|
|
console.log('\n' + '='.repeat(60));
|
|
console.log('FOCUS MANAGEMENT FIX SUMMARY');
|
|
console.log('='.repeat(60));
|
|
|
|
focusRules.forEach(rule => {
|
|
console.log(`${rule.file}: ${rule.modifications} focus sections added`);
|
|
});
|
|
|
|
console.log(`\nTotal files processed: ${cssFiles.length}`);
|
|
console.log(`Total focus modifications: ${totalModifications}`);
|
|
|
|
if (totalModifications > 0) {
|
|
console.log('\n✅ Focus management fixes applied successfully!');
|
|
console.log('\nKey improvements:');
|
|
console.log('• Added WCAG 2.1 compliant focus indicators');
|
|
console.log('• Implemented keyboard navigation support');
|
|
console.log('• Added high contrast mode compatibility');
|
|
console.log('• Included focus-visible polyfill support');
|
|
console.log('• Added smooth focus transitions');
|
|
console.log('• Respect user motion preferences');
|
|
|
|
console.log('\n📋 Next Steps:');
|
|
console.log('• Test keyboard navigation across all pages');
|
|
console.log('• Verify screen reader compatibility');
|
|
console.log('• Check high contrast mode display');
|
|
console.log('• Add focus-visible.js polyfill to pages');
|
|
} else {
|
|
console.log('\n✅ All CSS files already have focus management styles');
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
module.exports = { addFocusStylesToFile, FOCUS_PATTERNS, FOCUS_STYLES }; |