/** * MorphGuard Context-Aware Theme Integration * * This module integrates the dynamic theming system with the application context, * adapting themes based on: * 1. User activity and behavior patterns * 2. Application state and content * 3. Environmental signals * 4. Task-specific optimizations */ class ContextTheme { constructor(options = {}) { // Default options this.options = { detectionResultTheming: true, // Change theme based on detection results dataVisualizationTheming: true, // Optimize for data visualization attentionModeEnabled: true, // Focus mode for important tasks securityAlertTheming: true, // Special theme for security alerts adaptToContentDensity: true, // Adjust based on content density accessibilityAdaptation: true, // Adjust based on accessibility needs behavioralAdaptation: true, // Learn from user behavior ...options }; // Get theme manager instance this.themeManager = window.morphGuardTheme; if (!this.themeManager) { console.error('Theme manager not found. Ensure dynamic_theme.js is loaded first.'); return; } // Application context state this.appContext = { currentView: null, currentTask: null, detectionResult: null, securityAlerts: [], contentDensity: 'normal', userBehavior: { prefersDarkMode: null, prefersHighContrast: null, clickPatterns: [], sessionDuration: 0, frequentActions: {} }, accessibilityNeeds: { reducedMotion: false, highContrast: false, largerText: false }, environment: { cpuUsage: null, memoryUsage: null, batteryStatus: null, networkStatus: 'online' } }; // Task-specific theme overrides this.taskThemes = { detection: { variables: { '--accent-primary': '#3b82f6', // Blue focus for detection '--card-bg': 'rgba(59, 130, 246, 0.05)' } }, demorph: { variables: { '--accent-primary': '#8b5cf6', // Purple focus for demorphing '--card-bg': 'rgba(139, 92, 246, 0.05)' } }, training: { variables: { '--accent-primary': '#10b981', // Green focus for training '--card-bg': 'rgba(16, 185, 129, 0.05)' } }, security: { variables: { '--accent-primary': '#ef4444', // Red focus for security '--card-bg': 'rgba(239, 68, 68, 0.05)', '--border-color': 'rgba(239, 68, 68, 0.3)' } }, analytics: { variables: { '--accent-primary': '#f59e0b', // Amber focus for analytics '--card-bg': 'rgba(245, 158, 11, 0.05)', '--chart-grid': 'rgba(245, 158, 11, 0.2)' } } }; // Detection result theme modifiers this.detectionThemes = { morphed: { variables: { '--card-bg': 'var(--detection-morph)', '--border-color': 'var(--error)' } }, real: { variables: { '--card-bg': 'var(--detection-safe)', '--border-color': 'var(--success)' } } }; // Initialize this.init(); } /** * Initialize the context-aware theme integration */ init() { // Detect initial context this.detectInitialContext(); // Add observers for context changes this.setupContextObservers(); // Add theme manager observer this.themeManager.addObserver((event) => { // When theme changes from outside, update our state but don't override if (event.type === 'themeChange' && !this.isContextOverride) { this.baseTheme = event.theme; } }); // Store base theme this.baseTheme = this.themeManager.activeTheme; // Context override flag this.isContextOverride = false; // Expose on window for debugging window.morphGuardContextTheme = this; console.log('MorphGuard Context Theme initialized'); } /** * Detect initial application context */ detectInitialContext() { // Check URL for current view const path = window.location.pathname; if (path.includes('/demo')) { this.appContext.currentView = 'demo'; } else if (path.includes('/setup')) { this.appContext.currentView = 'setup'; } else if (path.includes('/lead')) { this.appContext.currentView = 'lead'; } else if (path === '/') { this.appContext.currentView = 'landing'; } // Check for reduced motion preference this.appContext.accessibilityNeeds.reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; // Update theme based on initial context this.updateThemeForContext(); // Detect environment this.detectEnvironment(); } /** * Setup observers for context changes */ setupContextObservers() { // Watch for view changes via navigation this.observeNavigation(); // Watch for detection results this.observeDetectionResults(); // Watch for security alerts this.observeSecurityAlerts(); // Watch for task changes this.observeTaskChanges(); // Track user behavior this.trackUserBehavior(); // Monitor environment this.monitorEnvironment(); } /** * Observe navigation for view changes */ observeNavigation() { // Listen for clicks on navigation links document.addEventListener('click', (e) => { try { // Check if a navigation link was clicked const link = e.target.closest('a'); if (link && link.href && link.href.startsWith(window.location.origin)) { const path = new URL(link.href).pathname; // Determine view from path let view = 'unknown'; if (path.includes('/demo')) { view = 'demo'; } else if (path.includes('/setup')) { view = 'setup'; } else if (path.includes('/lead')) { view = 'lead'; } else if (path === '/') { view = 'landing'; } // Update context if view changed if (view !== this.appContext.currentView) { this.appContext.currentView = view; // Defer theme update to prevent browser from cancelling navigation inside iframes setTimeout(() => { this.updateThemeForContext(); }, 0); } } } catch (err) { console.error('Error in observeNavigation click listener:', err); } }); // Add history state change listener window.addEventListener('popstate', () => { const path = window.location.pathname; // Determine view from path let view = 'unknown'; if (path.includes('/demo')) { view = 'demo'; } else if (path.includes('/setup')) { view = 'setup'; } else if (path.includes('/lead')) { view = 'lead'; } else if (path === '/') { view = 'landing'; } // Update context if view changed if (view !== this.appContext.currentView) { this.appContext.currentView = view; this.updateThemeForContext(); } }); } /** * Observe detection results */ observeDetectionResults() { // Watch for detection result elements being added to the DOM const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type === 'childList') { // Check for detection result elements const detectionResult = document.querySelector('.detection-result'); if (detectionResult) { // Extract result from data attributes const isMorphed = detectionResult.getAttribute('data-is-morphed') === 'true'; const confidence = parseFloat(detectionResult.getAttribute('data-confidence') || '0'); // Update context this.appContext.detectionResult = { isMorphed, confidence }; // Apply theme if enabled if (this.options.detectionResultTheming) { this.applyDetectionResultTheme(isMorphed); } } } } }); // Start observing observer.observe(document.body, { childList: true, subtree: true }); // Listen for custom detection events document.addEventListener('morphguard:detection', (e) => { if (e.detail && typeof e.detail.isMorphed !== 'undefined') { // Update context this.appContext.detectionResult = { isMorphed: e.detail.isMorphed, confidence: e.detail.confidence || 0 }; // Apply theme if enabled if (this.options.detectionResultTheming) { this.applyDetectionResultTheme(e.detail.isMorphed); } } }); } /** * Observe security alerts */ observeSecurityAlerts() { // Watch for alert elements being added to the DOM const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type === 'childList') { // Check for alert elements const alerts = document.querySelectorAll('.alert-security, .security-alert'); if (alerts.length > 0) { // Update context this.appContext.securityAlerts = Array.from(alerts).map(alert => ({ message: alert.textContent, level: alert.getAttribute('data-level') || 'warning', timestamp: new Date().toISOString() })); // Apply theme if enabled if (this.options.securityAlertTheming && this.appContext.securityAlerts.length > 0) { this.applySecurityAlertTheme(); } } } } }); // Start observing observer.observe(document.body, { childList: true, subtree: true }); // Listen for custom alert events document.addEventListener('morphguard:alert', (e) => { if (e.detail) { // Add alert to context this.appContext.securityAlerts.push({ message: e.detail.message || 'Security alert', level: e.detail.level || 'warning', timestamp: new Date().toISOString() }); // Apply theme if enabled if (this.options.securityAlertTheming && this.appContext.securityAlerts.length > 0) { this.applySecurityAlertTheme(); } } }); } /** * Observe task changes */ observeTaskChanges() { // Watch for task indicator elements const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type === 'childList') { // Check for task indicator elements const taskIndicator = document.querySelector('[data-current-task]'); if (taskIndicator) { const task = taskIndicator.getAttribute('data-current-task'); if (task && task !== this.appContext.currentTask) { this.appContext.currentTask = task; this.applyTaskTheme(task); } } } } }); // Start observing observer.observe(document.body, { childList: true, subtree: true }); // Check for task buttons document.addEventListener('click', (e) => { try { // Check for task buttons const taskButton = e.target.closest('[data-task]'); if (taskButton) { const task = taskButton.getAttribute('data-task'); if (task && task !== this.appContext.currentTask) { this.appContext.currentTask = task; this.applyTaskTheme(task); } } } catch (err) { console.error('Error in task button click listener:', err); } }); // Listen for custom task events document.addEventListener('morphguard:task', (e) => { if (e.detail && e.detail.task) { this.appContext.currentTask = e.detail.task; this.applyTaskTheme(e.detail.task); } }); } /** * Track user behavior for behavioral adaptation */ trackUserBehavior() { if (!this.options.behavioralAdaptation) return; // Session start time const sessionStart = Date.now(); // Periodically update session duration setInterval(() => { this.appContext.userBehavior.sessionDuration = (Date.now() - sessionStart) / 1000; }, 60000); // Every minute document.addEventListener('click', (e) => { try { // Record the clicked element const target = e.target; if (!target) return; const elementType = target.tagName ? target.tagName.toLowerCase() : 'unknown'; const classNames = target.classList ? Array.from(target.classList).join(' ') : ''; // Add to click patterns this.appContext.userBehavior.clickPatterns.push({ elementType, classNames, timestamp: new Date().toISOString() }); // Limit array size if (this.appContext.userBehavior.clickPatterns.length > 100) { this.appContext.userBehavior.clickPatterns.shift(); } // Track frequent actions const actionKey = `${elementType}:${classNames}`; this.appContext.userBehavior.frequentActions[actionKey] = (this.appContext.userBehavior.frequentActions[actionKey] || 0) + 1; // Analyze patterns periodically this.analyzeUserBehavior(); } catch (err) { console.error('Error in click pattern tracking listener:', err); } }); // Check initial theme preference this.appContext.userBehavior.prefersDarkMode = this.themeManager.isDarkTheme(this.themeManager.currentTheme); // Check for high contrast preference this.appContext.userBehavior.prefersHighContrast = this.themeManager.currentTheme === 'highContrast'; // Check for accessibility preferences const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (reducedMotion) { this.appContext.accessibilityNeeds.reducedMotion = true; } } /** * Monitor environment */ monitorEnvironment() { // Check network status window.addEventListener('online', () => { this.appContext.environment.networkStatus = 'online'; }); window.addEventListener('offline', () => { this.appContext.environment.networkStatus = 'offline'; // Apply offline theme if needed this.applyOfflineTheme(); }); // Monitor battery status if available if ('getBattery' in navigator) { navigator.getBattery().then(battery => { // Update battery status const updateBattery = () => { this.appContext.environment.batteryStatus = { level: battery.level, charging: battery.charging }; // Apply low battery theme if needed if (battery.level < 0.2 && !battery.charging) { this.applyLowBatteryTheme(); } }; // Listen for battery changes battery.addEventListener('levelchange', updateBattery); battery.addEventListener('chargingchange', updateBattery); // Initial update updateBattery(); }); } // Monitor content density this.monitorContentDensity(); } /** * Monitor content density */ monitorContentDensity() { if (!this.options.adaptToContentDensity) return; // Calculate content density periodically const calculateDensity = () => { const contentArea = document.querySelector('main') || document.body; const contentHeight = contentArea.scrollHeight; const viewportHeight = window.innerHeight; const density = contentHeight / viewportHeight; // Categorize density let densityCategory = 'normal'; if (density > 3) { densityCategory = 'very-high'; } else if (density > 2) { densityCategory = 'high'; } else if (density < 0.5) { densityCategory = 'low'; } // Update context if changed if (densityCategory !== this.appContext.contentDensity) { this.appContext.contentDensity = densityCategory; // Apply theme adjustments if needed this.applyContentDensityTheme(densityCategory); } }; // Calculate initially and on resize calculateDensity(); window.addEventListener('resize', calculateDensity); // Also recalculate periodically in case content changes setInterval(calculateDensity, 5000); } /** * Detect environment factors */ detectEnvironment() { // Check network status this.appContext.environment.networkStatus = navigator.onLine ? 'online' : 'offline'; // Check if running in a resource-constrained environment const isLowPower = window.navigator.hardwareConcurrency <= 2; if (isLowPower) { // Apply low-power optimizations this.applyLowPowerTheme(); } } /** * Update theme based on current context */ updateThemeForContext() { // View-specific theming switch (this.appContext.currentView) { case 'demo': // For demo view, use accent colors that highlight detection functions this.applyViewTheme('demo'); break; case 'setup': // For setup view, use accent colors that indicate configuration this.applyViewTheme('setup'); break; case 'lead': // For lead view, use accent colors that are inviting this.applyViewTheme('lead'); break; case 'landing': // For landing view, use bold, attention-grabbing colors this.applyViewTheme('landing'); break; default: // Reset to base theme this.resetToBaseTheme(); break; } } /** * Apply theme for specific view */ applyViewTheme(view) { let themeVariables = {}; switch (view) { case 'demo': themeVariables = { '--accent-primary': '#3b82f6', // Blue '--accent-secondary': '#60a5fa' }; break; case 'setup': themeVariables = { '--accent-primary': '#8b5cf6', // Purple '--accent-secondary': '#a78bfa' }; break; case 'lead': themeVariables = { '--accent-primary': '#10b981', // Green '--accent-secondary': '#34d399' }; break; case 'landing': themeVariables = { '--accent-primary': '#f59e0b', // Amber '--accent-secondary': '#fbbf24' }; break; } // Apply temporary theme variables this.applyThemeVariables(themeVariables); } /** * Apply theme for detection result */ applyDetectionResultTheme(isMorphed) { // Apply theme based on detection result const themeVariables = isMorphed ? this.detectionThemes.morphed.variables : this.detectionThemes.real.variables; // Apply temporary theme variables this.applyThemeVariables(themeVariables); // Set timeout to reset theme after a few seconds setTimeout(() => { this.resetToBaseTheme(); }, 5000); } /** * Apply theme for security alerts */ applySecurityAlertTheme() { // Get the highest severity alert const alerts = this.appContext.securityAlerts; let highestSeverity = 'info'; for (const alert of alerts) { if (alert.level === 'critical') { highestSeverity = 'critical'; break; } else if (alert.level === 'high' && highestSeverity !== 'critical') { highestSeverity = 'high'; } else if (alert.level === 'medium' && highestSeverity !== 'critical' && highestSeverity !== 'high') { highestSeverity = 'medium'; } } // Apply theme based on severity let themeVariables = {}; switch (highestSeverity) { case 'critical': themeVariables = { '--accent-primary': '#dc2626', // Bright red '--accent-secondary': '#ef4444', '--border-color': 'rgba(220, 38, 38, 0.5)', '--card-bg': 'rgba(220, 38, 38, 0.05)' }; break; case 'high': themeVariables = { '--accent-primary': '#ea580c', // Orange '--accent-secondary': '#f97316', '--border-color': 'rgba(234, 88, 12, 0.5)', '--card-bg': 'rgba(234, 88, 12, 0.05)' }; break; case 'medium': themeVariables = { '--accent-primary': '#f59e0b', // Amber '--accent-secondary': '#fbbf24', '--border-color': 'rgba(245, 158, 11, 0.5)', '--card-bg': 'rgba(245, 158, 11, 0.05)' }; break; default: themeVariables = { '--accent-primary': '#3b82f6', // Blue '--accent-secondary': '#60a5fa', '--border-color': 'rgba(59, 130, 246, 0.5)', '--card-bg': 'rgba(59, 130, 246, 0.05)' }; } // Apply temporary theme variables this.applyThemeVariables(themeVariables); } /** * Apply theme for specific task */ applyTaskTheme(task) { if (!this.taskThemes[task]) { this.resetToBaseTheme(); return; } // Apply task-specific theme this.applyThemeVariables(this.taskThemes[task].variables); } /** * Apply theme for offline mode */ applyOfflineTheme() { // Use grayscale theme for offline mode const themeVariables = { '--accent-primary': '#6b7280', // Gray '--accent-secondary': '#9ca3af', '--border-color': '#d1d5db' }; // Apply temporary theme variables this.applyThemeVariables(themeVariables); } /** * Apply theme for low battery */ applyLowBatteryTheme() { // Force dark theme to save power if (!this.themeManager.isDarkTheme(this.themeManager.activeTheme)) { this.isContextOverride = true; this.themeManager.setTheme('dark'); this.isContextOverride = false; } } /** * Apply theme for low-power devices */ applyLowPowerTheme() { // Disable animations document.documentElement.style.setProperty('--transition-normal', '0s'); document.documentElement.style.setProperty('--transition-fast', '0s'); document.documentElement.style.setProperty('--transition-slow', '0s'); // Use simpler theme const themeVariables = { '--shadow-sm': 'none', '--shadow-md': 'none', '--shadow-lg': 'none', '--shadow-xl': 'none' }; // Apply theme variables this.applyThemeVariables(themeVariables); } /** * Apply theme based on content density */ applyContentDensityTheme(density) { let themeVariables = {}; switch (density) { case 'very-high': // For very high density, reduce spacing and increase contrast themeVariables = { '--spacing-md': '0.5rem', '--spacing-lg': '1rem', '--spacing-xl': '1.5rem', '--text-primary': this.themeManager.isDarkTheme(this.themeManager.activeTheme) ? '#ffffff' : '#000000' }; break; case 'high': // For high density, slightly reduce spacing themeVariables = { '--spacing-md': '0.75rem', '--spacing-lg': '1.25rem', '--spacing-xl': '1.75rem' }; break; case 'low': // For low density, increase spacing themeVariables = { '--spacing-md': '1.25rem', '--spacing-lg': '2rem', '--spacing-xl': '3rem' }; break; default: // Reset to defaults themeVariables = { '--spacing-md': '1rem', '--spacing-lg': '1.5rem', '--spacing-xl': '2rem' }; } // Apply theme variables this.applyThemeVariables(themeVariables); } /** * Apply theme variables without changing base theme */ applyThemeVariables(variables) { // Mark as context override this.isContextOverride = true; // Apply variables for (const [property, value] of Object.entries(variables)) { document.documentElement.style.setProperty(property, value); } // Clear context override flag this.isContextOverride = false; } /** * Reset to base theme */ resetToBaseTheme() { // Only reset if this is a context override if (this.isContextOverride) { // Get current theme configuration const theme = this.themeManager.themes[this.baseTheme] || this.themeManager.themes.light; // Reset all variables for (const [property, value] of Object.entries(theme.variables)) { document.documentElement.style.setProperty(property, value); } // Clear context override flag this.isContextOverride = false; } } /** * Analyze user behavior for behavioral adaptation */ analyzeUserBehavior() { // Skip if behavioral adaptation is disabled if (!this.options.behavioralAdaptation) return; // Only analyze periodically if (!this._lastAnalysisTime || (Date.now() - this._lastAnalysisTime > 60000)) { this._lastAnalysisTime = Date.now(); // Analyze click patterns this.analyzeClickPatterns(); // Check for frequent actions this.checkFrequentActions(); // Check for accessibility needs this.checkAccessibilityNeeds(); } } /** * Analyze click patterns */ analyzeClickPatterns() { const patterns = this.appContext.userBehavior.clickPatterns; if (patterns.length < 10) return; // Example analysis: check if user frequently clicks on the same elements const elementCounts = {}; patterns.forEach(pattern => { const key = `${pattern.elementType}:${pattern.classNames}`; elementCounts[key] = (elementCounts[key] || 0) + 1; }); // Find most frequently clicked elements const sortedElements = Object.entries(elementCounts) .sort((a, b) => b[1] - a[1]) .slice(0, 3); // If there's a clear favorite, highlight it in the theme if (sortedElements.length > 0 && sortedElements[0][1] > patterns.length * 0.3) { const favElement = sortedElements[0][0].split(':')[1]; // If the favorite element is a navigation item, highlight that section if (favElement.includes('nav') || favElement.includes('menu')) { const section = this.getNavigationSection(favElement); if (section) { this.highlightSection(section); } } } } /** * Check for frequent actions */ checkFrequentActions() { const actions = this.appContext.userBehavior.frequentActions; const totalActions = Object.values(actions).reduce((sum, count) => sum + count, 0); // Skip if not enough actions if (totalActions < 20) return; // Check if user frequently performs certain actions for (const [action, count] of Object.entries(actions)) { // If action is performed frequently if (count > totalActions * 0.2) { // Check for specific actions if (action.includes('detection') || action.includes('detect')) { // User frequently uses detection - optimize UI for that this.optimizeUIForDetection(); } else if (action.includes('demorph')) { // User frequently uses demorphing - optimize UI for that this.optimizeUIForDemorphing(); } else if (action.includes('training') || action.includes('train')) { // User frequently uses training - optimize UI for that this.optimizeUIForTraining(); } } } } /** * Check for accessibility needs */ checkAccessibilityNeeds() { if (!this.options.accessibilityAdaptation) return; // Check if user might need high contrast const highContrastClicks = this.appContext.userBehavior.clickPatterns.filter( pattern => pattern.classNames.includes('high-contrast') || pattern.classNames.includes('zoom') || pattern.classNames.includes('accessibility') ).length; // If user has clicked on accessibility-related elements if (highContrastClicks > 0 && !this.appContext.accessibilityNeeds.highContrast) { this.appContext.accessibilityNeeds.highContrast = true; // Suggest high contrast theme this.suggestHighContrastTheme(); } // Check if user might need larger text const textSizeClicks = this.appContext.userBehavior.clickPatterns.filter( pattern => pattern.classNames.includes('text-size') || pattern.classNames.includes('font-size') || pattern.classNames.includes('zoom') ).length; // If user has clicked on text size elements if (textSizeClicks > 0 && !this.appContext.accessibilityNeeds.largerText) { this.appContext.accessibilityNeeds.largerText = true; // Apply larger text this.applyLargerText(); } } /** * Get navigation section from element class */ getNavigationSection(className) { // Parse class names to find section indicators const sections = ['detection', 'demorph', 'training', 'setup', 'analytics']; for (const section of sections) { if (className.includes(section)) { return section; } } return null; } /** * Highlight a specific section in the theme */ highlightSection(section) { // Apply task-specific theme if available if (this.taskThemes[section]) { this.applyThemeVariables(this.taskThemes[section].variables); } else { // Generic highlight this.applyThemeVariables({ '--accent-primary': '#3b82f6', '--card-bg': 'rgba(59, 130, 246, 0.05)' }); } } /** * Optimize UI for detection tasks */ optimizeUIForDetection() { // Apply detection-optimized theme this.applyThemeVariables({ '--accent-primary': '#3b82f6', // Blue focus for detection '--card-bg': 'rgba(59, 130, 246, 0.05)' }); // Find and enhance detection UI elements const detectionButtons = document.querySelectorAll('[data-task="detection"], .detection-button'); detectionButtons.forEach(button => { button.style.transform = 'scale(1.05)'; button.style.boxShadow = '0 4px 6px rgba(59, 130, 246, 0.25)'; }); } /** * Optimize UI for demorphing tasks */ optimizeUIForDemorphing() { // Apply demorphing-optimized theme this.applyThemeVariables({ '--accent-primary': '#8b5cf6', // Purple focus for demorphing '--card-bg': 'rgba(139, 92, 246, 0.05)' }); // Find and enhance demorphing UI elements const demorphButtons = document.querySelectorAll('[data-task="demorph"], .demorph-button'); demorphButtons.forEach(button => { button.style.transform = 'scale(1.05)'; button.style.boxShadow = '0 4px 6px rgba(139, 92, 246, 0.25)'; }); } /** * Optimize UI for training tasks */ optimizeUIForTraining() { // Apply training-optimized theme this.applyThemeVariables({ '--accent-primary': '#10b981', // Green focus for training '--card-bg': 'rgba(16, 185, 129, 0.05)' }); // Find and enhance training UI elements const trainingButtons = document.querySelectorAll('[data-task="training"], .training-button'); trainingButtons.forEach(button => { button.style.transform = 'scale(1.05)'; button.style.boxShadow = '0 4px 6px rgba(16, 185, 129, 0.25)'; }); } /** * Suggest high contrast theme */ suggestHighContrastTheme() { // Create suggestion element if not exists if (!document.querySelector('.theme-suggestion')) { const suggestion = document.createElement('div'); suggestion.className = 'theme-suggestion'; suggestion.innerHTML = `

Would you prefer a high contrast theme for better visibility?

`; // Add styles suggestion.style.position = 'fixed'; suggestion.style.bottom = '20px'; suggestion.style.right = '20px'; suggestion.style.maxWidth = '300px'; suggestion.style.backgroundColor = 'var(--card-bg)'; suggestion.style.borderRadius = 'var(--radius-lg)'; suggestion.style.boxShadow = 'var(--shadow-lg)'; suggestion.style.padding = 'var(--spacing-md)'; suggestion.style.zIndex = '1000'; // Add to document document.body.appendChild(suggestion); // Add event listeners document.getElementById('apply-high-contrast').addEventListener('click', () => { this.themeManager.setTheme('highContrast'); suggestion.remove(); }); document.getElementById('dismiss-suggestion').addEventListener('click', () => { suggestion.remove(); }); } } /** * Apply larger text */ applyLargerText() { // Increase font size variables this.applyThemeVariables({ '--font-size-xs': '0.875rem', // Increase from 0.75rem '--font-size-sm': '1rem', // Increase from 0.875rem '--font-size-md': '1.125rem', // Increase from 1rem '--font-size-lg': '1.25rem', // Increase from 1.125rem '--font-size-xl': '1.5rem', // Increase from 1.25rem '--font-size-2xl': '1.875rem' // Increase from 1.5rem }); } /** * Get current context state */ getContext() { return { appContext: { ...this.appContext }, isContextOverride: this.isContextOverride, baseTheme: this.baseTheme }; } } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', () => { // Check if theme manager is loaded if (window.morphGuardTheme) { // Initialize context theme window.morphGuardContextTheme = new ContextTheme(); } else { // Wait for theme manager to load const checkInterval = setInterval(() => { if (window.morphGuardTheme) { window.morphGuardContextTheme = new ContextTheme(); clearInterval(checkInterval); } }, 100); // Stop checking after 5 seconds setTimeout(() => { clearInterval(checkInterval); }, 5000); } }); // Export for module use if (typeof module !== 'undefined' && module.exports) { module.exports = ContextTheme; }