/** * Contextual Hint System * * A subtle, non-intrusive tooltip system providing just-in-time guidance and learning * for the Quantum NLP Framework. This system detects when a user might need help * understanding a feature and provides relevant information without disrupting workflow. */ class ContextualHintSystem { constructor() { this.hints = {}; this.activeHint = null; this.hintContainer = null; this.shownHints = []; this.initialize(); } /** * Initialize the hint system */ initialize() { // Load previously shown hints this.loadShownHints(); // Register predefined hints this.registerPredefinedHints(); // Initialize scroll listener for detecting visible elements this.initScrollListener(); // Create container for hints if it doesn't exist if (!document.getElementById('contextual-hints-container')) { this.hintContainer = document.createElement('div'); this.hintContainer.id = 'contextual-hints-container'; document.body.appendChild(this.hintContainer); } else { this.hintContainer = document.getElementById('contextual-hints-container'); } // Listen for ESC key to dismiss hints document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && this.activeHint) { this.dismissActiveHint(); } }); // Listen for clicks outside hint to dismiss document.addEventListener('click', (e) => { if (this.activeHint && !this.activeHint.contains(e.target)) { // Check if the click was not on the target element either const activeHintId = this.activeHint.getAttribute('data-hint-id'); const targetElement = document.querySelector(`[data-hint="${activeHintId}"]`); if (!targetElement || !targetElement.contains(e.target)) { this.dismissActiveHint(); } } }); } /** * Register a hint with the system * @param {string} id - Unique identifier for the hint * @param {object} options - Hint options */ registerHint(id, options) { this.hints[id] = { title: options.title || 'Hint', content: options.content || '', position: options.position || 'bottom', important: options.important || false, maxShows: options.maxShows || 3, icon: options.icon || 'fas fa-lightbulb', selector: options.selector || null, particles: options.particles || false, trigger: options.trigger || 'auto', // auto, manual, hover buttonText: options.buttonText || 'Got it', onShown: options.onShown || null, onDismiss: options.onDismiss || null }; // Attach triggers for this hint if necessary if (options.selector) { this.attachHintTrigger(id); } } /** * Register all predefined hints for the application */ registerPredefinedHints() { // Quantum Dimensions hint this.registerHint('quantum-dimensions', { title: 'Quantum Dimensions', content: 'Increase dimensions for deeper, multi-layered analysis of your text. Higher dimensions explore more interconnected thought paths.', position: 'top', selector: '#depth', icon: 'fas fa-layer-group', trigger: 'hover' }); // OpenAI integration hint this.registerHint('openai-integration', { title: 'AI Enhancement', content: 'Enable this to use OpenAI for generating human-like responses based on quantum analysis results. Requires API key in settings.', position: 'right', selector: '#use_ai', icon: 'fas fa-robot', important: !document.body.classList.contains('has-openai-key') }); // Analyze button hint this.registerHint('analyze-button', { title: 'Quantum Analysis', content: 'Start the quantum-inspired recursive thinking process to analyze your text through multiple dimensions.', position: 'top', selector: '#analyze-btn', particles: true, maxShows: 2 }); // Quantum Score hint this.registerHint('quantum-score', { title: 'Quantum Score', content: 'This score represents the confidence and coherence of the quantum analysis across all dimensions.', position: 'left', selector: '.quantum-score-visualization', icon: 'fas fa-chart-line', trigger: 'manual' }); // Zap Integrations hint this.registerHint('zap-integrations', { title: 'ZAP Integrations', content: 'Connect the Quantum Framework to other services and applications to extend its capabilities.', position: 'bottom', selector: 'a[href="/zap-integrations"]', icon: 'fas fa-bolt', trigger: 'hover' }); // Automation Workflow hint this.registerHint('automation-workflow', { title: 'Automation Workflow', content: 'View and configure automated tasks and workflows using the quantum framework.', position: 'bottom', selector: 'a[href="/automation-workflow"]', icon: 'fas fa-cogs', trigger: 'hover' }); // Named Entities hint this.registerHint('named-entities', { title: 'Named Entities', content: 'These are specific objects identified in your text like people, organizations, locations, and more.', position: 'right', selector: '.quantum-entity-item', icon: 'fas fa-fingerprint', trigger: 'manual' }); } /** * Attach a trigger to show a hint when interacting with an element * @param {string} hintId - The ID of the hint to trigger */ attachHintTrigger(hintId) { const hint = this.hints[hintId]; if (!hint || !hint.selector) return; // Find all matching elements const elements = document.querySelectorAll(hint.selector); if (elements.length === 0) return; elements.forEach(element => { // Add data attribute to mark the element as a hint target element.setAttribute('data-hint', hintId); element.classList.add('hint-target'); // Attach event listeners based on trigger type if (hint.trigger === 'hover') { element.addEventListener('mouseenter', () => { this.considerShowingHint(hintId, element); element.classList.add('hint-highlight'); }); element.addEventListener('mouseleave', () => { element.classList.remove('hint-highlight'); }); } else if (hint.trigger === 'auto') { // For auto triggers, we'll check visibility in the scroll listener // and show the hint when appropriate } // For manual triggers, the hint will be shown programmatically }); } /** * Consider whether to show a hint based on whether it's been shown before * @param {string} hintId - The ID of the hint to consider showing * @param {Element} target - The target element for the hint */ considerShowingHint(hintId, target) { // Don't show if another hint is active if (this.activeHint) return; const hint = this.hints[hintId]; if (!hint) return; // Count how many times this hint has been shown const timesShown = this.shownHints.filter(id => id === hintId).length; // If it's been shown fewer times than the max, show it if (timesShown < hint.maxShows) { this.showHint(hintId, target); } } /** * Show a hint for a specific element * @param {string} hintId - The ID of the hint to show * @param {Element} targetElement - The element to attach the hint to */ showHint(hintId, targetElement) { const hint = this.hints[hintId]; if (!hint) return; // Dismiss any active hint this.dismissActiveHint(); // Create the hint element const hintElement = document.createElement('div'); hintElement.className = `contextual-hint position-${hint.position}`; hintElement.setAttribute('data-hint-id', hintId); if (hint.important) { hintElement.classList.add('important'); } if (hint.particles) { hintElement.classList.add('has-particles'); } // Add LED tracer effect const ledTracer = document.createElement('div'); ledTracer.className = 'led-tracer'; hintElement.appendChild(ledTracer); // Add content hintElement.innerHTML += `