|
1 | 1 | import { useMemo, useRef, useEffect, useCallback } from 'react'; |
2 | | -import { useDispatch } from 'react-redux'; |
| 2 | +import { useDispatch, useSelector } from 'react-redux'; |
3 | 3 | import { ImageCard } from '@/components/Media/ImageCard'; |
4 | 4 | import { Image } from '@/types/Media'; |
5 | 5 | import { groupImagesByYearMonthFromMetadata } from '@/utils/dateUtils'; |
6 | 6 | import { setCurrentViewIndex } from '@/features/imageSlice'; |
| 7 | +import { MediaView } from './MediaView'; |
| 8 | +import { selectIsImageViewOpen } from '@/features/imageSelectors'; |
7 | 9 |
|
8 | 10 | export type MonthMarker = { |
9 | 11 | offset: number; |
@@ -31,6 +33,7 @@ export const ChronologicalGallery = ({ |
31 | 33 | const dispatch = useDispatch(); |
32 | 34 | const monthHeaderRefs = useRef<Map<string, HTMLDivElement | null>>(new Map()); |
33 | 35 | const galleryRef = useRef<HTMLDivElement>(null); |
| 36 | + const isImageViewOpen = useSelector(selectIsImageViewOpen); |
34 | 37 |
|
35 | 38 | // Optimized grouping with proper date handling |
36 | 39 | const grouped = useMemo( |
@@ -109,72 +112,76 @@ export const ChronologicalGallery = ({ |
109 | 112 | }, [recomputeMarkers, scrollContainerRef]); |
110 | 113 |
|
111 | 114 | return ( |
112 | | - <div ref={galleryRef} className={`space-y-0 ${className}`}> |
113 | | - {/* Title */} |
114 | | - {showTitle && ( |
115 | | - <div className="mb-6"> |
116 | | - <h1 className="mt-6 text-2xl font-bold">{title}</h1> |
117 | | - </div> |
118 | | - )} |
119 | | - |
120 | | - {/* Gallery Content */} |
121 | | - {sortedGrouped.map(({ year, months }) => ( |
122 | | - <div key={year} data-year={year}> |
123 | | - {months.map(([month, imgs]) => { |
124 | | - const monthName = new Date( |
125 | | - Number(year), |
126 | | - Number(month) - 1, |
127 | | - ).toLocaleString('default', { month: 'long' }); |
128 | | - |
129 | | - return ( |
130 | | - <div |
131 | | - key={`${year}-${month}`} |
132 | | - className="mb-8" |
133 | | - data-timeline-month={`${year}-${month}`} |
134 | | - id={`timeline-section-${year}-${month}`} |
135 | | - ref={(el) => { |
136 | | - const key = `${year}-${month}`; |
137 | | - if (el) { |
138 | | - monthHeaderRefs.current.set(key, el); |
139 | | - } else { |
140 | | - monthHeaderRefs.current.delete(key); |
141 | | - } |
142 | | - }} |
143 | | - > |
144 | | - {/* Sticky Month/Year Header */} |
145 | | - <div className="bg-background sticky top-0 z-10 py-3 backdrop-blur-sm"> |
146 | | - <h3 className="flex items-center text-xl font-semibold text-gray-800 dark:text-gray-200"> |
147 | | - <div className="bg-primary mr-2 h-6 w-1"></div> |
148 | | - {monthName} {year} |
149 | | - <div className="mt-1 ml-2 text-sm font-normal text-gray-500"> |
150 | | - {imgs.length} {imgs.length === 1 ? 'image' : 'images'} |
151 | | - </div> |
152 | | - </h3> |
153 | | - </div> |
154 | | - |
155 | | - {/* Images Grid */} |
156 | | - <div className="grid grid-cols-[repeat(auto-fill,_minmax(224px,_1fr))] gap-4 p-2"> |
157 | | - {imgs.map((img) => { |
158 | | - const chronologicalIndex = imageIndexMap.get(img.id) ?? -1; |
159 | | - |
160 | | - return ( |
161 | | - <div key={img.id} className="group relative"> |
162 | | - <ImageCard |
163 | | - image={img} |
164 | | - onClick={() => |
165 | | - dispatch(setCurrentViewIndex(chronologicalIndex)) |
166 | | - } |
167 | | - className="w-full transition-transform duration-200 group-hover:scale-105" |
168 | | - /> |
| 115 | + <> |
| 116 | + <div ref={galleryRef} className={`space-y-0 ${className}`}> |
| 117 | + {/* Title */} |
| 118 | + {showTitle && ( |
| 119 | + <div className="mb-6"> |
| 120 | + <h1 className="mt-6 text-2xl font-bold">{title}</h1> |
| 121 | + </div> |
| 122 | + )} |
| 123 | + |
| 124 | + {/* Gallery Content */} |
| 125 | + {sortedGrouped.map(({ year, months }) => ( |
| 126 | + <div key={year} data-year={year}> |
| 127 | + {months.map(([month, imgs]) => { |
| 128 | + const monthName = new Date( |
| 129 | + Number(year), |
| 130 | + Number(month) - 1, |
| 131 | + ).toLocaleString('default', { month: 'long' }); |
| 132 | + |
| 133 | + return ( |
| 134 | + <div |
| 135 | + key={`${year}-${month}`} |
| 136 | + className="mb-8" |
| 137 | + data-timeline-month={`${year}-${month}`} |
| 138 | + id={`timeline-section-${year}-${month}`} |
| 139 | + ref={(el) => { |
| 140 | + const key = `${year}-${month}`; |
| 141 | + if (el) { |
| 142 | + monthHeaderRefs.current.set(key, el); |
| 143 | + } else { |
| 144 | + monthHeaderRefs.current.delete(key); |
| 145 | + } |
| 146 | + }} |
| 147 | + > |
| 148 | + {/* Sticky Month/Year Header */} |
| 149 | + <div className="bg-background sticky top-0 z-10 py-3 backdrop-blur-sm"> |
| 150 | + <h3 className="flex items-center text-xl font-semibold text-gray-800 dark:text-gray-200"> |
| 151 | + <div className="bg-primary mr-2 h-6 w-1"></div> |
| 152 | + {monthName} {year} |
| 153 | + <div className="mt-1 ml-2 text-sm font-normal text-gray-500"> |
| 154 | + {imgs.length} {imgs.length === 1 ? 'image' : 'images'} |
169 | 155 | </div> |
170 | | - ); |
171 | | - })} |
| 156 | + </h3> |
| 157 | + </div> |
| 158 | + |
| 159 | + {/* Images Grid */} |
| 160 | + <div className="grid grid-cols-[repeat(auto-fill,_minmax(224px,_1fr))] gap-4 p-2"> |
| 161 | + {imgs.map((img) => { |
| 162 | + const chronologicalIndex = |
| 163 | + imageIndexMap.get(img.id) ?? -1; |
| 164 | + |
| 165 | + return ( |
| 166 | + <div key={img.id} className="group relative"> |
| 167 | + <ImageCard |
| 168 | + image={img} |
| 169 | + onClick={() => |
| 170 | + dispatch(setCurrentViewIndex(chronologicalIndex)) |
| 171 | + } |
| 172 | + className="w-full transition-transform duration-200 group-hover:scale-105" |
| 173 | + /> |
| 174 | + </div> |
| 175 | + ); |
| 176 | + })} |
| 177 | + </div> |
172 | 178 | </div> |
173 | | - </div> |
174 | | - ); |
175 | | - })} |
176 | | - </div> |
177 | | - ))} |
178 | | - </div> |
| 179 | + ); |
| 180 | + })} |
| 181 | + </div> |
| 182 | + ))} |
| 183 | + </div> |
| 184 | + {isImageViewOpen && <MediaView images={chronologicallySortedImages} />} |
| 185 | + </> |
179 | 186 | ); |
180 | 187 | }; |
0 commit comments