// ==============================================هیرو سکشن================================= const counters = document.querySelectorAll('.counter'); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; const counter = entry.target; const target = parseFloat(counter.dataset.target); const prefix = counter.dataset.prefix || ''; const suffix = counter.dataset.suffix || ''; const duration = 2000; let startTime = null; function animate(currentTime) { if (!startTime) startTime = currentTime; const progress = Math.min((currentTime - startTime) / duration, 1); const currentValue = progress * target; let displayValue; if (target % 1 !== 0) { displayValue = currentValue.toFixed(1); } else { displayValue = Math.floor(currentValue); } counter.textContent = prefix + displayValue + suffix; if (progress < 1) { requestAnimationFrame(animate); } else { counter.textContent = prefix + target + suffix; } } requestAnimationFrame(animate); observer.unobserve(counter); }); }, { threshold: 0.5, } ); counters.forEach((counter) => { observer.observe(counter); }); // ==============================================آرشیو سکشن ================================= function initRelatedSection(section) { const cards = section.querySelectorAll('.related-card'); cards.forEach((card) => { const container = card.querySelector('.media-container'); if (!container) return; if (container.dataset.initialized === 'true') return; container.dataset.initialized = 'true'; const progressCircle = card.querySelector('.progress-circle'); const type = container.dataset.type; const src = container.dataset.src; if (!type || !src) return; card.classList.add(type === 'video' ? 'is-video' : 'is-image'); if (type === 'video') { const ext = src.split('.').pop().toLowerCase(); const video = document.createElement('video'); video.muted = true; video.playsInline = true; video.preload = 'metadata'; const source = document.createElement('source'); source.src = src; source.type = `video/${ext}`; video.appendChild(source); container.appendChild(video); if (!progressCircle) return; const radius = progressCircle.r.baseVal.value; const circumference = 2 * Math.PI * radius; progressCircle.style.strokeDasharray = circumference; progressCircle.style.strokeDashoffset = circumference; let stopTimeout; card.addEventListener('mouseenter', async () => { clearTimeout(stopTimeout); try { video.currentTime = 0; await video.play(); progressCircle.style.transition = 'none'; progressCircle.style.strokeDashoffset = circumference; requestAnimationFrame(() => { progressCircle.style.transition = 'stroke-dashoffset 5s linear'; progressCircle.style.strokeDashoffset = 0; }); stopTimeout = setTimeout(() => { video.pause(); video.currentTime = 0; progressCircle.style.transition = 'none'; progressCircle.style.strokeDashoffset = circumference; }, 5000); } catch (err) { console.error(err); } }); card.addEventListener('mouseleave', () => { clearTimeout(stopTimeout); video.pause(); video.currentTime = 0; progressCircle.style.transition = 'none'; progressCircle.style.strokeDashoffset = circumference; }); card.addEventListener('click', () => { if (type === 'video') { openVideoPopup(src); } else { openImagePopup(src); } }); } else if (type === 'image') { const img = document.createElement('img'); img.src = src; img.alt = 'portfolio'; container.appendChild(img); } }); } function initGalleryFilter(section) { const tabs = section.querySelectorAll('.tabs button'); const cards = section.querySelectorAll('.related-card'); tabs.forEach((tab) => { tab.addEventListener('click', () => { tabs.forEach((btn) => { btn.classList.remove('current'); }); tab.classList.add('current'); const text = tab.querySelector('.txt')?.textContent.trim(); cards.forEach((card) => { const media = card.querySelector('.media-container'); if (!media) return; const type = media.dataset.type; if (text === 'همه') { card.style.display = ''; } else if (text === 'ویدیو') { if (type === 'video') { card.style.display = ''; } else { card.style.display = 'none'; } } else if (text === 'تصاویر') { if (type === 'image') { card.style.display = ''; } else { card.style.display = 'none'; } } }); }); }); } document.querySelectorAll('.related-content p').forEach((item) => { item.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); }); }); document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('[data-related-section]').forEach((section) => { initRelatedSection(section); initGalleryFilter(section); }); }); // =========================فیلتر============================ function initFilterSystem(section) { // ---- Selectors ---- const toggleBtn = document.getElementById('filterToggleBtn'); const toggleText = document.getElementById('filterToggleText'); const filterControls = document.getElementById('filterControls'); const categoryBtn = document.getElementById('categoryBtn'); const tagsBtn = document.getElementById('tagsBtn'); const categoryDrop = document.getElementById('categoryDropdown'); const tagsDrop = document.getElementById('tagsDropdown'); const clearBtn = document.getElementById('filterClearBtn'); const tagBadge = document.getElementById('tagBadge'); const mobileOverlay = document.getElementById('filterMobileOverlay'); const mobileBack = document.getElementById('filterMobileBack'); const mobileClose = document.getElementById('filterMobileClose'); const mobileTitle = document.getElementById('filterMobileTitle'); const mobileMain = document.getElementById('filterMobileMain'); const mobileCatSub = document.getElementById('filterMobileCategorySub'); const mobileTagsSub = document.getElementById('filterMobileTagsSub'); const mobileCatBtn = document.getElementById('mobileCategoryBtn'); const mobileTagsBtn2 = document.getElementById('mobileTagsBtn'); const mobileApply = document.getElementById('filterMobileApply'); const mobileClear2 = document.getElementById('filterMobileClear'); const isMobile = () => window.innerWidth <= 768; const categoryBadge = document.getElementById('categoryBadge'); const mobileCategoryBadge = document.getElementById('mobileCategoryBadge'); const mobileTagBadge = document.getElementById('mobileTagBadge'); // ================================================ // DESKTOP: باز / بسته کردن فیلتر بار // ================================================ let filterOpen = false; toggleBtn.addEventListener('click', () => { if (isMobile()) { openMobilePopup(); return; } filterOpen = !filterOpen; filterControls.classList.toggle('is-open', filterOpen); toggleText.textContent = filterOpen ? 'بستن' : 'فیلتر کردن'; if (!filterOpen) { closeAllDropdowns(); } }); // ================================================ // DESKTOP: اکاردئون دسته‌بندی // ================================================ categoryBtn.addEventListener('click', (e) => { e.stopPropagation(); const isOpen = categoryDrop.classList.contains('is-open'); closeAllDropdowns(); if (!isOpen) { categoryDrop.classList.add('is-open'); categoryBtn.classList.add('is-active'); } }); // ================================================ // DESKTOP: اکاردئون تگ‌ها // ================================================ tagsBtn.addEventListener('click', (e) => { e.stopPropagation(); const isOpen = tagsDrop.classList.contains('is-open'); closeAllDropdowns(); if (!isOpen) { tagsDrop.classList.add('is-open'); tagsBtn.classList.add('is-active'); } }); function closeAllDropdowns() { categoryDrop.classList.remove('is-open'); tagsDrop.classList.remove('is-open'); categoryBtn.classList.remove('is-active'); tagsBtn.classList.remove('is-active'); } // بستن دراپ‌داون با کلیک خارج از آن document.addEventListener('click', (e) => { if (!e.target.closest('.filter-group')) { closeAllDropdowns(); } }); // ================================================ // DESKTOP: فیلتر کردن کارت‌ها // ================================================ // اسکرول بعد از برداشتن تیک چک باکس====== function scrollToSectionTop() { section.scrollIntoView({ behavior: 'smooth', block: 'start', }); } // اسکرول بعد از زدن تیک =========== function scrollToSectionTop() { section.scrollIntoView({ behavior: 'smooth', block: 'start', }); } function applyDesktopFilter() { const selCats = [...section.querySelectorAll('.category-checkbox:checked')].map((c) => c.value); const selTags = [...section.querySelectorAll('.tag-checkbox:checked')].map((c) => c.value); filterCards(section, selCats, selTags); } // ================================================ // DESKTOP: شمارنده بج تگ‌ها // ================================================ function updateBadges() { // Desktop const desktopTagCount = section.querySelectorAll('.tag-checkbox:checked').length; const desktopCategoryCount = section.querySelectorAll('.category-checkbox:checked').length; // Mobile const mobileTagCount = section.querySelectorAll('.mob-tag-cb:checked').length; const mobileCategoryCount = section.querySelectorAll('.mob-cat-cb:checked').length; updateBadge(tagBadge, desktopTagCount); updateBadge(categoryBadge, desktopCategoryCount); updateBadge(mobileTagBadge, mobileTagCount); updateBadge(mobileCategoryBadge, mobileCategoryCount); } function updateDesktopClearButton() { const hasAny = section.querySelectorAll('.category-checkbox:checked, .tag-checkbox:checked').length > 0; clearBtn.disabled = !hasAny; } function updateBadge(el, count) { if (!el) return; el.textContent = count; el.style.display = count > 0 ? 'inline-flex' : 'none'; } section.querySelectorAll('.category-checkbox').forEach((cb) => { cb.addEventListener('change', () => { updateBadges(); updateDesktopClearButton(); applyDesktopFilter(); scrollToSectionTop(); }); }); section.querySelectorAll('.tag-checkbox').forEach((cb) => { cb.addEventListener('change', () => { updateBadges(); updateDesktopClearButton(); applyDesktopFilter(); scrollToSectionTop(); }); }); // ================================================ // DESKTOP: حذف فیلتر // ================================================ clearBtn.addEventListener('click', () => { section .querySelectorAll('.category-checkbox, .tag-checkbox') .forEach((cb) => (cb.checked = false)); updateBadges(); updateDesktopClearButton(); scrollToSectionTop(); filterCards(section, [], []); }); // ================================================ // فیلتر کارت‌ها (مشترک بین دسکتاپ و موبایل) // ================================================ function filterCards(sec, cats, tags) { sec.querySelectorAll('.related-card').forEach((card) => { const text = card.querySelector('.related-content p')?.textContent || ''; const passCategory = cats.length === 0 || cats.some((c) => text.includes(c)); const passTag = tags.length === 0 || tags.some((t) => text.includes(t)); card.style.display = passCategory && passTag ? '' : 'none'; }); } // ================================================ // MOBILE: باز کردن پاپ‌آپ // ================================================ function openMobilePopup() { mobileOverlay.classList.add('is-open'); document.body.style.overflow = 'hidden'; showMobileMain(); } function closeMobilePopup() { mobileOverlay.classList.remove('is-open'); document.body.style.overflow = ''; } mobileClose.addEventListener('click', closeMobilePopup); // ================================================ // MOBILE: نمای اصلی / زیرمنوها // ================================================ function showMobileMain() { mobileMain.classList.add('is-visible'); mobileCatSub.classList.remove('is-visible'); mobileTagsSub.classList.remove('is-visible'); mobileTitle.textContent = 'فیلتر کردن'; mobileBack.style.display = 'none'; mobileClose.style.display = 'flex'; mobileApply.textContent = 'اعمال فیلتر'; updateMobileFooter(); } function showMobileCategory() { mobileMain.classList.remove('is-visible'); mobileCatSub.classList.add('is-visible'); mobileTagsSub.classList.remove('is-visible'); mobileTitle.textContent = 'دسته بندی'; mobileBack.style.display = 'flex'; mobileClose.style.display = 'none'; updateMobileFooter(); } function showMobileTags() { mobileMain.classList.remove('is-visible'); mobileCatSub.classList.remove('is-visible'); mobileTagsSub.classList.add('is-visible'); mobileTitle.textContent = 'تگ‌ها'; mobileBack.style.display = 'flex'; mobileClose.style.display = 'none'; updateMobileFooter(); } mobileBack.addEventListener('click', showMobileMain); mobileCatBtn.addEventListener('click', showMobileCategory); mobileTagsBtn2.addEventListener('click', showMobileTags); // ================================================ // MOBILE: فعال/غیرفعال کردن دکمه‌های footer // ================================================ function updateMobileFooter() { const hasAny = section.querySelectorAll('.mob-cat-cb:checked, .mob-tag-cb:checked').length > 0; mobileApply.disabled = false; mobileClear2.disabled = !hasAny; } section.querySelectorAll('.mob-cat-cb, .mob-tag-cb').forEach((cb) => { cb.addEventListener('change', () => { updateMobileFooter(); updateBadges(); }); }); // ================================================ // MOBILE: اعمال و حذف فیلتر // ================================================ mobileApply.addEventListener('click', () => { const selCats = [...section.querySelectorAll('.mob-cat-cb:checked')].map((c) => c.value); const selTags = [...section.querySelectorAll('.mob-tag-cb:checked')].map((c) => c.value); filterCards(section, selCats, selTags); closeMobilePopup(); }); mobileClear2.addEventListener('click', () => { section.querySelectorAll('.mob-cat-cb, .mob-tag-cb').forEach((cb) => (cb.checked = false)); updateMobileFooter(); updateBadges(); filterCards(section, [], []); }); mobileOverlay.addEventListener('click', (e) => { if (e.target === mobileOverlay) closeMobilePopup(); }); updateBadges(); updateDesktopClearButton(); } document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('[data-related-section]').forEach((section) => { initRelatedSection(section); initGalleryFilter(section); initFilterSystem(section); }); });