357 lines
9.8 KiB
JavaScript
357 lines
9.8 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import React, { useEffect, useState } from 'react'
|
|
import Image from 'next/image'
|
|
import AppContainer from './appContainer'
|
|
|
|
const shimmer = (width, height) => `
|
|
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
|
|
<defs>
|
|
<linearGradient id="gradient">
|
|
<stop stop-color="#e5e7eb" offset="20%" />
|
|
<stop stop-color="#f9fafb" offset="50%" />
|
|
<stop stop-color="#e5e7eb" offset="70%" />
|
|
</linearGradient>
|
|
</defs>
|
|
<rect width="${width}" height="${height}" fill="#e5e7eb" />
|
|
<rect width="${width}" height="${height}" fill="url(#gradient)" />
|
|
</svg>
|
|
`
|
|
|
|
const toBase64 = value =>
|
|
typeof window === 'undefined' ? Buffer.from(value).toString('base64') : window.btoa(value)
|
|
|
|
const galleryBannerLoader = () => '/resource/parallax/Gallery.jpg'
|
|
|
|
const Gallery = ({ images }) => {
|
|
const [selectedImage, setSelectedImage] = useState(null)
|
|
|
|
const closeLightbox = () => setSelectedImage(null)
|
|
|
|
const showPreviousImage = () => {
|
|
setSelectedImage(current => (current === 0 ? images.length - 1 : current - 1))
|
|
}
|
|
|
|
const showNextImage = () => {
|
|
setSelectedImage(current => (current === images.length - 1 ? 0 : current + 1))
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (selectedImage === null) return undefined
|
|
|
|
const handleKeyDown = event => {
|
|
if (event.key === 'Escape') setSelectedImage(null)
|
|
if (event.key === 'ArrowRight') {
|
|
setSelectedImage(current => (current === images.length - 1 ? 0 : current + 1))
|
|
}
|
|
if (event.key === 'ArrowLeft') {
|
|
setSelectedImage(current => (current === 0 ? images.length - 1 : current - 1))
|
|
}
|
|
}
|
|
|
|
const previousOverflow = document.body.style.overflow
|
|
document.body.style.overflow = 'hidden'
|
|
window.addEventListener('keydown', handleKeyDown)
|
|
|
|
return () => {
|
|
document.body.style.overflow = previousOverflow
|
|
window.removeEventListener('keydown', handleKeyDown)
|
|
}
|
|
}, [selectedImage, images.length])
|
|
|
|
return (
|
|
<AppContainer title='گالری بیمارستان مهر ایرانیان پرند'>
|
|
<style jsx>{`
|
|
.gallery-page {
|
|
direction: rtl;
|
|
padding: 3rem 1rem 5rem;
|
|
background: #fff;
|
|
}
|
|
|
|
.gallery-header {
|
|
max-width: 1200px;
|
|
margin: 0 auto 2rem;
|
|
text-align: right;
|
|
}
|
|
|
|
.gallery-header h2 {
|
|
margin: 0 0 0.5rem;
|
|
color: #263238;
|
|
font-size: 1.75rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.gallery-header p {
|
|
margin: 0;
|
|
color: #6b7280;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.gallery-header::after {
|
|
content: '';
|
|
display: block;
|
|
width: 54px;
|
|
height: 3px;
|
|
margin-top: 0.9rem;
|
|
border-radius: 999px;
|
|
background: #009688;
|
|
}
|
|
|
|
.gallery-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.gallery-card {
|
|
position: relative;
|
|
aspect-ratio: 16 / 9;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.85rem;
|
|
background: #f3f4f6;
|
|
cursor: zoom-in;
|
|
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07);
|
|
transition: transform 180ms ease, box-shadow 180ms ease;
|
|
}
|
|
|
|
.gallery-card:hover,
|
|
.gallery-card:focus-visible {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.15);
|
|
outline: none;
|
|
}
|
|
|
|
.gallery-card :global(img) {
|
|
transition: transform 250ms ease;
|
|
}
|
|
|
|
.gallery-card:hover :global(img) {
|
|
transform: scale(1.035);
|
|
}
|
|
|
|
.lightbox {
|
|
position: fixed;
|
|
z-index: 1500;
|
|
inset: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4.5rem 5rem 3rem;
|
|
background: rgba(0, 0, 0, 0.92);
|
|
}
|
|
|
|
.lightbox-image {
|
|
max-width: 100%;
|
|
max-height: calc(100vh - 7.5rem);
|
|
object-fit: contain;
|
|
border-radius: 0.4rem;
|
|
}
|
|
|
|
.lightbox-close,
|
|
.lightbox-navigation {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 0;
|
|
color: #fff;
|
|
background: rgba(255, 255, 255, 0.13);
|
|
cursor: pointer;
|
|
transition: background 150ms ease;
|
|
}
|
|
|
|
.lightbox-close:hover,
|
|
.lightbox-navigation:hover {
|
|
background: rgba(255, 255, 255, 0.25);
|
|
}
|
|
|
|
.lightbox-close {
|
|
top: 1.25rem;
|
|
right: 1.25rem;
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: 50%;
|
|
font-size: 1.9rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.lightbox-navigation {
|
|
top: 50%;
|
|
width: 46px;
|
|
height: 58px;
|
|
border-radius: 0.5rem;
|
|
font-size: 2rem;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.lightbox-previous {
|
|
left: 1.25rem;
|
|
}
|
|
|
|
.lightbox-next {
|
|
right: 1.25rem;
|
|
}
|
|
|
|
.lightbox-counter {
|
|
position: absolute;
|
|
bottom: 1rem;
|
|
left: 50%;
|
|
margin: 0;
|
|
color: #fff;
|
|
font-size: 0.9rem;
|
|
transform: translateX(-50%);
|
|
}
|
|
|
|
@media (max-width: 992px) {
|
|
.gallery-grid {
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.gallery-page {
|
|
padding: 2rem 1rem 4rem;
|
|
}
|
|
|
|
.gallery-grid {
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.lightbox {
|
|
padding: 4rem 1rem;
|
|
}
|
|
|
|
.lightbox-navigation {
|
|
top: auto;
|
|
bottom: 0.8rem;
|
|
transform: none;
|
|
}
|
|
|
|
.lightbox-previous {
|
|
left: 1rem;
|
|
}
|
|
|
|
.lightbox-next {
|
|
right: 1rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.gallery-header h2 {
|
|
font-size: 1.4rem;
|
|
}
|
|
|
|
.gallery-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
`}</style>
|
|
|
|
<div className='parallax-container'>
|
|
<h1 className='center-align text-white header_back service-text dana font-weight-bold'>گالری بیمارستان</h1>
|
|
<Image
|
|
loader={galleryBannerLoader}
|
|
src='gallery-banner.jpg'
|
|
className='responsive-img shadow-5'
|
|
alt='گالری بیمارستان مهر ایرانیان پرند'
|
|
width={3000}
|
|
height={1300}
|
|
priority
|
|
/>
|
|
</div>
|
|
|
|
<main className='gallery-page'>
|
|
<header className='gallery-header'>
|
|
<h2>گالری تصاویر</h2>
|
|
<p>تصاویر بیمارستان مهر ایرانیان پرند</p>
|
|
</header>
|
|
|
|
<section className='gallery-grid' aria-label='تصاویر گالری بیمارستان'>
|
|
{images.map((image, index) => (
|
|
<button
|
|
type='button'
|
|
className='gallery-card'
|
|
key={image.id}
|
|
aria-label={`نمایش تصویر ${index + 1} از گالری`}
|
|
onClick={() => setSelectedImage(index)}
|
|
>
|
|
<Image
|
|
src={image.image}
|
|
alt={image.title}
|
|
layout='fill'
|
|
objectFit='cover'
|
|
placeholder='blur'
|
|
blurDataURL={`data:image/svg+xml;base64,${toBase64(shimmer(640, 360))}`}
|
|
/>
|
|
</button>
|
|
))}
|
|
</section>
|
|
</main>
|
|
|
|
{selectedImage !== null && (
|
|
<div className='lightbox' role='dialog' aria-modal='true' aria-label='نمایش تصویر گالری' onClick={closeLightbox}>
|
|
<button type='button' className='lightbox-close' aria-label='بستن تصویر' onClick={closeLightbox}>
|
|
×
|
|
</button>
|
|
<button
|
|
type='button'
|
|
className='lightbox-navigation lightbox-previous'
|
|
aria-label='تصویر قبلی'
|
|
onClick={event => {
|
|
event.stopPropagation()
|
|
showPreviousImage()
|
|
}}
|
|
>
|
|
‹
|
|
</button>
|
|
<img
|
|
className='lightbox-image'
|
|
src={images[selectedImage].image}
|
|
alt={images[selectedImage].title}
|
|
onClick={event => event.stopPropagation()}
|
|
/>
|
|
<button
|
|
type='button'
|
|
className='lightbox-navigation lightbox-next'
|
|
aria-label='تصویر بعدی'
|
|
onClick={event => {
|
|
event.stopPropagation()
|
|
showNextImage()
|
|
}}
|
|
>
|
|
›
|
|
</button>
|
|
<p className='lightbox-counter'>
|
|
{selectedImage + 1} از {images.length}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</AppContainer>
|
|
)
|
|
}
|
|
|
|
export async function getStaticProps() {
|
|
const galleryDirectory = path.join(process.cwd(), 'public', 'resource', 'images', 'gallery')
|
|
const fileNames = fs
|
|
.readdirSync(galleryDirectory)
|
|
.filter(fileName => /\.(jpe?g|png|webp)$/i.test(fileName))
|
|
.sort((first, second) => first.localeCompare(second, undefined, { numeric: true }))
|
|
|
|
const images = fileNames.map((fileName, index) => ({
|
|
id: fileName,
|
|
image: `/resource/images/gallery/${encodeURIComponent(fileName)}`,
|
|
title: `تصویر ${index + 1} از بیمارستان مهر ایرانیان پرند`
|
|
}))
|
|
|
|
return {
|
|
props: { images }
|
|
}
|
|
}
|
|
|
|
export default Gallery
|