add gallery

This commit is contained in:
reza karimi
2026-09-28 13:33:01 +03:30
parent e2199dc294
commit c8f091a694
67 changed files with 2039 additions and 608 deletions
Generated
+1
View File
@@ -0,0 +1 @@
pjson.js
+1
View File
@@ -20,3 +20,4 @@ export const AppFile = addr => {
return `${serve}/${addr}`
}
export const AppProduction = 'https://mehriranianco.ir/api/'
// export const AppProduction = 'http://127.0.0.1:8000/api/'
+336 -73
View File
@@ -1,93 +1,356 @@
import fs from 'fs'
import path from 'path'
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import AppContainer from './appContainer'
import { AppFile, AppUrl } from '../lib/api'
import Image from 'next/image'
import dynamic from 'next/dynamic'
import { Suspense } from 'react'
import AppContainer from './appContainer'
import { MDBBtn, MDBCol, MDBContainer, MDBRow } from 'mdb-react-ui-kit'
import { LightBox } from 'react-lightbox-pack'
import { Button, Divider, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react'
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 APV = dynamic(() => import('./components/Videos'), {
ssr: false
})
const shimmer = (w, h) => `
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="g">
<stop stop-color="#333" offset="20%" />
<stop stop-color="#222" offset="50%" />
<stop stop-color="#333" offset="70%" />
</linearGradient>
</defs>
<rect width="${w}" height="${h}" fill="#333" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`
const toBase64 = value =>
typeof window === 'undefined' ? Buffer.from(value).toString('base64') : window.btoa(value)
const toBase64 = str => (typeof window === 'undefined' ? Buffer.from(str).toString('base64') : window.btoa(str))
const galleryBannerLoader = () => '/resource/parallax/Gallery.jpg'
const Gallery = dataImage => {
const [Images, SetImages] = useState(dataImage)
const [justifyActive, setJustifyActive] = React.useState('tab1')
const [toggle, setToggle] = React.useState(false)
const [sIndex, setSIndex] = React.useState(0)
const [filterId, setFilterId] = React.useState(1)
const Parallax = ({ quality }) => {
return `../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 Filter = async filter => {
// const res = await axios.get(AppUrl(`FilterGalleyImages/${filter}`))
// SetImages({ dataImage: res.data })
// setFilterId(filter)
// }
// const AllImage = async () => {
// const res = await axios.get(AppUrl(`GetGalleyImages`))
// SetImages({ dataImage: res.data })
// }
const showNextImage = () => {
setSelectedImage(current => (current === images.length - 1 ? 0 : current + 1))
}
// Handler
// const lightBoxHandler = (state, sIndex) => {
// setToggle(state)
// setSIndex(sIndex)
// }
useEffect(() => {
if (selectedImage === null) return undefined
const handleJustifyClick = value => {
if (value === justifyActive) {
return
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))
}
}
setJustifyActive(value)
}
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 (
<div>
<style jsx>
{`
.cardImage {
background-color: #f3f4f6;
padding: 5px;
border-radius: 1rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 2px;
<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));
}
`}
</style>
<AppContainer></AppContainer>
</div>
}
@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}>
&times;
</button>
<button
type='button'
className='lightbox-navigation lightbox-previous'
aria-label='تصویر قبلی'
onClick={event => {
event.stopPropagation()
showPreviousImage()
}}
>
&#8249;
</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()
}}
>
&#8250;
</button>
<p className='lightbox-counter'>
{selectedImage + 1} از {images.length}
</p>
</div>
)}
</AppContainer>
)
}
export async function getServerSideProps(context) {
// const res = await axios.get(AppUrl('GetGalleyImages'));
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: {
dataImage: null
} // will be passed to the page component as props
props: { images }
}
}
export default Gallery
+6 -6
View File
@@ -215,7 +215,7 @@ export default function App() {
</div>
</Link>
</MDBNavbarLink> */}
<MDBNavbarLink
{/* <MDBNavbarLink
className={
router.pathname === '/medical-equipment' ? 'active-item text-white' : '' + 'text-white nav_item '
}
@@ -225,16 +225,16 @@ export default function App() {
<span style={{ cursor: 'pointer', fontSize: '15px' }}>واحد تجهیزات پزشکی </span>
</div>
</Link>
</MDBNavbarLink>
<MDBNavbarLink
</MDBNavbarLink> */}
{/* <MDBNavbarLink
className={router.pathname === '/stock-unit' ? 'active-item text-white' : '' + 'text-white nav_item '}
>
{/* <Link className={'text-white nav_item d-flex flex-row-reverse '} href='/stock-unit'>
<Link className={'text-white nav_item d-flex flex-row-reverse '} href='/stock-unit'>
<div className={'pointer d-flex justify-content-end'}>
<span style={{ cursor: 'pointer', fontSize: '15px' }}>امور سهام </span>
</div>
</Link> */}
</MDBNavbarLink>
</Link>
</MDBNavbarLink> */}
{/* <MDBNavbarLink
className={router.pathname === '/page/news/52' ? 'active-item text-white' : '' + 'text-white nav_item '}
+1042
View File
File diff suppressed because it is too large Load Diff
-26
View File
@@ -16,32 +16,6 @@ const MedicalEquipment = () => {
height={2000}
/>
</div>
<div className='lg:mx-20 sm:mx-5 my-25'>
<div className={'bk-med flex justify-content-center align-items-center flex-col'}>
<div>
<MDBTypography
style={{ borderLeft: 'none', borderRight: '6px solid ', backgroundColor: '#F0F0F0' }}
note
noteColor='dark'
className='mb-0'
>
<MDBRow>
<MDBTypography className={'dana right-align'}>
اگر به دنبال همکاری با بخش تجهیزات بیمارستان هستید، لطفا با یکی از شماره‌های زیر تماس حاصل نمایید تا
اطلاعات بیشتری در این خصوص از ما دریافت کنید
</MDBTypography>
</MDBRow>
</MDBTypography>
</div>
<div className='flex lg:flex-row md:flex-col justify-center items-center sm:flex-col gap-x-5 mt-4'>
<a className='dana' href='tel:021-53457999'>021-53457999</a>
<br />
<a className='dana' href='tel:09194199420'>09194199420</a>
<br />
<a>خانم زارعی</a>
</div>
</div>
</div>
</AppContainer>
)
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB