// Main JavaScript functionality for the Dify Learning Platform document.addEventListener('DOMContentLoaded', function() { // Initialize tooltips initializeTooltips(); // Initialize animations initializeAnimations(); // Initialize progress tracking initializeProgressTracking(); // Initialize search functionality initializeSearch(); }); /** * Initialize Bootstrap tooltips */ function initializeTooltips() { var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); } /** * Initialize scroll animations */ function initializeAnimations() { // Fade in elements on scroll const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('fade-in'); } }); }, observerOptions); // Observe elements for animation document.querySelectorAll('.tutorial-card, .project-card, .feature-item').forEach(el => { observer.observe(el); }); } /** * Initialize progress tracking */ function initializeProgressTracking() { // Track page views trackPageView(); // Track tutorial interactions document.querySelectorAll('.tutorial-card .btn').forEach(btn => { btn.addEventListener('click', function(e) { const tutorialTitle = this.closest('.tutorial-card').querySelector('.card-title').textContent; trackEvent('tutorial_started', { tutorial: tutorialTitle }); }); }); // Track project interactions document.querySelectorAll('.project-card .btn').forEach(btn => { btn.addEventListener('click', function(e) { const projectTitle = this.closest('.project-card').querySelector('.card-title').textContent; trackEvent('project_started', { project: projectTitle }); }); }); } /** * Initialize search functionality */ function initializeSearch() { const searchInput = document.getElementById('search-input'); if (searchInput) { searchInput.addEventListener('input', debounce(handleSearch, 300)); } } /** * Handle search functionality */ function handleSearch(event) { const query = event.target.value.toLowerCase().trim(); const tutorials = document.querySelectorAll('.tutorial-card'); const projects = document.querySelectorAll('.project-card'); // Filter tutorials tutorials.forEach(card => { const title = card.querySelector('.card-title').textContent.toLowerCase(); const description = card.querySelector('.card-text').textContent.toLowerCase(); const isVisible = title.includes(query) || description.includes(query) || query === ''; card.closest('.path-item, .col-md-6, .col-lg-4')?.style.setProperty('display', isVisible ? '' : 'none'); }); // Filter projects projects.forEach(card => { const title = card.querySelector('.card-title').textContent.toLowerCase(); const description = card.querySelector('.card-text').textContent.toLowerCase(); const isVisible = title.includes(query) || description.includes(query) || query === ''; card.closest('.col-md-6, .col-lg-4')?.style.setProperty('display', isVisible ? '' : 'none'); }); // Show/hide sections based on results updateSearchResults(query); } /** * Update search results display */ function updateSearchResults(query) { const tutorialSection = document.querySelector('.learning-path'); const projectSection = document.querySelector('#projects'); if (query) { const visibleTutorials = document.querySelectorAll('.tutorial-card:not([style*="display: none"])'); const visibleProjects = document.querySelectorAll('.project-card:not([style*="display: none"])'); // Show no results message if needed if (visibleTutorials.length === 0 && visibleProjects.length === 0) { showNoResultsMessage(); } else { hideNoResultsMessage(); } } else { hideNoResultsMessage(); } } /** * Show no results message */ function showNoResultsMessage() { let noResultsMsg = document.getElementById('no-results-message'); if (!noResultsMsg) { noResultsMsg = document.createElement('div'); noResultsMsg.id = 'no-results-message'; noResultsMsg.className = 'alert alert-info text-center'; noResultsMsg.innerHTML = ` No tutorials or projects found matching your search. `; document.querySelector('.container').appendChild(noResultsMsg); feather.replace(); } noResultsMsg.style.display = 'block'; } /** * Hide no results message */ function hideNoResultsMessage() { const noResultsMsg = document.getElementById('no-results-message'); if (noResultsMsg) { noResultsMsg.style.display = 'none'; } } /** * Track page views for analytics */ function trackPageView() { const pageData = { page: window.location.pathname, title: document.title, timestamp: new Date().toISOString() }; // Store in localStorage for demo purposes const visits = JSON.parse(localStorage.getItem('dify_visits') || '[]'); visits.push(pageData); localStorage.setItem('dify_visits', JSON.stringify(visits.slice(-100))); // Keep last 100 visits } /** * Track custom events */ function trackEvent(eventName, eventData = {}) { const event = { name: eventName, data: eventData, timestamp: new Date().toISOString(), page: window.location.pathname }; // Store in localStorage for demo purposes const events = JSON.parse(localStorage.getItem('dify_events') || '[]'); events.push(event); localStorage.setItem('dify_events', JSON.stringify(events.slice(-100))); // Keep last 100 events console.log('Event tracked:', event); } /** * Utility function to debounce function calls */ function debounce(func, wait) { let timeout; return function(...args) { const later = () => { clearTimeout(timeout); func.apply(this, args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Smooth scroll to element */ function smoothScrollTo(element, offset = 80) { const targetPosition = element.offsetTop - offset; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } /** * Show loading spinner */ function showLoader(container) { const loader = document.createElement('div'); loader.className = 'text-center py-4'; loader.innerHTML = `
Loading...
`; container.appendChild(loader); return loader; } /** * Hide loading spinner */ function hideLoader(loader) { if (loader && loader.parentNode) { loader.parentNode.removeChild(loader); } } /** * Show toast notification */ function showToast(message, type = 'info') { const toast = document.createElement('div'); toast.className = `toast align-items-center text-white bg-${type} border-0`; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; // Add to toast container or create one let toastContainer = document.getElementById('toast-container'); if (!toastContainer) { toastContainer = document.createElement('div'); toastContainer.id = 'toast-container'; toastContainer.className = 'toast-container position-fixed top-0 end-0 p-3'; toastContainer.style.zIndex = '9999'; document.body.appendChild(toastContainer); } toastContainer.appendChild(toast); // Initialize and show toast const bsToast = new bootstrap.Toast(toast); bsToast.show(); // Remove from DOM after hiding toast.addEventListener('hidden.bs.toast', () => { toast.remove(); }); } /** * Copy text to clipboard */ async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); showToast('Copied to clipboard!', 'success'); } catch (err) { console.error('Failed to copy:', err); showToast('Failed to copy to clipboard', 'danger'); } } /** * Format time duration */ function formatDuration(minutes) { if (minutes < 60) { return `${minutes} min`; } else { const hours = Math.floor(minutes / 60); const remainingMinutes = minutes % 60; return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`; } } /** * Calculate reading time for content */ function calculateReadingTime(text, wordsPerMinute = 200) { const wordCount = text.split(/\s+/).length; const minutes = Math.ceil(wordCount / wordsPerMinute); return Math.max(1, minutes); } /** * Initialize progress bars with animation */ function animateProgressBar(progressBar, targetWidth) { let currentWidth = 0; const increment = targetWidth / 20; const interval = setInterval(() => { currentWidth += increment; if (currentWidth >= targetWidth) { currentWidth = targetWidth; clearInterval(interval); } progressBar.style.width = `${currentWidth}%`; }, 50); } // Export functions for use in other scripts window.DifyLearning = { trackEvent, showToast, copyToClipboard, formatDuration, calculateReadingTime, smoothScrollTo, showLoader, hideLoader, animateProgressBar };