scroll stepbystep showcase section
This commit is contained in:
@@ -643,7 +643,7 @@ section[class*='-section'] {
|
||||
}
|
||||
.scroll-track {
|
||||
width: 5px;
|
||||
height: 93px;
|
||||
height: 86px;
|
||||
background: #dfdfdf;
|
||||
border-radius: 26.6px;
|
||||
position: relative;
|
||||
@@ -672,7 +672,7 @@ body.dragging-scroll {
|
||||
align-items: flex-start;
|
||||
gap: 48px;
|
||||
position: relative;
|
||||
/* top: 69px; */
|
||||
top: 69px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.side-buttons {
|
||||
@@ -1504,7 +1504,7 @@ textarea {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 389px));
|
||||
gap: 16px;
|
||||
|
||||
margin-top: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
.related-card {
|
||||
@@ -1733,6 +1733,7 @@ textarea {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
.text-item {
|
||||
height: 60dvh;
|
||||
|
||||
@@ -611,11 +611,126 @@ function updateScrollScene() {
|
||||
setActiveSlide(current);
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateScrollScene);
|
||||
let currentSlideIndex = 0;
|
||||
let isAnimating = false;
|
||||
|
||||
window.addEventListener('resize', updateScrollScene);
|
||||
function goToSlide(index) {
|
||||
if (index < 0 || index >= totalSlides) return;
|
||||
|
||||
currentSlideIndex = index;
|
||||
isAnimating = true;
|
||||
|
||||
const progress = index / (totalSlides - 1);
|
||||
const exactIndex = index;
|
||||
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
if (isMobile) {
|
||||
textTrack.style.transform = 'translateY(0)';
|
||||
resetTextItemInlineStyles();
|
||||
setActiveSlide(currentSlideIndex);
|
||||
setTimeout(() => {
|
||||
isAnimating = false;
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
textTrack.style.transform = `translateY(-${exactIndex * 60}vh)`;
|
||||
|
||||
textItems.forEach((item) => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
textItems.forEach((item, idx) => {
|
||||
const offset = idx - exactIndex;
|
||||
const absOffset = Math.abs(offset);
|
||||
|
||||
let blur = 0;
|
||||
let opacity = 1;
|
||||
|
||||
if (offset > 0) {
|
||||
blur = absOffset > 0.1 ? Math.min((absOffset - 0.1) * 25, 20) : 0;
|
||||
opacity = Math.max(1 - absOffset * 2.5, 0);
|
||||
}
|
||||
|
||||
item.style.filter = `blur(${blur}px)`;
|
||||
item.style.opacity = opacity;
|
||||
});
|
||||
|
||||
setActiveSlide(currentSlideIndex);
|
||||
|
||||
setTimeout(() => {
|
||||
isAnimating = false;
|
||||
}, 600);
|
||||
}
|
||||
|
||||
let lastScrollTime = 0;
|
||||
const scrollCooldown = 800;
|
||||
|
||||
showcase.addEventListener('wheel', function(e) {
|
||||
const currentTime = new Date().getTime();
|
||||
const isAtEnd = currentSlideIndex === totalSlides - 1;
|
||||
const isAtStart = currentSlideIndex === 0;
|
||||
|
||||
|
||||
if ((e.deltaY > 0 && !isAtEnd) || (e.deltaY < 0 && !isAtStart)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
if (isAnimating || (currentTime - lastScrollTime < scrollCooldown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(e.deltaY) < 10) return;
|
||||
|
||||
if (e.deltaY > 0) {
|
||||
if (!isAtEnd) {
|
||||
lastScrollTime = currentTime;
|
||||
goToSlide(currentSlideIndex + 1);
|
||||
}
|
||||
} else {
|
||||
if (!isAtStart) {
|
||||
lastScrollTime = currentTime;
|
||||
goToSlide(currentSlideIndex - 1);
|
||||
}
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
showcase.addEventListener('touchmove', function(e) {
|
||||
const currentTime = new Date().getTime();
|
||||
const isAtEnd = currentSlideIndex === totalSlides - 1;
|
||||
const isAtStart = currentSlideIndex === 0;
|
||||
|
||||
const currentTouchY = e.touches[0].clientY;
|
||||
const diffY = touchStartY - currentTouchY;
|
||||
|
||||
|
||||
if ((diffY > 0 && !isAtEnd) || (diffY < 0 && !isAtStart)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (isAnimating || (currentTime - lastScrollTime < scrollCooldown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(diffY) > 50) {
|
||||
if (diffY > 0) {
|
||||
if (!isAtEnd) {
|
||||
lastScrollTime = currentTime;
|
||||
goToSlide(currentSlideIndex + 1);
|
||||
}
|
||||
} else {
|
||||
if (!isAtStart) {
|
||||
lastScrollTime = currentTime;
|
||||
goToSlide(currentSlideIndex - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
goToSlide(0);
|
||||
|
||||
updateScrollScene();
|
||||
|
||||
const portfolioNavConfig = {
|
||||
actionType: 'project',
|
||||
@@ -971,25 +1086,27 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
updateUI();
|
||||
});
|
||||
|
||||
|
||||
const relatedCards = [
|
||||
...document.querySelectorAll('[data-related-section="gallery"] .related-card'),
|
||||
];
|
||||
|
||||
let currentPopupIndex = 0;
|
||||
const galleryItems = [
|
||||
{
|
||||
type: 'project',
|
||||
},
|
||||
const hasGalleryThumbnail = document.querySelector('.gallery-thumbnail') !== null;
|
||||
|
||||
...[...document.querySelectorAll('[data-related-section="gallery"] .related-card')].map(
|
||||
(card) => ({
|
||||
let currentPopupIndex = 0;
|
||||
const galleryItems = [];
|
||||
|
||||
if (hasGalleryThumbnail) {
|
||||
galleryItems.push({
|
||||
type: 'project',
|
||||
});
|
||||
}
|
||||
|
||||
relatedCards.forEach((card) => {
|
||||
galleryItems.push({
|
||||
type: 'card',
|
||||
element: card,
|
||||
})
|
||||
),
|
||||
];
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function openPopupByIndex(index) {
|
||||
const item = galleryItems[index];
|
||||
@@ -998,7 +1115,6 @@ function openPopupByIndex(index) {
|
||||
|
||||
currentPopupIndex = index;
|
||||
|
||||
// اول هر دو پاپآپ بسته شوند
|
||||
overlay.classList.remove('active');
|
||||
imagePopup.classList.remove('active');
|
||||
|
||||
@@ -1024,13 +1140,11 @@ function openPopupByIndex(index) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
@@ -1040,15 +1154,18 @@ document.querySelector('.gallery-thumbnail .wrapper')?.addEventListener('click',
|
||||
openPopupByIndex(0);
|
||||
});
|
||||
|
||||
relatedCards.forEach((card, index) => {
|
||||
relatedCards.forEach((card) => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.play-btn')) return;
|
||||
|
||||
openPopupByIndex(index + 1);
|
||||
const targetIndex = galleryItems.findIndex(item => item.element === card);
|
||||
|
||||
if (targetIndex !== -1) {
|
||||
openPopupByIndex(targetIndex);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.querySelectorAll('.next-popup').forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
if (currentPopupIndex < galleryItems.length - 1) {
|
||||
@@ -1064,6 +1181,8 @@ document.querySelectorAll('.prev-popup').forEach((btn) => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (!imagePopup.classList.contains('active')) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user