اسلایدر/دماوندپلیمر - فراغیب
بدون خلاصۀ ویرایش |
بدون خلاصۀ ویرایش |
||
| خط ۱: | خط ۱: | ||
<br> | |||
<html> | <html> | ||
<div | <div | ||
| خط ۱۱۷: | خط ۱۱۸: | ||
<style> | <style> | ||
.fgwiki-gallery, | |||
.fgwiki-gallery *{ | |||
box-sizing: border-box; | box-sizing:border-box; | ||
} | |||
.fgwiki-gallery{ | |||
/* Mobile First */ | |||
--fg-items: | --fg-items:1; | ||
--fg-gap: | --fg-gap:12px; | ||
--fg-radius: 18px; | --fg-radius:18px; | ||
--fg-image-height: | --fg-image-height:260px; | ||
--fg-side-blur: | --fg-side-blur:0; | ||
--fg-side-opacity: | --fg-side-opacity:1; | ||
--fg-accent: #ff2a2a; | --fg-accent:#ff2a2a; | ||
--fg-card-bg: # | --fg-card-bg:#fff; | ||
--fg-image-bg: #f8f9fa; | --fg-image-bg:#f8f9fa; | ||
--fg-caption-bg: # | --fg-caption-bg:#fff; | ||
--fg-caption-color: #243447; | --fg-caption-color:#243447; | ||
position:relative; | |||
width:100%; | |||
position: relative; | max-width:1240px; | ||
width: | margin:28px auto; | ||
margin: 28px auto; | padding:0 36px 42px; | ||
padding: 0 | direction:rtl; | ||
direction: rtl; | font-family:iransans,Arial,sans-serif; | ||
font-family: iransans, Arial, sans-serif; | overflow:hidden; | ||
} | |||
.fgwiki-gallery__viewport{ | |||
width:100%; | |||
width: 100%; | overflow:hidden; | ||
overflow: hidden; | border-radius:var(--fg-radius); | ||
border-radius: var(--fg-radius); | touch-action:pan-y; | ||
touch-action: pan-y; | } | ||
.fgwiki-gallery__track{ | |||
display:flex; | |||
gap:var(--fg-gap); | |||
display: flex | width:100%; | ||
will-change:transform; | |||
gap: var(--fg-gap); | transform:translate3d(0,0,0); | ||
width: 100%; | transition:transform .65s cubic-bezier(.22,1,.36,1); | ||
transform: translate3d(0, 0, 0); | } | ||
transition: transform | .fgwiki-gallery__slide{ | ||
flex:0 0 calc( | |||
(100% - (var(--fg-items) - 1) * var(--fg-gap)) | |||
/ | |||
var(--fg-items) | |||
flex: 0 0 calc( | |||
); | ); | ||
min-width: 0; | min-width:0; | ||
margin: 0; | margin:0; | ||
overflow: hidden; | overflow:hidden; | ||
background: var(--fg-card-bg) | background:var(--fg-card-bg); | ||
border-radius:var(--fg-radius); | |||
border-radius: var(--fg-radius) | border:1px solid #e5e7eb; | ||
box-shadow:0 6px 18px rgba(0,0,0,.06); | |||
border: | |||
box-shadow: 0 | |||
transition: | transition: | ||
transform .4s ease, | |||
opacity .4s ease, | |||
filter .4s ease, | |||
box-shadow .4s ease; | |||
} | |||
.fgwiki-gallery__slide img{ | |||
width: | display:block; | ||
background: var(--fg-accent); | width:100%; | ||
border-radius: 999px; | height:var(--fg-image-height); | ||
padding:10px; | |||
object-fit:contain; | |||
object-position:center; | |||
outline: 2px solid var(--fg-accent); | background:var(--fg-image-bg); | ||
outline-offset: 2px; | border:0; | ||
} | |||
.fgwiki-gallery__caption{ | |||
min-height:62px; | |||
padding:12px 14px; | |||
background:var(--fg-caption-bg); | |||
color:var(--fg-caption-color); | |||
font-size:13px; | |||
font-weight:700; | |||
line-height:1.8; | |||
text-align:right; | |||
} | |||
.fgwiki- | /* موبایل هیچ Blur ندارد */ | ||
.fgwiki-gallery__slide, | |||
.fgwiki-gallery__slide.is-center, | |||
.fgwiki-gallery__slide:not(.is-center){ | |||
opacity:1; | |||
.fgwiki-gallery__button { | filter:none; | ||
transform:none; | |||
} | |||
/* دکمه ها */ | |||
.fgwiki-gallery__button{ | |||
position:absolute; | |||
top:50%; | |||
z-index:15; | |||
width:34px; | |||
height:34px; | |||
display:flex; | |||
align-items:center; | |||
justify-content:center; | |||
padding:0; | |||
border:0; | |||
border-radius:50%; | |||
background:rgba(36,52,71,.82); | |||
color:#fff; | |||
font-size:18px; | |||
cursor:pointer; | |||
box-shadow:2px 5px 4px rgba(0,0,0,.35); | |||
transform:translateY(-50%); | |||
transition:.25s; | |||
} | |||
.fgwiki-gallery__button:hover{ | |||
background:var(--fg-accent); | |||
transform:translateY(-50%) scale(1.08); | |||
} | |||
.fgwiki-gallery__button:focus-visible{ | |||
outline:3px solid rgba(255,42,42,.25); | |||
outline-offset:3px; | |||
} | |||
.fgwiki-gallery__button--right{ | |||
right:0; | |||
} | |||
.fgwiki-gallery__button--left{ | |||
left:0; | |||
} | |||
/* Dots */ | |||
.fgwiki-gallery__dots{ | |||
position:absolute; | |||
bottom:6px; | |||
left:50%; | |||
display:flex; | |||
gap:7px; | |||
transform:translateX(-50%); | |||
} | |||
.fgwiki-gallery__dot{ | |||
width:9px; | |||
height:9px; | |||
padding:0; | |||
border:0; | |||
border-radius:999px; | |||
background:#d6dbe1; | |||
cursor:pointer; | |||
transition:.25s; | |||
} | |||
.fgwiki-gallery__dot.is-active{ | |||
width:24px; | |||
background:var(--fg-accent); | |||
} | |||
.fgwiki-gallery__dot:focus-visible{ | |||
outline:2px solid var(--fg-accent); | |||
outline-offset:2px; | |||
} | |||
/* ---------- Tablet ---------- */ | |||
@media (min-width:601px){ | |||
.fgwiki-gallery{ | |||
--fg-items:2; | |||
--fg-gap:18px; | |||
--fg-image-height:280px; | |||
--fg-side-blur:1.5px; | |||
padding-left:46px; | |||
padding-right:46px; | |||
} | |||
.fgwiki-gallery__slide:not(.is-center){ | |||
transform:scale(.95); | |||
opacity:.6; | |||
filter:blur(var(--fg-side-blur)); | |||
} | |||
.fgwiki-gallery__slide.is-center{ | |||
transform:scale(1.03); | |||
opacity:1; | |||
filter:none; | |||
box-shadow:0 12px 28px rgba(255,42,42,.18); | |||
border-color:rgba(255,42,42,.30); | |||
} | |||
.fgwiki-gallery__caption{ | |||
min-height:68px; | |||
} | |||
.fgwiki-gallery__button{ | |||
width:40px; | |||
height:40px; | |||
font-size:21px; | |||
} | |||
} | |||
/* ---------- Desktop ---------- */ | |||
@media (min-width:901px){ | |||
.fgwiki-gallery{ | |||
--fg-items:3; | |||
--fg-image-height:300px; | |||
--fg-side-blur:2px; | |||
--fg-side-opacity:.55; | |||
padding-left:56px; | |||
padding-right:56px; | |||
} | |||
.fgwiki-gallery__slide:not(.is-center){ | |||
opacity:var(--fg-side-opacity); | |||
transform:scale(.94); | |||
} | |||
.fgwiki-gallery__button{ | |||
width:44px; | |||
height:44px; | |||
font-size:24px; | |||
} | |||
.fgwiki-gallery__caption{ | |||
min-height:72px; | |||
font-size:14px; | |||
} | |||
} | |||
/* کاهش انیمیشن */ | |||
@media (prefers-reduced-motion:reduce){ | |||
.fgwiki-gallery__track, | |||
.fgwiki-gallery__slide, | |||
.fgwiki-gallery__button, | |||
.fgwiki-gallery__dot{ | |||
transition:none; | |||
} | |||
} | |||
</style> | </style> | ||
<script> | <script> | ||
(function () { | |||
"use strict"; | |||
document.querySelectorAll(".fgwiki-gallery").forEach(function (slider) { | |||
const track = slider.querySelector(".fgwiki-gallery__track"); | |||
const viewport = slider.querySelector(".fgwiki-gallery__viewport"); | |||
const originalSlides = Array.from( | |||
slider.querySelectorAll(".fgwiki-gallery__slide") | |||
); | |||
const rightButton = slider.querySelector(".fgwiki-gallery__button--right"); | |||
const leftButton = slider.querySelector(".fgwiki-gallery__button--left"); | |||
const dotsContainer = slider.querySelector(".fgwiki-gallery__dots"); | |||
if ( | |||
!track || | |||
!viewport || | |||
originalSlides.length === 0 | |||
){ | |||
return; | |||
} | |||
/* ---------------------- */ | |||
/* State */ | |||
/* ---------------------- */ | |||
let currentIndex = 0; | |||
let visibleItems = 1; | |||
let slideWidth = 0; | |||
let slideStep = 0; | |||
let totalSlides = originalSlides.length; | |||
let autoPlayTimer = null; | |||
let isAnimating = false; | |||
let resizeTimer = null; | |||
let touchStartX = 0; | |||
let touchCurrentX = 0; | |||
let pointerDown = false; | |||
const autoPlayDelay = 3500; | |||
/* ---------------------- */ | |||
/* Helpers */ | |||
/* ---------------------- */ | |||
function getVisibleItems(){ | |||
const value = parseInt( | |||
getComputedStyle(slider) | |||
.getPropertyValue("--fg-items"), | |||
10 | |||
); | |||
return Math.max(1,value || 1); | |||
} | |||
/* ---------------------- */ | |||
function removeClones(){ | |||
track | |||
.querySelectorAll(".is-clone") | |||
.forEach(function(node){ | |||
node.remove(); | |||
}); | |||
} | |||
/* ---------------------- */ | |||
function cloneSlides(){ | |||
removeClones(); | |||
visibleItems = getVisibleItems(); | |||
const slides = Array.from(track.children) | |||
.filter(function(slide){ | |||
return !slide.classList.contains("is-clone"); | |||
}); | |||
const before = slides | |||
.slice(-visibleItems) | |||
.map(function(slide){ | |||
const clone = slide.cloneNode(true); | |||
clone.classList.add("is-clone"); | |||
clone.setAttribute("aria-hidden","true"); | |||
return clone; | |||
}); | |||
const after = slides | |||
.slice(0,visibleItems) | |||
.map(function(slide){ | |||
const clone = slide.cloneNode(true); | |||
clone.classList.add("is-clone"); | |||
clone.setAttribute("aria-hidden","true"); | |||
return clone; | |||
}); | |||
before.forEach(function(node){ | |||
track.insertBefore(node,track.firstChild); | |||
}); | |||
after.forEach(function(node){ | |||
track.appendChild(node); | |||
}); | |||
currentIndex = visibleItems; | |||
} | |||
/* ---------------------- */ | |||
function getSlides(){ | |||
return Array.from( | |||
track.querySelectorAll(".fgwiki-gallery__slide") | |||
); | |||
} | |||
/* ---------------------- */ | |||
function calculateSizes(){ | |||
const slide = getSlides()[0]; | |||
if(!slide){ | |||
return; | |||
} | |||
slideWidth = slide.offsetWidth; | |||
const gap = parseFloat( | |||
getComputedStyle(track).columnGap || | |||
getComputedStyle(track).gap || | |||
0 | |||
); | |||
slideStep = slideWidth + gap; | |||
} | |||
/* ---------------------- */ | |||
function translate(immediate=false){ | |||
const offset = currentIndex * slideStep; | |||
if(immediate){ | |||
track.style.transition="none"; | |||
}else{ | |||
track.style.transition=""; | |||
} | |||
/* RTL */ | |||
track.style.transform = | |||
"translate3d("+offset+"px,0,0)"; | |||
if(immediate){ | |||
requestAnimationFrame(function(){ | |||
track.style.transition=""; | |||
}); | |||
} | |||
} | |||
/* ---------------------- */ | |||
function updateCenter(){ | |||
const slides = getSlides(); | |||
slides.forEach(function(slide){ | |||
slide.classList.remove("is-center"); | |||
}); | |||
const center = | |||
currentIndex + | |||
Math.floor(visibleItems/2); | |||
if(slides[center]){ | |||
slides[center] | |||
.classList.add("is-center"); | |||
} | |||
} | |||
/* ---------------------- */ | |||
function updateDots(){ | |||
const dots = | |||
dotsContainer.querySelectorAll( | |||
".fgwiki-gallery__dot" | |||
); | |||
const realIndex = | |||
( | |||
( | |||
currentIndex-visibleItems | |||
)%totalSlides+ | |||
totalSlides | |||
)%totalSlides; | |||
const active = | |||
Math.min( | |||
realIndex, | |||
Math.max(0,totalSlides-visibleItems) | |||
); | |||
dots.forEach(function(dot,index){ | |||
const state=index===active; | |||
dot.classList.toggle( | |||
"is-active", | |||
state | |||
); | |||
dot.setAttribute( | |||
"aria-current", | |||
state | |||
); | |||
}); | |||
} | |||
/* ---------------------- */ | |||
function update(immediate=false){ | |||
calculateSizes(); | |||
translate(immediate); | |||
updateCenter(); | |||
updateDots(); | |||
} | |||
/* ---------------------- */ | |||
function build(){ | |||
cloneSlides(); | |||
createDots(); | |||
update(true); | |||
} | |||
/* ---------------------- */ | |||
function debounceResize(){ | |||
clearTimeout(resizeTimer); | |||
resizeTimer=setTimeout(function(){ | |||
const logicalIndex= | |||
( | |||
( | |||
currentIndex-visibleItems | |||
)%totalSlides+ | |||
totalSlides | |||
)%totalSlides; | |||
build(); | |||
currentIndex= | |||
visibleItems+ | |||
logicalIndex; | |||
update(true); | |||
},150); | |||
} | |||
/* ---------------------- */ | |||
/* Movement Logic */ | |||
/* ---------------------- */ | |||
function normalizeIndex(){ | |||
const maxIndex = | |||
totalSlides + visibleItems; | |||
if(currentIndex >= maxIndex){ | |||
currentIndex = visibleItems; | |||
update(true); | |||
} | |||
if(currentIndex < visibleItems){ | |||
currentIndex = | |||
totalSlides + | |||
visibleItems - | |||
1; | |||
update(true); | |||
} | |||
} | |||
/* ---------------------- */ | |||
function goToSlide(index){ | |||
if(isAnimating){ | |||
return; | |||
} | |||
currentIndex = index; | |||
isAnimating = true; | |||
update(false); | |||
} | |||
/* ---------------------- */ | |||
function moveRight(){ | |||
goToSlide(currentIndex + 1); | |||
} | |||
/* ---------------------- */ | |||
function moveLeft(){ | |||
goToSlide(currentIndex - 1); | |||
} | |||
/* ---------------------- */ | |||
/* Transition Handler */ | |||
/* ---------------------- */ | |||
track.addEventListener( | |||
"transitionend", | |||
function(event){ | |||
if(event.propertyName !== "transform"){ | |||
return; | |||
} | |||
if(!isAnimating){ | |||
return; | |||
} | |||
normalizeIndex(); | |||
isAnimating = false; | |||
}); | |||
/* ---------------------- */ | |||
/* Dots Navigation */ | |||
/* ---------------------- */ | |||
function createDots(){ | |||
if(!dotsContainer){ | |||
return; | |||
} | |||
const count = | |||
Math.max( | |||
1, | |||
totalSlides-visibleItems+1 | |||
); | |||
dotsContainer.innerHTML=""; | |||
for( | |||
let i=0; | |||
i<count; | |||
i++ | |||
){ | |||
const dot = | |||
document.createElement("button"); | |||
dot.type="button"; | |||
dot.className = | |||
"fgwiki-gallery__dot"; | |||
dot.setAttribute( | |||
"aria-label", | |||
"نمایش اسلاید شماره "+(i+1) | |||
); | |||
dot.addEventListener( | |||
"click", | |||
function(){ | |||
if(isAnimating){ | |||
return; | |||
} | |||
currentIndex = | |||
visibleItems+i; | |||
goToSlide(currentIndex); | |||
restartAutoPlay(); | |||
}); | |||
dotsContainer.appendChild(dot); | |||
} | |||
updateDots(); | |||
} | |||
/* ---------------------- */ | |||
/* Buttons */ | |||
/* ---------------------- */ | |||
if(rightButton){ | |||
rightButton.addEventListener( | |||
"click", | |||
function(){ | |||
moveRight(); | |||
restartAutoPlay(); | |||
}); | |||
} | |||
if(leftButton){ | |||
leftButton.addEventListener( | |||
"click", | |||
function(){ | |||
moveLeft(); | |||
restartAutoPlay(); | |||
}); | |||
} | |||
/* ---------------------- */ | |||
/* Keyboard Support */ | |||
/* ---------------------- */ | |||
slider.addEventListener( | |||
"keydown", | |||
function(event){ | |||
if(event.key==="ArrowLeft"){ | |||
moveLeft(); | |||
restartAutoPlay(); | |||
} | |||
if(event.key==="ArrowRight"){ | |||
moveRight(); | |||
restartAutoPlay(); | |||
} | |||
}); | |||
slider.setAttribute( | |||
"tabindex", | |||
"0" | |||
); | |||
/* ---------------------- */ | |||
/* Hover Pause */ | |||
/* ---------------------- */ | |||
slider.addEventListener( | |||
"mouseenter", | |||
stopAutoPlay | |||
); | |||
slider.addEventListener( | |||
"mouseleave", | |||
startAutoPlay | |||
); | |||
slider.addEventListener( | |||
"focusin", | |||
stopAutoPlay | |||
); | |||
slider.addEventListener( | |||
"focusout", | |||
function(event){ | |||
if(!slider.contains(event.relatedTarget)){ | |||
startAutoPlay(); | |||
} | |||
}); | |||
/* ---------------------- */ | |||
/* Touch / Swipe */ | |||
/* ---------------------- */ | |||
slider.addEventListener( | |||
"touchstart", | |||
function(event){ | |||
if(event.touches.length !== 1){ | |||
return; | |||
} | |||
pointerDown = true; | |||
touchStartX = | |||
event.touches[0].clientX; | |||
touchCurrentX = | |||
touchStartX; | |||
stopAutoPlay(); | |||
}, | |||
{ | |||
passive:true | |||
} | |||
); | |||
slider.addEventListener( | |||
"touchmove", | |||
function(event){ | |||
if(!pointerDown){ | |||
return; | |||
} | |||
touchCurrentX = | |||
event.touches[0].clientX; | |||
}, | |||
{ | |||
passive:true | |||
} | |||
); | |||
slider.addEventListener( | |||
"touchend", | |||
function(){ | |||
if(!pointerDown){ | |||
return; | |||
} | |||
pointerDown=false; | |||
const distance = | |||
touchCurrentX - | |||
touchStartX; | |||
if(Math.abs(distance)>45){ | |||
if(distance>0){ | |||
moveLeft(); | |||
}else{ | |||
moveRight(); | |||
} | |||
} | |||
startAutoPlay(); | |||
}, | |||
{ | |||
passive:true | |||
} | |||
); | |||
/* ---------------------- */ | |||
/* Auto Play */ | |||
/* ---------------------- */ | |||
function startAutoPlay(){ | |||
stopAutoPlay(); | |||
if( | |||
window.matchMedia( | |||
"(prefers-reduced-motion: reduce)" | |||
).matches | |||
){ | |||
return; | |||
} | |||
autoPlayTimer = | |||
setInterval(function(){ | |||
if(!isAnimating){ | |||
moveRight(); | |||
} | |||
},autoPlayDelay); | |||
} | |||
function stopAutoPlay(){ | |||
if(autoPlayTimer!==null){ | |||
clearInterval(autoPlayTimer); | |||
autoPlayTimer=null; | |||
} | |||
} | |||
function restartAutoPlay(){ | |||
stopAutoPlay(); | |||
startAutoPlay(); | |||
} | |||
/* ---------------------- */ | |||
/* Visibility Observer */ | |||
/* ---------------------- */ | |||
if("IntersectionObserver" in window){ | |||
const observer = | |||
new IntersectionObserver( | |||
function(entries){ | |||
entries.forEach(function(entry){ | |||
if(entry.isIntersecting){ | |||
startAutoPlay(); | |||
}else{ | |||
stopAutoPlay(); | |||
} | |||
}); | |||
}, | |||
{ | |||
threshold:.25 | |||
} | |||
); | |||
observer.observe(slider); | |||
}else{ | |||
startAutoPlay(); | |||
} | |||
/* ---------------------- */ | |||
/* Resize */ | |||
/* ---------------------- */ | |||
window.addEventListener( | |||
"resize", | |||
debounceResize | |||
); | |||
/* ---------------------- */ | |||
/* Initial Build */ | |||
/* ---------------------- */ | |||
build(); | |||
/* ---------------------- */ | |||
/* Accessibility */ | |||
/* ---------------------- */ | |||
slider.setAttribute( | |||
"role", | |||
"region" | |||
); | |||
slider.setAttribute( | |||
"aria-label", | |||
"گالری تصاویر" | |||
); | |||
track.setAttribute( | |||
"aria-live", | |||
"polite" | |||
); | |||
}); | |||
}); | |||
})(); | |||
</script> | </script> | ||
</html> | </html> | ||
نسخهٔ ۶ اوت ۲۰۲۶، ساعت ۰۸:۰۸