document.addEventListener('DOMContentLoaded', () => { const buttons = document.querySelectorAll('.toggle-btn'); const wrapper = document.querySelector('.table-wrapper'); const columns = document.querySelectorAll('.column'); let isClickScrolling = false; let isInitialLoad = true; setTimeout(() => { isInitialLoad = false; }, 100); buttons.forEach((btn) => { btn.addEventListener('click', (e) => { e.preventDefault(); const currentTarget = btn.dataset.target; const targetId = currentTarget === 'challenges' ? 'solutions' : 'challenges'; const targetColumn = document.getElementById(targetId); if (targetColumn) { isClickScrolling = true; targetColumn.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest', }); buttons.forEach((b) => { const active = b.dataset.target === targetId; b.classList.toggle('is-active', active); b.setAttribute('aria-selected', active); }); setTimeout(() => { isClickScrolling = false; }, 800); } }); }); const observer = new IntersectionObserver( (entries) => { if (isClickScrolling || isInitialLoad) return; entries.forEach((entry) => { if (entry.isIntersecting) { const id = entry.target.id; buttons.forEach((btn) => { const isActive = btn.dataset.target === id; btn.classList.toggle('is-active', isActive); btn.setAttribute('aria-selected', isActive); }); } }); }, { root: wrapper, threshold: 0.6, } ); columns.forEach((col) => observer.observe(col)); }); function equalHeights() { const leftItems = document.querySelectorAll('.itemc'); const rightItems = document.querySelectorAll('.itemr'); leftItems.forEach((leftItem, index) => { const rightItem = rightItems[index]; if (!rightItem) return; leftItem.style.height = 'auto'; rightItem.style.height = 'auto'; const maxHeight = Math.max(leftItem.offsetHeight, rightItem.offsetHeight); leftItem.style.height = `${maxHeight}px`; rightItem.style.height = `${maxHeight}px`; }); } window.addEventListener('load', equalHeights); window.addEventListener('resize', equalHeights); const stepsData = [ { number: '01', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '02', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '03', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '04', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '05', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '06', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '07', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '08', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, { number: '09', title: 'ایده‌یابی و پیدا کردن مشکلات صفحه', intro: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', content: [ 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', ], }, ]; const container = document.getElementById('stepsProcess'); const isMobile = window.innerWidth <= 768; const visibleSteps = isMobile ? stepsData.filter((step) => Number(step.number) <= 7) : stepsData; visibleSteps.forEach((step, i) => { const intro = step.intro || ''; const items = step.content || []; container.insertAdjacentHTML( 'beforeend', `
${step.number}
${intro ? `

${intro}

` : ''}
` ); }); const steps = document.querySelectorAll('.step'); steps.forEach((step) => { const toggleStep = () => { steps.forEach((s) => { if (s !== step) s.classList.remove('active'); }); step.classList.toggle('active'); }; step.querySelector('.step-header').addEventListener('click', toggleStep); step.querySelector('.step-number-bg').addEventListener('click', toggleStep); }); const form = document.getElementById('contactForm'); const submitBtn = document.getElementById('submitBtn'); const backBtn = document.getElementById('backBtn'); const successMessage = document.getElementById('successMessage'); const submitBtnText = submitBtn.querySelector('.btn-text'); form.addEventListener('submit', function (event) { event.preventDefault(); submitBtn.classList.add('loading'); submitBtnText.textContent = 'درحال ارسال فرم'; submitBtn.disabled = true; setTimeout(() => { form.style.display = 'none'; successMessage.classList.add('visible'); }, 1500); }); backBtn.addEventListener('click', function () { successMessage.classList.remove('visible'); form.style.display = 'flex'; submitBtn.disabled = false; submitBtn.classList.remove('loading'); submitBtnText.textContent = 'ثبت درخواست'; form.reset(); }); const customSelect = document.getElementById('customSelect'); const selectBox = customSelect.querySelector('.select-box'); const options = customSelect.querySelectorAll('.option'); const selectedText = customSelect.querySelector('.selected-text'); selectBox.addEventListener('click', () => { customSelect.classList.toggle('active'); }); options.forEach((option) => { option.addEventListener('click', () => { options.forEach((item) => { item.classList.remove('active'); }); option.classList.add('active'); selectedText.textContent = option.textContent; customSelect.classList.remove('active'); }); }); document.addEventListener('click', (e) => { if (!customSelect.contains(e.target)) { customSelect.classList.remove('active'); } }); 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); }); }); const slides = [ { type: 'image', src: 'src/assets/images/5.png', number: '01', title: 'لورم ایپسوم متن ساختگی', description: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', gradientClass: 'gradient-one', mobilePositionClass: 'mobile-pos-one', }, { type: 'image', src: 'src/assets/images/4.png', number: '02', title: 'لورم اپسیلون متن ساختگی', description: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', gradientClass: 'gradient-two', mobilePositionClass: 'mobile-pos-two', }, { type: 'image', src: 'src/assets/images/6.png', number: '03', title: 'لورم اپسیلون متن ساختگی', description: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ', gradientClass: 'gradient-three', mobilePositionClass: 'mobile-pos-three', }, ]; const showcase = document.getElementById('showcase'); const mediaWrapper = document.getElementById('showcasemediaWrapper'); const textTrack = document.getElementById('textTrack'); function renderMedia() { slides.forEach((slide, index) => { const item = document.createElement('div'); item.className = ` media-item ${slide.gradientClass || ''} ${slide.mobilePositionClass || ''} `; if (index === 0) { item.classList.add('active'); } if (slide.type === 'image' || slide.type === 'gif') { const img = document.createElement('img'); img.src = slide.src; item.appendChild(img); } if (slide.type === 'video') { const video = document.createElement('video'); video.src = slide.src; video.autoplay = true; video.loop = true; video.muted = true; video.playsInline = true; item.appendChild(video); } mediaWrapper.appendChild(item); }); } function renderTexts() { slides.forEach((slide) => { const item = document.createElement('div'); item.className = 'text-item'; item.innerHTML = ` ${slide.number}

${slide.title}

${slide.description}

`; textTrack.appendChild(item); }); } renderMedia(); renderTexts(); const mediaItems = document.querySelectorAll('.media-item'); const textItems = document.querySelectorAll('.text-item'); const totalSlides = slides.length; const showcaseScrollContainer = showcase.querySelector('.container-showcase'); document.documentElement.style.setProperty('--slides-count', slides.length); function setActiveSlide(current) { mediaItems.forEach((item, index) => { item.classList.toggle('active', index === current); }); textItems.forEach((item, index) => { item.classList.toggle('active', index === current); }); } function resetTextItemInlineStyles() { textItems.forEach((item) => { item.style.opacity = ''; item.style.filter = ''; }); } function updateScrollScene() { const isMobile = window.innerWidth <= 768; const rect = showcase.getBoundingClientRect(); const sectionTop = window.scrollY + rect.top; const scrollInside = window.scrollY - sectionTop; const scrollHeight = showcaseScrollContainer?.offsetHeight ?? showcase.offsetHeight; const maxScroll = Math.max(scrollHeight - window.innerHeight, 1); const progress = Math.min(Math.max(scrollInside / maxScroll, 0), 1); const exactIndex = progress * (totalSlides - 1); const current = Math.round(exactIndex); if (isMobile) { textTrack.style.transform = 'translateY(0)'; resetTextItemInlineStyles(); setActiveSlide(current); return; } textTrack.style.transform = `translateY(-${exactIndex * 60}vh)`; textItems.forEach((item) => { item.classList.remove('active'); }); textItems.forEach((item, index) => { const offset = index - exactIndex; let blur = 0; let opacity = 1; if (offset > 0) { const enterProgress = Math.min(offset, 1); blur = Math.max((enterProgress - 0.35) * 14, 0); opacity = Math.min(1.2 - enterProgress, 1); } item.style.filter = `blur(${blur}px)`; item.style.opacity = opacity; }); setActiveSlide(current); } window.addEventListener('scroll', updateScrollScene); window.addEventListener('resize', updateScrollScene); updateScrollScene(); const portfolioNavConfig = { actionType: 'project', projectPreviewImage: './src/assets/images/gallery-thumbnail.webp', websiteUrl: 'https://example.com', }; const overlay = document.getElementById('portfolioOverlay'); const imagePopup = document.getElementById('portfolioOverlayimg'); const navLinksContainer = document.getElementById('portfolioNavLinks'); const navAction = document.getElementById('portfolioNavAction'); const navSections = [...document.querySelectorAll('section[data-nav-title]')].filter( (section) => section.dataset.nav !== 'false' && section.offsetParent !== null ); navSections.forEach((section) => { const id = section.id || section.className.split(' ')[0]; section.id = id; const btn = document.createElement('button'); btn.className = 'portfolio-nav-btn'; btn.textContent = section.dataset.navTitle; btn.dataset.target = id; btn.addEventListener('click', () => { document.getElementById(id).scrollIntoView({ behavior: 'smooth', block: 'start', }); }); navLinksContainer.appendChild(btn); }); const navButtons = document.querySelectorAll('.portfolio-nav-btn'); const sectionObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const activeId = entry.target.id; navButtons.forEach((btn) => { btn.classList.remove('active'); if (btn.dataset.target === activeId) { btn.classList.add('active'); btn.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest', }); } }); } }); }, { threshold: 0.45 } ); navSections.forEach((section) => sectionObserver.observe(section)); const portfolioNav = document.getElementById('portfolioNav'); document.querySelector('.portfolio-nav-meeting').addEventListener('click', function () { const target = document.querySelector(this.dataset.scrollTarget); if (target) { target.scrollIntoView({ behavior: 'smooth', }); } }); const aboutSection = document.querySelector('.about-section'); const showcaseSection = document.querySelector('.showcase-section'); const mediaSection = document.querySelector('.media-section'); function togglePortfolioNav() { const aboutTop = aboutSection.getBoundingClientRect().top; const showcaseRect = showcaseSection.getBoundingClientRect(); const mediaTop = mediaSection.getBoundingClientRect().top; const afterAbout = aboutTop <= window.innerHeight; const showcaseVisible = showcaseRect.top <= window.innerHeight && showcaseRect.bottom >= 0; const mediaVisible = mediaTop <= window.innerHeight; if (afterAbout) { portfolioNav.classList.add('show'); } else { portfolioNav.classList.remove('show'); } if (showcaseVisible && !mediaVisible) { portfolioNav.classList.remove('show'); } } window.addEventListener('scroll', togglePortfolioNav); window.addEventListener('load', togglePortfolioNav); function openPortfolioPopup() { overlay.classList.add('active'); document.body.style.overflow = 'hidden'; const sideWrapper = document.querySelector('.side-buttons-wrapper'); const portfolioWrapper = document.querySelector('.portfolio-logo-wrapper'); const desktopBtn = document.querySelector('.desktop-btn'); const phoneBtn = document.querySelector('.phone-btn'); const desktopUse = document.getElementById('desktopIcon'); const phoneUse = document.getElementById('phoneIcon'); sideWrapper?.classList.remove('rotated-desktop'); if (window.innerWidth <= 768) { handleMobilePopupView(); phoneBtn?.classList.add('active'); desktopBtn?.classList.remove('active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon-active'); } else { rotateOverlay?.classList.remove('show'); portfolioWrapper?.classList.remove('mobile-view'); sideWrapper?.classList.remove('rotated-desktop'); desktopBtn?.classList.add('active'); phoneBtn?.classList.remove('active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon-active'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon'); } } if (portfolioNavConfig.actionType === 'project') { navAction.innerHTML = ` `; document .querySelector('.portfolio-nav-project-btn') ?.addEventListener('click', openPortfolioPopup); } if (portfolioNavConfig.actionType === 'website') { navAction.innerHTML = ` بازدید از سایت `; } document.querySelectorAll('.close-popup').forEach((btn) => { btn.addEventListener('click', () => { const video = imagePopup.querySelector('.video-popup-player'); if (video) { video.pause(); video.removeAttribute('src'); video.load(); // video.src = ''; } overlay.classList.remove('active'); imagePopup.classList.remove('active'); document.body.style.overflow = ''; }); }); function openImagePopup(src) { // const img = imagePopup?.querySelector('img'); const img = imagePopup.querySelector('.img-popup-img'); const video = imagePopup.querySelector('.video-popup-player'); video.pause(); // video.src = ''; video.style.display = 'none'; img.style.display = 'block'; img.src = src; imagePopup?.classList.add('active'); document.body.style.overflow = 'hidden'; } imagePopup?.addEventListener('click', (e) => { const video = imagePopup.querySelector('.video-popup-player'); if (video) { video.pause(); video.src = ''; } }); function openVideoPopup(src, poster = '') { const img = imagePopup.querySelector('.img-popup-img'); const video = imagePopup.querySelector('.video-popup-player'); img.style.display = 'none'; video.style.display = 'block'; video.pause(); video.removeAttribute('poster'); if (poster) { video.poster = poster; } video.src = src; video.load(); imagePopup.classList.add('active'); document.body.style.overflow = 'hidden'; } document.addEventListener('DOMContentLoaded', () => { const mediaContainer = document.getElementById('media-section-container'); const section = document.querySelector('.media-section'); const mediaData = { type: 'image', src: './public/images/media.jpg', hideOnMobile: false, }; function handleMobileVisibility() { if (window.innerWidth <= 768 && mediaData.hideOnMobile) { section.style.display = 'none'; } else { section.style.display = 'block'; } } handleMobileVisibility(); window.addEventListener('resize', handleMobileVisibility); function renderMedia(data) { let element; if (data.type === 'image') { element = document.createElement('img'); element.src = data.src; element.alt = ''; } else if (data.type === 'gif') { element = document.createElement('img'); element.src = data.src; element.alt = ''; } else if (data.type === 'video') { element = document.createElement('video'); element.src = data.src; element.autoplay = true; element.muted = true; element.loop = true; element.playsInline = true; } element.classList.add('media'); mediaContainer.appendChild(element); } renderMedia(mediaData); }); document.querySelector('.gallery-thumbnail .wrapper')?.addEventListener('click', (e) => { e.preventDefault(); openPopupByIndex(0); }); const navScroll = document.getElementById('portfolioNavScroll'); const scrollThumb = document.querySelector('.portfolio-scroll-thumb'); const scrollTrack = document.querySelector('.portfolio-scroll-track'); function updateFakeScrollbar() { if (!navScroll || !scrollThumb || !scrollTrack) return; const maxScroll = navScroll.scrollWidth - navScroll.clientWidth; const currentScroll = Math.abs(navScroll.scrollLeft); const trackWidth = scrollTrack.clientWidth; const thumbWidth = 28; const maxThumbMove = trackWidth - thumbWidth; const scrollPercent = currentScroll / maxScroll; scrollThumb.style.right = `${scrollPercent * maxThumbMove}px`; } navScroll?.addEventListener('scroll', updateFakeScrollbar); window.addEventListener('load', updateFakeScrollbar); window.addEventListener('resize', updateFakeScrollbar); document.addEventListener('DOMContentLoaded', () => { const phoneBtn = document.querySelector('.phone-btn'); const desktopBtn = document.querySelector('.desktop-btn'); const portfolioWrapper = document.querySelector('.portfolio-logo-wrapper'); const desktopUse = document.getElementById('desktopIcon'); const phoneUse = document.getElementById('phoneIcon'); const sideWrapper = document.querySelector('.side-buttons-wrapper'); let isMobileView = window.innerWidth <= 768; function updateUI() { sideWrapper?.classList.remove('rotated-desktop'); if (isMobileView) { portfolioWrapper?.classList.add('mobile-view'); phoneBtn?.classList.add('active'); desktopBtn?.classList.remove('active'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon-active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon'); } else { portfolioWrapper?.classList.remove('mobile-view'); desktopBtn?.classList.add('active'); phoneBtn?.classList.remove('active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon-active'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon'); } } phoneBtn?.addEventListener('click', () => { isMobileView = true; updateUI(); }); desktopBtn?.addEventListener('click', () => { isMobileView = false; updateUI(); }); updateUI(); }); const relatedCards = [ ...document.querySelectorAll('[data-related-section="gallery"] .related-card'), ]; let currentPopupIndex = 0; const galleryItems = [ { type: 'project', }, ...[...document.querySelectorAll('[data-related-section="gallery"] .related-card')].map( (card) => ({ type: 'card', element: card, }) ), ]; function openPopupByIndex(index) { const item = galleryItems[index]; if (!item) return; currentPopupIndex = index; // اول هر دو پاپ‌آپ بسته شوند overlay.classList.remove('active'); imagePopup.classList.remove('active'); if (item.type === 'project') { openPortfolioPopup(); } else { const media = item.element.querySelector('.media-container'); const mediaType = media.dataset.type; const src = media.dataset.src; const poster = media.dataset.poster; if (mediaType === 'video') { openVideoPopup(src, poster); } else { openImagePopup(src); } } updatePopupButtons(); } function updatePopupButtons() { document.querySelectorAll('.next-popup').forEach((btn) => { btn.disabled = currentPopupIndex === galleryItems.length - 1; btn.classList.toggle('disabled', currentPopupIndex === galleryItems.length - 1); }); document.querySelectorAll('.prev-popup').forEach((btn) => { btn.disabled = currentPopupIndex === 0; btn.classList.toggle('disabled', currentPopupIndex === 0); }); } document.querySelector('.gallery-thumbnail .wrapper')?.addEventListener('click', (e) => { e.preventDefault(); openPopupByIndex(0); }); relatedCards.forEach((card, index) => { card.addEventListener('click', (e) => { if (e.target.closest('.play-btn')) return; openPopupByIndex(index + 1); }); }); document.querySelectorAll('.next-popup').forEach((btn) => { btn.addEventListener('click', () => { if (currentPopupIndex < galleryItems.length - 1) { openPopupByIndex(currentPopupIndex + 1); } }); }); document.querySelectorAll('.prev-popup').forEach((btn) => { btn.addEventListener('click', () => { if (currentPopupIndex > 0) { openPopupByIndex(currentPopupIndex - 1); } }); }); window.addEventListener('keydown', (e) => { if (!imagePopup.classList.contains('active')) return; if (e.key === 'ArrowRight') { if (currentPopupIndex < galleryItems.length - 1) { openPopupByIndex(currentPopupIndex + 1); } } if (e.key === 'ArrowLeft') { if (currentPopupIndex > 0) { openPopupByIndex(currentPopupIndex - 1); } } }); let rotationTimer = null; function handleMobilePopupView() { const rotateOverlay = document.getElementById('rotateOverlay'); const portfolioWrapper = document.querySelector('.portfolio-logo-wrapper'); const sideWrapper = document.querySelector('.side-buttons-wrapper'); if (!rotateOverlay || !portfolioWrapper || !sideWrapper) return; rotateOverlay.classList.add('show'); clearTimeout(rotationTimer); rotationTimer = setTimeout(() => { rotateOverlay.classList.remove('show'); updateOrientationState(); }, 2000); window.removeEventListener('resize', updateOrientationState); window.removeEventListener('orientationchange', updateOrientationState); window.addEventListener('resize', updateOrientationState); window.addEventListener('orientationchange', updateOrientationState); function updateOrientationState() { const isLandscape = window.innerWidth > window.innerHeight; const desktopBtn = document.querySelector('.desktop-btn'); const phoneBtn = document.querySelector('.phone-btn'); const desktopUse = document.getElementById('desktopIcon'); const phoneUse = document.getElementById('phoneIcon'); if (isLandscape) { portfolioWrapper.classList.remove('mobile-view'); sideWrapper.classList.add('rotated-desktop'); sideWrapper.classList.add('is-rotated'); overlay.classList.add('is-rotated2'); desktopBtn?.classList.add('active'); phoneBtn?.classList.remove('active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon-active'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon'); } else { portfolioWrapper.classList.add('mobile-view'); sideWrapper.classList.remove('rotated-desktop'); sideWrapper.classList.remove('is-rotated'); overlay.classList.remove('is-rotated2'); phoneBtn?.classList.add('active'); desktopBtn?.classList.remove('active'); phoneUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#phone-icon-active'); desktopUse?.setAttribute('href', './src/assets/icons/portfolioP.svg#descktop-icon'); } } updateOrientationState(); } window.addEventListener('load', () => { const portfolioImageScroll = document.getElementById('portfolioScroll'); const portfolioCustomThumb = document.getElementById('scrollThumb'); const portfolioCustomTrack = document.querySelector('.scroll-track'); if (!portfolioImageScroll || !portfolioCustomThumb || !portfolioCustomTrack) { console.log('Portfolio scroll elements not found'); return; } let isDraggingPortfolioThumb = false; function updatePortfolioThumb() { if (isDraggingPortfolioThumb) return; const maxScroll = portfolioImageScroll.scrollHeight - portfolioImageScroll.clientHeight; const maxThumbMove = portfolioCustomTrack.clientHeight - portfolioCustomThumb.clientHeight; if (maxScroll <= 0) return; const thumbPosition = (portfolioImageScroll.scrollTop / maxScroll) * maxThumbMove; portfolioCustomThumb.style.top = `${thumbPosition}px`; } portfolioImageScroll.addEventListener('scroll', updatePortfolioThumb); updatePortfolioThumb(); let portfolioDragOffsetY = 0; portfolioCustomThumb.addEventListener('mousedown', (event) => { isDraggingPortfolioThumb = true; document.body.style.userSelect = 'none'; portfolioDragOffsetY = event.clientY - portfolioCustomThumb.getBoundingClientRect().top; }); document.addEventListener('mouseup', () => { isDraggingPortfolioThumb = false; document.body.style.userSelect = ''; }); document.addEventListener('mousemove', (event) => { if (!isDraggingPortfolioThumb) return; const trackRect = portfolioCustomTrack.getBoundingClientRect(); let newThumbTop = event.clientY - trackRect.top - portfolioDragOffsetY; const maxThumbTop = portfolioCustomTrack.clientHeight - portfolioCustomThumb.clientHeight; newThumbTop = Math.max(0, Math.min(newThumbTop, maxThumbTop)); portfolioCustomThumb.style.top = `${newThumbTop}px`; const scrollPercent = newThumbTop / maxThumbTop; const maxImageScroll = portfolioImageScroll.scrollHeight - portfolioImageScroll.clientHeight; portfolioImageScroll.scrollTop = scrollPercent * maxImageScroll; }); }); const nameInput = document.getElementById('name'); const nameError = document.getElementById('nameError'); nameInput.addEventListener('input', function () { const hasNumber = /\d/.test(this.value); if (hasNumber) { this.classList.add('input-error'); nameError.textContent = '* فقط حروف فارسی و انگلیسی مجاز است'; } else { this.classList.remove('input-error'); nameError.textContent = ''; } }); const phoneInput = document.getElementById('phone'); const phoneError = document.getElementById('phoneError'); phoneInput.addEventListener('input', function () { const hasLetter = /[a-zA-Zآ-ی]/.test(this.value); if (hasLetter) { this.classList.add('input-error'); phoneError.textContent = 'فقط عدد مجاز است'; } else { this.classList.remove('input-error'); phoneError.textContent = ''; } this.value = this.value.replace(/\D/g, ''); }); const emailInput = document.getElementById('email'); const emailError = document.getElementById('emailError'); emailInput.addEventListener('input', function () { if (this.value !== '' && !this.value.includes('@')) { this.classList.add('input-error'); emailError.textContent = 'ایمیل باید شامل @ باشد'; } else { this.classList.remove('input-error'); emailError.textContent = ''; } }); const slider = document.getElementById('portfolioNavScroll'); let isDown = false; let startX = 0; let scrollLeft = 0; slider.addEventListener('mousedown', (e) => { isDown = true; slider.style.cursor = 'grabbing'; startX = e.pageX; scrollLeft = slider.scrollLeft; }); window.addEventListener('mouseup', () => { isDown = false; slider.style.cursor = 'grab'; }); slider.addEventListener('mousemove', (e) => { if (!isDown) return; e.preventDefault(); const walk = e.pageX - startX; slider.scrollLeft = scrollLeft - walk; }); slider.addEventListener( 'wheel', (e) => { e.preventDefault(); slider.scrollLeft += e.deltaY; }, { passive: false } );