1- // components/shared/NewsGallerySimple.tsx
2-
31"use client" ;
42
53import React , { useState , useEffect } from "react" ;
@@ -8,12 +6,14 @@ import Image from "next/image";
86interface NewsGallerySimpleProps {
97 gallery ?: string [ ] | null ;
108 mainImage ?: string ;
11- params :any ;
9+ params : any ;
1210}
1311
14- export default function NewsGallerySimple ( { gallery, mainImage , params } : NewsGallerySimpleProps ) {
12+ export default function NewsGallerySimple ( { gallery, mainImage, params } : NewsGallerySimpleProps ) {
1513 const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
1614 const [ currentIndex , setCurrentIndex ] = useState ( 0 ) ;
15+ const [ isImageFullscreen , setIsImageFullscreen ] = useState ( false ) ;
16+ const [ fullscreenImage , setFullscreenImage ] = useState ( '' ) ;
1717
1818 if ( ! gallery || gallery . length === 0 ) {
1919 return null ;
@@ -27,15 +27,13 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
2727 // تعیین تعداد نمایش بر اساس صفحه
2828 const getDisplayCount = ( ) => {
2929 if ( typeof window !== 'undefined' ) {
30- return window . innerWidth < 768 ? 4 : 3 ; // موبایل: 4, دسکتاپ: 3
30+ return window . innerWidth < 768 ? 4 : 3 ;
3131 }
32- return 4 ; // پیشفرض موبایل
32+ return 4 ;
3333 } ;
3434
3535 const [ displayCount , setDisplayCount ] = useState ( 4 ) ;
3636 const showViewMoreButton = allImages . length > displayCount ;
37-
38- // فقط تعداد مشخصی تصویر اول برای پیشنمایش
3937 const previewImages = allImages . slice ( 0 , displayCount ) ;
4038
4139 // بررسی تغییر سایز صفحه
@@ -45,7 +43,7 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
4543 setDisplayCount ( newCount ) ;
4644 } ;
4745
48- handleResize ( ) ; // تنظیم اولیه
46+ handleResize ( ) ;
4947 window . addEventListener ( 'resize' , handleResize ) ;
5048 return ( ) => window . removeEventListener ( 'resize' , handleResize ) ;
5149 } , [ ] ) ;
@@ -57,12 +55,27 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
5755 document . body . style . overflow = "hidden" ;
5856 } ;
5957
60- // بستن مودال - فقط با دکمه بستن
58+ // بستن مودال
6159 const closeModal = ( ) => {
6260 setIsModalOpen ( false ) ;
6361 document . body . style . overflow = "" ;
6462 } ;
6563
64+ // باز کردن تصویر در تمام صفحه
65+ const openImageFullscreen = ( imageUrl : string , e ?: React . MouseEvent ) => {
66+ if ( e ) e . stopPropagation ( ) ;
67+ setFullscreenImage ( imageUrl ) ;
68+ setIsImageFullscreen ( true ) ;
69+ document . body . style . overflow = "hidden" ;
70+ } ;
71+
72+ // بستن تصویر تمام صفحه
73+ const closeImageFullscreen = ( ) => {
74+ setIsImageFullscreen ( false ) ;
75+ setFullscreenImage ( '' ) ;
76+ document . body . style . overflow = "" ;
77+ } ;
78+
6679 // رفتن به اسلاید قبلی
6780 const goToPrevious = ( e ?: React . MouseEvent ) => {
6881 if ( e ) e . stopPropagation ( ) ;
@@ -81,17 +94,7 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
8194 setCurrentIndex ( index ) ;
8295 } ;
8396
84- // تمام صفحه کردن
85- const toggleFullscreen = async ( e : React . MouseEvent ) => {
86- e . stopPropagation ( ) ;
87- if ( ! document . fullscreenElement ) {
88- await document . documentElement . requestFullscreen ( ) ;
89- } else {
90- await document . exitFullscreen ( ) ;
91- }
92- } ;
93-
94- // ناوبری با کیبورد
97+ // ناوبری با کیبورد برای مودال اصلی
9598 useEffect ( ( ) => {
9699 if ( ! isModalOpen ) return ;
97100
@@ -109,6 +112,20 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
109112 return ( ) => window . removeEventListener ( "keydown" , handleKeyDown ) ;
110113 } , [ isModalOpen ] ) ;
111114
115+ // ناوبری با کیبورد برای حالت تمام صفحه تصویر
116+ useEffect ( ( ) => {
117+ if ( ! isImageFullscreen ) return ;
118+
119+ const handleKeyDown = ( e : KeyboardEvent ) => {
120+ if ( e . key === "Escape" ) {
121+ closeImageFullscreen ( ) ;
122+ }
123+ } ;
124+
125+ window . addEventListener ( "keydown" , handleKeyDown ) ;
126+ return ( ) => window . removeEventListener ( "keydown" , handleKeyDown ) ;
127+ } , [ isImageFullscreen ] ) ;
128+
112129 // پشتیبانی از سوایپ لمسی برای موبایل
113130 const [ touchStart , setTouchStart ] = useState ( 0 ) ;
114131 const [ touchEnd , setTouchEnd ] = useState ( 0 ) ;
@@ -137,12 +154,12 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
137154
138155 return (
139156 < >
140- { /* پیشنمایش گالری گرید - تعداد متغیر بر اساس دستگاه */ }
157+ { /* پیشنمایش گالری گرید */ }
141158 < div className = "w-full my-8" >
142159 < div className = { `grid gap-3 md:gap-3 ${
143160 displayCount === 4
144- ? 'grid-cols-2' // موبایل: 4 ستون
145- : 'grid-cols-3' // دسکتاپ: 3 ستون
161+ ? 'grid-cols-2'
162+ : 'grid-cols-3'
146163 } `} >
147164 { previewImages . map ( ( img , idx ) => (
148165 < div
@@ -158,7 +175,6 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
158175 sizes = "(max-width: 768px) 25vw, 33vw"
159176 unoptimized = { true }
160177 />
161- { /* لایه تیره و متن "+ بیشتر" برای آخرین عکس اگر بیشتر از تعداد نمایش باشد */ }
162178 { idx === displayCount - 1 && showViewMoreButton && (
163179 < div className = "absolute inset-0 bg-black/40 flex items-center justify-center transition-opacity group-hover:bg-black/70" >
164180 < div className = "text-center text-white" >
@@ -171,7 +187,7 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
171187 < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
172188 </ svg >
173189 < span className = "text-sm font-medium" >
174- +{ allImages . length - displayCount } < span > { params == "fa" ? "بیشتر" : "more" } </ span >
190+ +{ allImages . length - displayCount } < span > { params == "fa" ? "بیشتر" : "more" } </ span >
175191 </ span >
176192 </ div >
177193 </ div >
@@ -181,34 +197,28 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
181197 </ div >
182198 </ div >
183199
184- { /* مودال فول اسکرین با اسلایدر و thumbnail */ }
200+ { /* مودال اسلایدر اصلی */ }
185201 { isModalOpen && (
186- < div
187- className = "fixed inset-0 z-[9999] backdrop-blur-md bg-white/10 dark:bg-black/20"
188-
189- >
190- { /* هدر مودال با دکمههای کنترل */ }
191- < div className = "absolute top-0 left-0 right-0 z-20 flex justify-between p-4 " >
192- { /* دکمه بستن - فقط همین دکمه مودال رو میبنده */ }
202+ < div className = "fixed inset-0 z-[9999] backdrop-blur-md bg-white/10 dark:bg-black/20" >
203+ { /* هدر مودال */ }
204+ < div className = "absolute top-0 left-0 right-0 z-20 flex justify-between p-4" >
193205 < button
194206 onClick = { closeModal }
195- className = "px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center"
207+ className = "px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center"
196208 aria-label = "بستن"
197209 >
198210 < svg className = "w-6 h-6" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
199211 < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M6 18L18 6M6 6l12 12" />
200212 </ svg >
201213 </ button >
202214
203- { /* شمارنده تصاویر */ }
204- < div className = "px-5 flex items-center justify-center rounded-full bg-black/50 text-white text-sm" >
215+ < div className = "px-5 flex items-center justify-center rounded-full bg-black/50 text-white text-sm" >
205216 < span > { currentIndex + 1 } / { allImages . length } </ span >
206217 </ div >
207218
208- { /* دکمه تمام صفحه */ }
209219 < button
210- onClick = { toggleFullscreen }
211- className = "px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center"
220+ onClick = { ( e ) => openImageFullscreen ( allImages [ currentIndex ] , e ) }
221+ className = "px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center"
212222 aria-label = "تمام صفحه"
213223 >
214224 < svg className = "w-5 h-5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
@@ -218,59 +228,52 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
218228 </ div >
219229
220230 { /* اسلایدر اصلی */ }
221- < div
222- className = "relative w-full h-full cursor-pointer"
223- onClick = { ( e ) => e . stopPropagation ( ) }
224- >
231+ < div className = "relative w-full h-full cursor-pointer" >
225232 < div
226233 className = "relative w-full h-full flex items-center justify-center"
227234 onTouchStart = { handleTouchStart }
228235 onTouchMove = { handleTouchMove }
229236 onTouchEnd = { handleTouchEnd }
230237 >
231- { /* تصویر اصلی */ }
232- < div className = "relative w-full h-full max-w-7xl mx-auto " >
238+ < div className = "relative w-full h-full max-w-7xl mx-auto" >
233239 < Image
234240 src = { allImages [ currentIndex ] }
235241 alt = { `تصویر ${ currentIndex + 1 } ` }
236242 fill
237- className = " p-4 md:p-8 object-contain mx-auto my-auto lg:my-0 rounded-3xl !h-max !w-max !max-h-full !max-w-full"
243+ className = "p-4 md:p-8 object-contain mx-auto my-auto lg:my-0 rounded-3xl !h-max !w-max !max-h-full !max-w-full"
238244 sizes = "100vw"
239245 priority
240246 unoptimized = { true }
241247 />
242248 </ div >
243249
244- { /* دکمه قبلی */ }
245- { allImages . length > 1 && (
246- < button
247- onClick = { goToPrevious }
248- className = "absolute right-4 md:right-6 px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center shadow-lg"
249- aria-label = "قبلی"
250- >
251- < svg className = "w-6 h-6 md:w-7 md:h-7" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
252- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
253- </ svg >
254- </ button >
255- ) }
256-
257- { /* دکمه بعدی */ }
258250 { allImages . length > 1 && (
259- < button
260- onClick = { goToNext }
261- className = "absolute left-4 md:left-6 px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center shadow-lg"
262- aria-label = "بعدی"
263- >
264- < svg className = "w-6 h-6 md:w-7 md:h-7" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
265- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M15 19l-7-7 7-7" />
266- </ svg >
267- </ button >
251+ < >
252+ < button
253+ onClick = { goToPrevious }
254+ className = "absolute right-4 md:right-6 px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center shadow-lg"
255+ aria-label = "قبلی"
256+ >
257+ < svg className = "w-6 h-6 md:w-7 md:h-7" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
258+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
259+ </ svg >
260+ </ button >
261+ < button
262+ onClick = { goToNext }
263+ className = "absolute left-4 md:left-6 px-3 aspect-square rounded-full bg-black/50 dark:bg-white/50 dark:text-black dark:hover:bg-white/80 text-white hover:bg-black/70 flex items-center justify-center shadow-lg"
264+ aria-label = "بعدی"
265+ >
266+ < svg className = "w-6 h-6 md:w-7 md:h-7" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
267+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M15 19l-7-7 7-7" />
268+ </ svg >
269+ </ button >
270+ </ >
268271 ) }
269272 </ div >
270273
271- { /* ثامبیلنیل (تصاویر کوچک در پایین) - به صورت افقی و در مرکز */ }
274+ { /* thumbnails */ }
272275 { allImages . length > 1 && (
273- < div className = "absolute bottom-0 left-0 right-0 z-20 pb-4 md:pb-6 bg-gradient-to-t from-black/70 to-transparent pt-8" >
276+ < div className = "absolute bottom-0 left-0 right-0 z-20 pb-4 md:pb-6 bg-gradient-to-t from-black/70 to-transparent pt-8" >
274277 < div className = "flex justify-center items-center px-4" >
275278 < div className = "flex gap-2 md:gap-3 mb-[60px] lg:mb-0 py-5 overflow-x-auto w-full scrollbar-hide justify-center" >
276279 { allImages . map ( ( img , idx ) => (
@@ -301,7 +304,38 @@ export default function NewsGallerySimple({ gallery, mainImage , params }: NewsG
301304 </ div >
302305 ) }
303306
304- { /* استایل برای مخفی کردن اسکرولبار در مرورگرها */ }
307+ { /* مودال تمام صفحه برای نمایش تصویر به صورت کامل و بدون حاشیه */ }
308+ { isImageFullscreen && (
309+ < div
310+ className = "fixed inset-0 z-[10000] bg-black"
311+ onClick = { closeImageFullscreen }
312+ >
313+ < button
314+ onClick = { closeImageFullscreen }
315+ className = "absolute top-4 right-4 z-20 w-[60px] h-[60px] rounded-full bg-white/20 hover:bg-white/30 text-white transition-all duration-200 flex items-center justify-center"
316+ aria-label = "بستن"
317+ >
318+ < svg className = "w-6 h-6" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
319+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M6 18L18 6M6 6l12 12" />
320+ </ svg >
321+ </ button >
322+
323+
324+ < div className = "relative w-full h-full" >
325+ < Image
326+ src = { fullscreenImage }
327+ alt = "Fullscreen image"
328+ fill
329+ className = "object-contain p-4"
330+ sizes = "100vw"
331+ priority
332+ unoptimized = { true }
333+ onClick = { ( e ) => e . stopPropagation ( ) }
334+ />
335+ </ div >
336+ </ div >
337+ ) }
338+
305339 < style jsx global > { `
306340 .scrollbar-hide {
307341 -ms-overflow-style: none;
0 commit comments