292 lines
8.8 KiB
JavaScript
292 lines
8.8 KiB
JavaScript
// Company Stacks Carousel functionality
|
|
class CompanyCarousel {
|
|
constructor() {
|
|
this.carousel = document.getElementById('companyCarousel');
|
|
this.leftBtn = document.querySelector('.carousel-btn-left');
|
|
this.rightBtn = document.querySelector('.carousel-btn-right');
|
|
this.scrollAmount = 280; // Width of one card plus gap
|
|
this.autoScrollInterval = null;
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
if (!this.carousel) return;
|
|
|
|
this.updateButtons();
|
|
this.setupEventListeners();
|
|
this.startAutoScroll();
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Scroll event to update button states
|
|
this.carousel.addEventListener('scroll', () => {
|
|
this.updateButtons();
|
|
});
|
|
|
|
// Stop auto-scroll on hover
|
|
this.carousel.addEventListener('mouseenter', () => {
|
|
this.stopAutoScroll();
|
|
});
|
|
|
|
// Resume auto-scroll when mouse leaves
|
|
this.carousel.addEventListener('mouseleave', () => {
|
|
this.startAutoScroll();
|
|
});
|
|
|
|
// Touch/swipe support for mobile
|
|
let startX = 0;
|
|
let scrollLeft = 0;
|
|
let isDown = false;
|
|
|
|
this.carousel.addEventListener('mousedown', (e) => {
|
|
isDown = true;
|
|
startX = e.pageX - this.carousel.offsetLeft;
|
|
scrollLeft = this.carousel.scrollLeft;
|
|
this.carousel.style.cursor = 'grabbing';
|
|
this.stopAutoScroll();
|
|
});
|
|
|
|
this.carousel.addEventListener('mouseleave', () => {
|
|
isDown = false;
|
|
this.carousel.style.cursor = 'grab';
|
|
});
|
|
|
|
this.carousel.addEventListener('mouseup', () => {
|
|
isDown = false;
|
|
this.carousel.style.cursor = 'grab';
|
|
this.startAutoScroll();
|
|
});
|
|
|
|
this.carousel.addEventListener('mousemove', (e) => {
|
|
if (!isDown) return;
|
|
e.preventDefault();
|
|
const x = e.pageX - this.carousel.offsetLeft;
|
|
const walk = (x - startX) * 2;
|
|
this.carousel.scrollLeft = scrollLeft - walk;
|
|
});
|
|
|
|
// Touch events for mobile
|
|
this.carousel.addEventListener('touchstart', (e) => {
|
|
startX = e.touches[0].pageX - this.carousel.offsetLeft;
|
|
scrollLeft = this.carousel.scrollLeft;
|
|
this.stopAutoScroll();
|
|
});
|
|
|
|
this.carousel.addEventListener('touchmove', (e) => {
|
|
if (!startX) return;
|
|
const x = e.touches[0].pageX - this.carousel.offsetLeft;
|
|
const walk = (x - startX) * 2;
|
|
this.carousel.scrollLeft = scrollLeft - walk;
|
|
});
|
|
|
|
this.carousel.addEventListener('touchend', () => {
|
|
startX = 0;
|
|
this.startAutoScroll();
|
|
});
|
|
}
|
|
|
|
scrollLeft() {
|
|
this.carousel.scrollBy({
|
|
left: -this.scrollAmount,
|
|
behavior: 'smooth'
|
|
});
|
|
this.stopAutoScroll();
|
|
setTimeout(() => this.startAutoScroll(), 3000);
|
|
}
|
|
|
|
scrollRight() {
|
|
this.carousel.scrollBy({
|
|
left: this.scrollAmount,
|
|
behavior: 'smooth'
|
|
});
|
|
this.stopAutoScroll();
|
|
setTimeout(() => this.startAutoScroll(), 3000);
|
|
}
|
|
|
|
updateButtons() {
|
|
const scrollLeft = this.carousel.scrollLeft;
|
|
const maxScroll = this.carousel.scrollWidth - this.carousel.clientWidth;
|
|
|
|
// Update left button
|
|
if (this.leftBtn) {
|
|
this.leftBtn.disabled = scrollLeft <= 0;
|
|
this.leftBtn.style.opacity = scrollLeft <= 0 ? '0.5' : '1';
|
|
}
|
|
|
|
// Update right button
|
|
if (this.rightBtn) {
|
|
this.rightBtn.disabled = scrollLeft >= maxScroll - 1; // -1 for rounding errors
|
|
this.rightBtn.style.opacity = scrollLeft >= maxScroll - 1 ? '0.5' : '1';
|
|
}
|
|
}
|
|
|
|
startAutoScroll() {
|
|
this.stopAutoScroll();
|
|
this.autoScrollInterval = setInterval(() => {
|
|
const maxScroll = this.carousel.scrollWidth - this.carousel.clientWidth;
|
|
const currentScroll = this.carousel.scrollLeft;
|
|
|
|
if (currentScroll >= maxScroll - 1) {
|
|
// Reset to beginning
|
|
this.carousel.scrollTo({
|
|
left: 0,
|
|
behavior: 'smooth'
|
|
});
|
|
} else {
|
|
// Scroll to next item
|
|
this.scrollRight();
|
|
}
|
|
}, 4000); // Auto-scroll every 4 seconds
|
|
}
|
|
|
|
stopAutoScroll() {
|
|
if (this.autoScrollInterval) {
|
|
clearInterval(this.autoScrollInterval);
|
|
this.autoScrollInterval = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global functions for button clicks
|
|
function scrollCarousel(direction) {
|
|
if (window.companyCarousel) {
|
|
if (direction === 'left') {
|
|
window.companyCarousel.scrollLeft();
|
|
} else {
|
|
window.companyCarousel.scrollRight();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Featured Projects Carousel functionality
|
|
class FeaturedCarousel {
|
|
constructor() {
|
|
this.carousel = document.getElementById('featuredCarousel');
|
|
this.leftBtn = document.querySelector('.featured-section .carousel-btn-left');
|
|
this.rightBtn = document.querySelector('.featured-section .carousel-btn-right');
|
|
this.scrollAmount = 304; // Width of one featured card (280px) plus gap (24px)
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
if (!this.carousel) return;
|
|
|
|
this.updateButtons();
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Scroll event to update button states
|
|
this.carousel.addEventListener('scroll', () => {
|
|
this.updateButtons();
|
|
});
|
|
|
|
// Touch/swipe support for mobile
|
|
let startX = 0;
|
|
let scrollLeft = 0;
|
|
let isDown = false;
|
|
|
|
this.carousel.addEventListener('mousedown', (e) => {
|
|
isDown = true;
|
|
startX = e.pageX - this.carousel.offsetLeft;
|
|
scrollLeft = this.carousel.scrollLeft;
|
|
this.carousel.style.cursor = 'grabbing';
|
|
});
|
|
|
|
this.carousel.addEventListener('mouseleave', () => {
|
|
isDown = false;
|
|
this.carousel.style.cursor = 'grab';
|
|
});
|
|
|
|
this.carousel.addEventListener('mouseup', () => {
|
|
isDown = false;
|
|
this.carousel.style.cursor = 'grab';
|
|
});
|
|
|
|
this.carousel.addEventListener('mousemove', (e) => {
|
|
if (!isDown) return;
|
|
e.preventDefault();
|
|
const x = e.pageX - this.carousel.offsetLeft;
|
|
const walk = (x - startX) * 2;
|
|
this.carousel.scrollLeft = scrollLeft - walk;
|
|
});
|
|
|
|
// Touch events for mobile
|
|
this.carousel.addEventListener('touchstart', (e) => {
|
|
startX = e.touches[0].pageX - this.carousel.offsetLeft;
|
|
scrollLeft = this.carousel.scrollLeft;
|
|
});
|
|
|
|
this.carousel.addEventListener('touchmove', (e) => {
|
|
if (!startX) return;
|
|
const x = e.touches[0].pageX - this.carousel.offsetLeft;
|
|
const walk = (x - startX) * 2;
|
|
this.carousel.scrollLeft = scrollLeft - walk;
|
|
});
|
|
|
|
this.carousel.addEventListener('touchend', () => {
|
|
startX = 0;
|
|
});
|
|
}
|
|
|
|
scrollLeft() {
|
|
this.carousel.scrollBy({
|
|
left: -this.scrollAmount,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
|
|
scrollRight() {
|
|
this.carousel.scrollBy({
|
|
left: this.scrollAmount,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
|
|
updateButtons() {
|
|
const scrollLeft = this.carousel.scrollLeft;
|
|
const maxScroll = this.carousel.scrollWidth - this.carousel.clientWidth;
|
|
|
|
// Update left button
|
|
if (this.leftBtn) {
|
|
this.leftBtn.disabled = scrollLeft <= 0;
|
|
this.leftBtn.style.opacity = scrollLeft <= 0 ? '0.5' : '1';
|
|
}
|
|
|
|
// Update right button
|
|
if (this.rightBtn) {
|
|
this.rightBtn.disabled = scrollLeft >= maxScroll - 1;
|
|
this.rightBtn.style.opacity = scrollLeft >= maxScroll - 1 ? '0.5' : '1';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global functions for button clicks
|
|
function scrollFeaturedCarousel(direction) {
|
|
if (window.featuredCarousel) {
|
|
if (direction === 'left') {
|
|
window.featuredCarousel.scrollLeft();
|
|
} else {
|
|
window.featuredCarousel.scrollRight();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize carousel when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.companyCarousel = new CompanyCarousel();
|
|
window.featuredCarousel = new FeaturedCarousel();
|
|
});
|
|
|
|
// Re-initialize if page content changes
|
|
function reinitializeCarousel() {
|
|
if (window.companyCarousel) {
|
|
window.companyCarousel.stopAutoScroll();
|
|
}
|
|
window.companyCarousel = new CompanyCarousel();
|
|
}
|
|
|
|
// Export for module usage
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = { CompanyCarousel, scrollCarousel, reinitializeCarousel };
|
|
} |