// Load tutorials data let tutorialsData = {}; let allTutorials = []; let filteredTutorials = []; let currentFilter = null; // Initialize the app async function init() { try { const response = await fetch('tutorials_data.json'); tutorialsData = await response.json(); // Flatten all tutorials for search allTutorials = []; Object.entries(tutorialsData).forEach(([category, data]) => { data.tutorials.forEach(tutorial => { allTutorials.push({ ...tutorial, category, icon: data.icon }); }); }); filteredTutorials = [...allTutorials]; renderCategories(); updateStats(); setupEventListeners(); } catch (error) { console.error('Error loading tutorials:', error); document.getElementById('categories').innerHTML = '
Error loading tutorials data
'; } } // Render all categories function renderCategories() { const container = document.getElementById('categories'); container.innerHTML = ''; const categoriesWithTutorials = Object.entries(tutorialsData).filter(([_, data]) => { // Check if any tutorials match current filter if (!currentFilter) return data.tutorials.length > 0; return data.tutorials.some(t => filteredTutorials.some(ft => ft.category === _ && ft.title === t.title && ft.language === t.language ) ); }); if (categoriesWithTutorials.length === 0) { container.innerHTML = `
🔍
No tutorials found

Try a different search term

`; return; } categoriesWithTutorials.forEach(([category, data], index) => { const categoryDiv = document.createElement('div'); categoryDiv.className = 'category'; categoryDiv.style.animationDelay = `${index * 0.1}s`; // Filter tutorials for this category const categoryTutorials = currentFilter ? data.tutorials.filter(t => filteredTutorials.some(ft => ft.category === category && ft.title === t.title && ft.language === t.language ) ) : data.tutorials; categoryDiv.innerHTML = `
${data.icon}
${category}
${categoryTutorials.length}
${categoryTutorials.map(tutorial => createTutorialCard(tutorial, category, data.icon)).join('')}
`; container.appendChild(categoryDiv); }); } // Create tutorial card HTML function createTutorialCard(tutorial, category, icon) { const videoLabel = tutorial.is_video ? ' 🎥' : ''; return `
${tutorial.language}
${tutorial.title}${videoLabel}
`; } // Show tutorial details in modal function showTutorialDetails(tutorial, category, icon) { const modal = document.getElementById('tutorialModal'); const modalBody = document.getElementById('modalBody'); const videoInfo = tutorial.is_video ? '

📹 Format: Video Tutorial

' : '

📝 Format: Written Tutorial

'; modalBody.innerHTML = `

${icon} ${tutorial.title}

Category: ${category}

Language/Tech: ${tutorial.language}

${videoInfo}

Description: Learn how to build your own ${category.toLowerCase()} using ${tutorial.language}. This tutorial will guide you through the process step by step.

🚀 Ready to start learning?

Open Tutorial

💡 Tip: "What I cannot create, I do not understand" - Building from scratch is the best way to truly understand how technology works!

`; modal.style.display = 'block'; } // Toggle category collapse function toggleCategory(header) { const toggle = header.querySelector('.category-toggle'); const tutorials = header.nextElementSibling; if (tutorials.style.display === 'none') { tutorials.style.display = 'grid'; toggle.classList.remove('collapsed'); } else { tutorials.style.display = 'none'; toggle.classList.add('collapsed'); } } // Search functionality function handleSearch(searchTerm) { searchTerm = searchTerm.toLowerCase().trim(); if (!searchTerm) { filteredTutorials = [...allTutorials]; currentFilter = null; document.getElementById('filterChips').innerHTML = ''; } else { filteredTutorials = allTutorials.filter(tutorial => tutorial.title.toLowerCase().includes(searchTerm) || tutorial.language.toLowerCase().includes(searchTerm) || tutorial.category.toLowerCase().includes(searchTerm) ); currentFilter = searchTerm; // Show filter chip const filterChips = document.getElementById('filterChips'); filterChips.innerHTML = `
🔍 "${searchTerm}"
`; } renderCategories(); updateStats(); } // Clear search function clearSearch() { document.getElementById('searchInput').value = ''; document.querySelector('.clear-btn').classList.remove('show'); handleSearch(''); } // Surprise me - random tutorial function surpriseMe() { const randomTutorial = allTutorials[Math.floor(Math.random() * allTutorials.length)]; // Scroll to category const categoryId = `tutorials-${randomTutorial.category.replace(/\s+/g, '-')}`; const categoryElement = document.getElementById(categoryId); if (categoryElement) { // Expand category if collapsed if (categoryElement.style.display === 'none') { categoryElement.previousElementSibling.click(); } // Scroll to category categoryElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Highlight the tutorial card const cards = categoryElement.querySelectorAll('.tutorial-card'); cards.forEach(card => card.classList.remove('highlight')); setTimeout(() => { const matchingCard = Array.from(cards).find(card => card.textContent.includes(randomTutorial.title) ); if (matchingCard) { matchingCard.classList.add('highlight'); setTimeout(() => matchingCard.classList.remove('highlight'), 3000); } }, 500); } // Show the tutorial details setTimeout(() => { showTutorialDetails(randomTutorial, randomTutorial.category, randomTutorial.icon); }, 1000); } // Show all tutorials function showAll() { clearSearch(); // Expand all categories document.querySelectorAll('.tutorials').forEach(tutorials => { tutorials.style.display = 'grid'; const toggle = tutorials.previousElementSibling.querySelector('.category-toggle'); if (toggle) toggle.classList.remove('collapsed'); }); } // Update statistics function updateStats() { const languages = new Set(allTutorials.map(t => t.language)); const categories = Object.keys(tutorialsData).length; document.getElementById('totalTutorials').textContent = allTutorials.length; document.getElementById('totalCategories').textContent = categories; document.getElementById('totalLanguages').textContent = languages.size; document.getElementById('visibleCount').textContent = filteredTutorials.length; } // Setup event listeners function setupEventListeners() { const searchInput = document.getElementById('searchInput'); const clearBtn = document.querySelector('.clear-btn'); const surpriseBtn = document.getElementById('surpriseBtn'); const showAllBtn = document.getElementById('showAllBtn'); const modal = document.getElementById('tutorialModal'); const closeModal = document.querySelector('.close-modal'); // Search input searchInput.addEventListener('input', (e) => { const value = e.target.value; if (value) { clearBtn.classList.add('show'); } else { clearBtn.classList.remove('show'); } handleSearch(value); }); // Clear button clearBtn.addEventListener('click', clearSearch); // Surprise button surpriseBtn.addEventListener('click', surpriseMe); // Show all button showAllBtn.addEventListener('click', showAll); // Modal close closeModal.addEventListener('click', () => { modal.style.display = 'none'; }); window.addEventListener('click', (e) => { if (e.target === modal) { modal.style.display = 'none'; } }); // Keyboard shortcuts document.addEventListener('keydown', (e) => { // Escape to close modal if (e.key === 'Escape' && modal.style.display === 'block') { modal.style.display = 'none'; } // Ctrl+K to focus search if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); searchInput.focus(); } // Ctrl+R for random if ((e.ctrlKey || e.metaKey) && e.key === 'r') { e.preventDefault(); surpriseMe(); } }); } // Initialize on load window.addEventListener('DOMContentLoaded', init);