Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!-- Ionicons -->
- <script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>
- <script nomodule src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"></script>
- <!-- GSAP -->
- <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
- <script>
- // Products data
- const products = [
- {
- name: "Obsidian Puffer",
- img: "https://images.unsplash.com/photo-1591047139829-d91aecb6caea?w=400&h=400&fit=crop",
- price: "$240 USD",
- tag: "Outerwear",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Slate Joggers",
- img: "https://images.unsplash.com/photo-1594633312681-425c7b97ccd1?w=400&h=400&fit=crop",
- price: "$160 USD",
- tag: "Essentials",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Noir Shirt",
- img: "https://images.unsplash.com/photo-1621072156002-e2fccdc0b176?w=400&h=400&fit=crop",
- price: "$190 USD",
- tag: "Classic",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Ash Knit",
- img: "https://images.unsplash.com/photo-1576566588028-4147f3842f27?w=400&h=400&fit=crop",
- price: "$220 USD",
- tag: "Core Piece",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Form Jacket",
- img: "https://images.unsplash.com/photo-1591085686350-798c0f9faa7f?w=400&h=400&fit=crop",
- price: "$280 USD",
- tag: "Minimal",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Carbon Trousers",
- img: "https://images.unsplash.com/photo-1594633313593-bab3825d0caf?w=400&h=400&fit=crop",
- price: "$210 USD",
- tag: "Tailored",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Edge Vest",
- img: "https://images.unsplash.com/photo-1434389677669-e08b4cac3105?w=400&h=400&fit=crop",
- price: "$150 USD",
- tag: "Layer",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Grain Tee",
- img: "https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?w=400&h=400&fit=crop",
- price: "$130 USD",
- tag: "Everyday",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Stone Cap",
- img: "https://images.unsplash.com/photo-1588850561407-ed78c282e89b?w=400&h=400&fit=crop",
- price: "$95 USD",
- tag: "Accessory",
- url: "https://ovdivi.com/blog/",
- },
- {
- name: "Void Coat",
- img: "https://images.unsplash.com/photo-1539533018447-63fcce2678e3?w=400&h=400&fit=crop",
- price: "$310 USD",
- tag: "Statement",
- url: "https://ovdivi.com/blog/",
- },
- ];
- // Main slider logic
- const ovPsGallery = document.querySelector(".ov-ps-ovPsGallery");
- const ovPsProductsContainer = document.querySelector(".ov-ps-products");
- const ovPsProductName = document.querySelector(".ov-ps-product-name");
- const ovPsProductNameText = document.querySelector(".ov-ps-product-name p");
- const ovPsProductPreview = document.querySelector(".ov-ps-product-preview");
- const ovPsPreviewOverlay = document.querySelector(".ov-ps-preview-overlay");
- const ovPsPreviewName = document.querySelector(".ov-ps-product-preview-name p");
- const ovPsPreviewImg = document.querySelector(".ov-ps-product-preview-img img");
- const ovPsPreviewTag = document.querySelector(".ov-ps-product-preview-tag p");
- const ovPsPreviewUrl = document.querySelector(".ov-ps-product-url .ov-ps-btn a");
- const ovPsProductBanner = document.querySelector(".ov-ps-product-banner");
- const ovPsBannerImg = document.querySelector(".ov-ps-product-banner img");
- const ovPsViewBtn = document.querySelector(".ov-ps-view-btn");
- const ovPsViewBtnIcon = ovPsViewBtn.querySelector("ion-icon");
- const ovPsPrevBtn = document.querySelector(".ov-ps-nav-btn.ov-ps-prev");
- const ovPsNextBtn = document.querySelector(".ov-ps-nav-btn.ov-ps-next");
- const ovPsDragIndicator = document.querySelector(".ov-ps-drag-indicator");
- let currentProductIndex = 0;
- let slideItems = [];
- let isPreviewAnimating = false;
- let isPreviewOpen = false;
- let isDragging = false;
- let dragStartX = 0;
- let dragThreshold = 50;
- const BUFFER_SIZE = 5;
- const spacing = 0.375;
- const slideWidth = spacing * 1000;
- function addSlideItem(relativeIndex) {
- const productIndex =
- (((currentProductIndex + relativeIndex) % products.length) +
- products.length) %
- products.length;
- const product = products[productIndex];
- const li = document.createElement("li");
- li.innerHTML = `<img src="${product.img}" alt="${product.name}" />`;
- li.dataset.relativeIndex = relativeIndex;
- li.addEventListener("click", function(e) {
- if (!isDragging && relativeIndex === 0) {
- togglePreview();
- }
- });
- gsap.set(li, {
- x: relativeIndex * slideWidth,
- scale: relativeIndex === 0 ? 1.25 : 0.75,
- zIndex: relativeIndex === 0 ? 100 : 1,
- opacity: isPreviewOpen ? 0 : 1,
- });
- ovPsProductsContainer.appendChild(li);
- slideItems.push({ element: li, relativeIndex: relativeIndex });
- }
- function removeSlideItem(relativeIndex) {
- const itemIndex = slideItems.findIndex(
- (item) => item.relativeIndex === relativeIndex
- );
- if (itemIndex !== -1) {
- const item = slideItems[itemIndex];
- item.element.remove();
- slideItems.splice(itemIndex, 1);
- }
- }
- function updateSliderPosition() {
- slideItems.forEach((item) => {
- const isActive = item.relativeIndex === 0;
- gsap.to(item.element, {
- x: item.relativeIndex * slideWidth,
- scale: isActive ? 1.25 : 0.75,
- zIndex: isActive ? 100 : 1,
- duration: 0.75,
- ease: "power3.out",
- });
- });
- }
- function updateProductName() {
- const actualIndex =
- ((currentProductIndex % products.length) + products.length) %
- products.length;
- ovPsProductNameText.textContent = products[actualIndex].name;
- }
- function updatePreviewContent(animate = true) {
- const actualIndex =
- ((currentProductIndex % products.length) + products.length) %
- products.length;
- const currentProduct = products[actualIndex];
- if (!animate) {
- // Solo actualizar contenido sin animar (para inicialización)
- ovPsPreviewName.textContent = currentProduct.name;
- ovPsPreviewImg.src = currentProduct.img;
- ovPsPreviewImg.alt = currentProduct.name;
- ovPsPreviewTag.textContent = currentProduct.tag;
- ovPsPreviewUrl.href = currentProduct.url;
- ovPsPreviewUrl.target = "_blank";
- ovPsPreviewUrl.rel = "noopener noreferrer";
- ovPsPreviewUrl.textContent = `Ver Detalles - ${currentProduct.price}`;
- ovPsBannerImg.src = currentProduct.img;
- ovPsBannerImg.alt = currentProduct.name;
- return;
- }
- // Animar el preview hacia abajo primero
- gsap.to(ovPsProductPreview, {
- y: "0%",
- opacity: 0,
- duration: 0.3,
- ease: "power2.in",
- onComplete: () => {
- // Update content
- ovPsPreviewName.textContent = currentProduct.name;
- ovPsPreviewImg.src = currentProduct.img;
- ovPsPreviewImg.alt = currentProduct.name;
- ovPsPreviewTag.textContent = currentProduct.tag;
- ovPsPreviewUrl.href = currentProduct.url;
- ovPsPreviewUrl.target = "_blank";
- ovPsPreviewUrl.rel = "noopener noreferrer";
- ovPsPreviewUrl.textContent = `Ver Detalles - ${currentProduct.price}`;
- ovPsBannerImg.src = currentProduct.img;
- ovPsBannerImg.alt = currentProduct.name;
- // Animar el preview desde abajo hacia arriba
- gsap.fromTo(ovPsProductPreview,
- {
- y: "20%",
- opacity: 0
- },
- {
- y: "-50%",
- opacity: 1,
- duration: 0.5,
- ease: "power2.out"
- }
- );
- // Fade banner image
- gsap.to(ovPsBannerImg, {
- opacity: 1,
- duration: 0.3
- });
- }
- });
- }
- function moveNext() {
- if (isPreviewAnimating) return;
- currentProductIndex++;
- removeSlideItem(-BUFFER_SIZE);
- slideItems.forEach((item) => {
- item.relativeIndex--;
- item.element.dataset.relativeIndex = item.relativeIndex;
- item.element.onclick = function() {
- if (!isDragging && item.relativeIndex === 0) {
- togglePreview();
- }
- };
- });
- addSlideItem(BUFFER_SIZE);
- updateSliderPosition();
- updateProductName();
- if (isPreviewOpen) {
- updatePreviewContent();
- }
- }
- function movePrev() {
- if (isPreviewAnimating) return;
- currentProductIndex--;
- removeSlideItem(BUFFER_SIZE);
- slideItems.forEach((item) => {
- item.relativeIndex++;
- item.element.dataset.relativeIndex = item.relativeIndex;
- item.element.onclick = function() {
- if (!isDragging && item.relativeIndex === 0) {
- togglePreview();
- }
- };
- });
- addSlideItem(-BUFFER_SIZE);
- updateSliderPosition();
- updateProductName();
- if (isPreviewOpen) {
- updatePreviewContent();
- }
- }
- function updateButtonStates() {
- if (isPreviewAnimating) {
- ovPsPrevBtn.classList.add("ov-ps-disabled");
- ovPsNextBtn.classList.add("ov-ps-disabled");
- } else {
- ovPsPrevBtn.classList.remove("ov-ps-disabled");
- ovPsNextBtn.classList.remove("ov-ps-disabled");
- }
- }
- function getActiveSlide() {
- return slideItems.find((item) => item.relativeIndex === 0);
- }
- function animateSideItems(hide = false) {
- const activeSlide = getActiveSlide();
- // Ocultar/mostrar TODOS los slides
- slideItems.forEach((item) => {
- gsap.to(item.element, {
- x: hide
- ? item.relativeIndex * slideWidth * 1.5
- : item.relativeIndex * slideWidth,
- opacity: hide ? 0 : 1,
- duration: 0.75,
- ease: "power3.inOut",
- });
- });
- // Ajustar el slide activo
- if (activeSlide) {
- gsap.to(activeSlide.element, {
- scale: hide ? 0.75 : 1.25,
- duration: 0.75,
- ease: "power3.inOut",
- });
- }
- }
- function togglePreview() {
- if (isPreviewAnimating) return;
- isPreviewAnimating = true;
- updateButtonStates();
- if (!isPreviewOpen) {
- updatePreviewContent();
- ovPsViewBtn.classList.add("ov-ps-active");
- ovPsViewBtnIcon.name = "close-outline";
- ovPsPreviewOverlay.classList.add("active");
- // Cambiar z-index a 0 cuando se abre
- ovPsProductBanner.style.zIndex = "0";
- // Ocultar título con opacidad 0
- ovPsProductName.style.opacity = "0";
- } else {
- ovPsViewBtn.classList.remove("ov-ps-active");
- ovPsViewBtnIcon.name = "eye-outline";
- ovPsPreviewOverlay.classList.remove("active");
- // Restaurar z-index a -1 cuando se cierra
- ovPsProductBanner.style.zIndex = "-1";
- // Mostrar título con opacidad 1
- ovPsProductName.style.opacity = "1";
- }
- gsap.to(ovPsProductPreview, {
- y: isPreviewOpen ? "100%" : "-50%",
- duration: 0.75,
- ease: "power3.inOut",
- });
- gsap.to(ovPsProductBanner, {
- opacity: isPreviewOpen ? 0 : 1,
- duration: 0.4,
- delay: isPreviewOpen ? 0 : 0.25,
- ease: "power3.inOut",
- });
- animateSideItems(!isPreviewOpen);
- setTimeout(() => {
- isPreviewAnimating = false;
- isPreviewOpen = !isPreviewOpen;
- updateButtonStates();
- }, 600);
- }
- function closePreview() {
- if (isPreviewOpen && !isPreviewAnimating) {
- togglePreview();
- }
- }
- // Drag functionality
- function handleDragStart(e) {
- if (isPreviewAnimating) return;
- isDragging = false;
- dragStartX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX;
- ovPsGallery.classList.add('dragging');
- }
- function handleDragMove(e) {
- if (isPreviewAnimating) return;
- if (!dragStartX) return;
- const currentX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX;
- const diff = currentX - dragStartX;
- if (Math.abs(diff) > 5) {
- isDragging = true;
- e.preventDefault();
- }
- slideItems.forEach((item) => {
- gsap.to(item.element, {
- x: item.relativeIndex * slideWidth + diff * 0.5,
- duration: 0.1,
- });
- });
- }
- function handleDragEnd(e) {
- if (isPreviewAnimating) return;
- if (!dragStartX) return;
- const currentX = e.type.includes('mouse') ? e.clientX : e.changedTouches[0].clientX;
- const diff = currentX - dragStartX;
- ovPsGallery.classList.remove('dragging');
- if (Math.abs(diff) > dragThreshold) {
- if (diff > 0) {
- movePrev();
- } else {
- moveNext();
- }
- } else {
- updateSliderPosition();
- }
- dragStartX = 0;
- setTimeout(() => {
- isDragging = false;
- }, 100);
- }
- // Mouse events
- ovPsGallery.addEventListener('mousedown', handleDragStart);
- ovPsGallery.addEventListener('mousemove', handleDragMove);
- ovPsGallery.addEventListener('mouseup', handleDragEnd);
- ovPsGallery.addEventListener('mouseleave', handleDragEnd);
- // Touch events
- ovPsGallery.addEventListener('touchstart', handleDragStart, { passive: false });
- ovPsGallery.addEventListener('touchmove', handleDragMove, { passive: false });
- ovPsGallery.addEventListener('touchend', handleDragEnd);
- // ESC key to close preview
- document.addEventListener('keydown', (e) => {
- if (e.key === 'Escape') {
- closePreview();
- }
- });
- // Click outside preview to close
- ovPsPreviewOverlay.addEventListener('click', closePreview);
- // Hide drag indicator after first interaction
- ovPsGallery.addEventListener('mousedown', () => {
- setTimeout(() => {
- ovPsDragIndicator.style.display = 'none';
- }, 1000);
- }, { once: true });
- ovPsGallery.addEventListener('touchstart', () => {
- setTimeout(() => {
- ovPsDragIndicator.style.display = 'none';
- }, 1000);
- }, { once: true });
- function initializeSlider() {
- for (let i = -BUFFER_SIZE; i <= BUFFER_SIZE; i++) {
- addSlideItem(i);
- }
- updateSliderPosition();
- updateProductName();
- updatePreviewContent(false); // false = no animar en la inicialización
- updateButtonStates();
- }
- ovPsPrevBtn.addEventListener("click", movePrev);
- ovPsNextBtn.addEventListener("click", moveNext);
- ovPsViewBtn.addEventListener("click", togglePreview);
- initializeSlider();
- </script>
Advertisement
Add Comment
Please, Sign In to add comment