diff options
Diffstat (limited to 'static/blog-script.js')
-rw-r--r-- | static/blog-script.js | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/static/blog-script.js b/static/blog-script.js new file mode 100644 index 0000000..73719a8 --- /dev/null +++ b/static/blog-script.js @@ -0,0 +1,344 @@ +// DOM Elements +const searchInput = document.getElementById('searchInput'); +const searchBtn = document.getElementById('searchBtn'); +const blogGrid = document.getElementById('blogGrid'); +const categoryLinks = document.querySelectorAll('.category-link'); +const sortSelect = document.getElementById('sortBy'); +const paginationNumbers = document.querySelectorAll('.pagination-number'); +const prevBtn = document.getElementById('prevBtn'); +const nextBtn = document.getElementById('nextBtn'); + +// Blog posts data (in a real app, this would come from an API) +const blogPosts = Array.from(document.querySelectorAll('.blog-post')); + +// Search functionality +const performSearch = () => { + const searchTerm = searchInput.value.toLowerCase().trim(); + + blogPosts.forEach(post => { + const title = post.querySelector('.post-title').textContent.toLowerCase(); + const excerpt = post.querySelector('.post-excerpt').textContent.toLowerCase(); + const category = post.querySelector('.post-category').textContent.toLowerCase(); + + const matches = title.includes(searchTerm) || + excerpt.includes(searchTerm) || + category.includes(searchTerm); + + post.style.display = matches || searchTerm === '' ? 'block' : 'none'; + }); + + // Update results count + const visiblePosts = blogPosts.filter(post => post.style.display !== 'none'); + updateResultsMessage(visiblePosts.length, searchTerm); +}; + +const updateResultsMessage = (count, searchTerm) => { + let existingMessage = document.querySelector('.search-results-message'); + + if (existingMessage) { + existingMessage.remove(); + } + + if (searchTerm) { + const message = document.createElement('div'); + message.className = 'search-results-message'; + message.style.cssText = ` + padding: 1rem; + background: var(--surface); + border-radius: 0.5rem; + margin-bottom: 2rem; + color: var(--text-secondary); + text-align: center; + `; + message.textContent = `Found ${count} article${count !== 1 ? 's' : ''} for "${searchTerm}"`; + + blogGrid.parentNode.insertBefore(message, blogGrid); + } +}; + +// Search event listeners +searchBtn.addEventListener('click', performSearch); +searchInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + performSearch(); + } +}); + +// Real-time search +searchInput.addEventListener('input', () => { + if (searchInput.value.length > 2 || searchInput.value.length === 0) { + performSearch(); + } +}); + +// Category filtering +categoryLinks.forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault(); + + // Update active state + categoryLinks.forEach(l => l.classList.remove('active')); + link.classList.add('active'); + + const category = link.dataset.category; + + blogPosts.forEach(post => { + if (category === 'all') { + post.style.display = 'block'; + } else { + const postCategory = post.dataset.category; + post.style.display = postCategory === category ? 'block' : 'none'; + } + }); + + // Clear search when filtering by category + searchInput.value = ''; + const existingMessage = document.querySelector('.search-results-message'); + if (existingMessage) { + existingMessage.remove(); + } + + // Update pagination + updatePagination(); + }); +}); + +// Sorting functionality +sortSelect.addEventListener('change', () => { + const sortBy = sortSelect.value; + const postsArray = Array.from(blogPosts); + + postsArray.sort((a, b) => { + const dateA = new Date(a.querySelector('.post-date').textContent); + const dateB = new Date(b.querySelector('.post-date').textContent); + + switch (sortBy) { + case 'newest': + return dateB - dateA; + case 'oldest': + return dateA - dateB; + case 'popular': + // In a real app, this would sort by view count or engagement + return Math.random() - 0.5; + default: + return 0; + } + }); + + // Re-append sorted posts to the grid + postsArray.forEach(post => { + blogGrid.appendChild(post); + }); +}); + +// Pagination functionality +let currentPage = 1; +const postsPerPage = 6; + +const updatePagination = () => { + const visiblePosts = blogPosts.filter(post => post.style.display !== 'none'); + const totalPages = Math.ceil(visiblePosts.length / postsPerPage); + + // Show/hide posts based on current page + visiblePosts.forEach((post, index) => { + const startIndex = (currentPage - 1) * postsPerPage; + const endIndex = startIndex + postsPerPage; + + if (index >= startIndex && index < endIndex) { + post.style.display = 'block'; + } else { + post.style.display = 'none'; + } + }); + + // Update pagination buttons + prevBtn.disabled = currentPage === 1; + nextBtn.disabled = currentPage === totalPages || totalPages === 0; + + // Update page numbers + paginationNumbers.forEach((btn, index) => { + btn.classList.toggle('active', index + 1 === currentPage); + }); +}; + +// Pagination event listeners +prevBtn.addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + updatePagination(); + scrollToTop(); + } +}); + +nextBtn.addEventListener('click', () => { + const visiblePosts = blogPosts.filter(post => post.style.display !== 'none'); + const totalPages = Math.ceil(visiblePosts.length / postsPerPage); + + if (currentPage < totalPages) { + currentPage++; + updatePagination(); + scrollToTop(); + } +}); + +paginationNumbers.forEach((btn, index) => { + btn.addEventListener('click', () => { + currentPage = index + 1; + updatePagination(); + scrollToTop(); + }); +}); + +const scrollToTop = () => { + blogGrid.scrollIntoView({ behavior: 'smooth', block: 'start' }); +}; + +// Newsletter form handlers +document.querySelectorAll('.newsletter-form, .newsletter-form-large').forEach(form => { + form.addEventListener('submit', (e) => { + e.preventDefault(); + const email = form.querySelector('input[type="email"]').value; + + if (email) { + showToast(`Thanks for subscribing! We'll send updates to ${email}`, 'success'); + form.reset(); + } + }); +}); + +// Toast notification function +const showToast = (message, type = 'success') => { + const toast = document.createElement('div'); + toast.className = 'toast'; + toast.style.cssText = ` + position: fixed; + top: 2rem; + right: 2rem; + background: ${type === 'success' ? 'var(--success)' : 'var(--error)'}; + color: white; + padding: 1rem 1.5rem; + border-radius: 0.5rem; + box-shadow: var(--shadow-lg); + z-index: 1000; + transform: translateX(100%); + transition: transform 0.3s ease; + `; + toast.textContent = message; + + document.body.appendChild(toast); + + // Show toast + setTimeout(() => { + toast.style.transform = 'translateX(0)'; + }, 100); + + // Hide toast + setTimeout(() => { + toast.style.transform = 'translateX(100%)'; + setTimeout(() => { + document.body.removeChild(toast); + }, 300); + }, 4000); +}; + +// Read more link handlers +document.querySelectorAll('.read-more').forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault(); + const postTitle = link.closest('.blog-post').querySelector('.post-title').textContent; + showToast(`Opening article: "${postTitle}"`, 'success'); + + // In a real app, this would navigate to the full article + setTimeout(() => { + window.location.href = `article.html?title=${encodeURIComponent(postTitle)}`; + }, 1000); + }); +}); + +// Navbar background on scroll +window.addEventListener('scroll', () => { + const navbar = document.querySelector('.navbar'); + if (window.scrollY > 50) { + navbar.style.background = 'rgba(255, 255, 255, 0.98)'; + } else { + navbar.style.background = 'rgba(255, 255, 255, 0.95)'; + } +}); + +// Intersection Observer for animations +const observerOptions = { + threshold: 0.1, + rootMargin: '0px 0px -50px 0px' +}; + +const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.style.opacity = '1'; + entry.target.style.transform = 'translateY(0)'; + } + }); +}, observerOptions); + +// Observe blog posts for animation +document.querySelectorAll('.blog-post').forEach(post => { + post.style.opacity = '0'; + post.style.transform = 'translateY(30px)'; + post.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; + observer.observe(post); +}); + +// Initialize page +document.addEventListener('DOMContentLoaded', () => { + updatePagination(); + + // Add loading animation to hero elements + const heroTitle = document.querySelector('.hero-title'); + const heroSubtitle = document.querySelector('.hero-subtitle'); + const heroSearch = document.querySelector('.hero-search'); + + [heroTitle, heroSubtitle, heroSearch].forEach((element, index) => { + if (element) { + element.style.opacity = '0'; + element.style.transform = 'translateY(30px)'; + element.style.transition = 'opacity 0.8s ease, transform 0.8s ease'; + + setTimeout(() => { + element.style.opacity = '1'; + element.style.transform = 'translateY(0)'; + }, 200 + (index * 200)); + } + }); +}); + +// Button click handlers +document.querySelectorAll('.btn').forEach(btn => { + btn.addEventListener('click', (e) => { + const buttonText = btn.textContent.toLowerCase(); + + if (buttonText.includes('trial') || buttonText.includes('start')) { + e.preventDefault(); + showToast('Starting your free trial! Redirecting to registration...', 'success'); + setTimeout(() => { + window.location.href = 'signup.html'; + }, 2000); + } + }); +}); + +// Sidebar sticky behavior enhancement +window.addEventListener('scroll', () => { + const sidebar = document.querySelector('.blog-sidebar'); + const footer = document.querySelector('.footer'); + + if (sidebar && footer) { + const sidebarRect = sidebar.getBoundingClientRect(); + const footerRect = footer.getBoundingClientRect(); + + if (footerRect.top < window.innerHeight && sidebarRect.bottom > footerRect.top) { + sidebar.style.transform = `translateY(${footerRect.top - sidebarRect.bottom - 20}px)`; + } else { + sidebar.style.transform = 'translateY(0)'; + } + } +}); |