@@ -61,53 +61,14 @@ <h2 class="font-serif text-4xl text-gray-900 mb-2" i18n="@@galleryTitle">Gallery
6161 </ div >
6262 } @else {
6363 <!-- List View -->
64- < div class ="bg-white rounded-xl shadow-card overflow-hidden border border-gray-100 animate-page-enter ">
65- < div class ="overflow-x-auto ">
66- < table class ="min-w-full divide-y divide-gray-100 ">
67- < thead class ="bg-gray-50 ">
68- < tr >
69- < th scope ="col " class ="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider " i18n ="@@galleryTableImage "> Image</ th >
70- < th scope ="col " class ="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider " i18n ="@@galleryTableInfo "> File Info</ th >
71- < th scope ="col " class ="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider " i18n ="@@galleryTableCategory "> Category</ th >
72- < th scope ="col " class ="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider " i18n ="@@galleryTableDate "> Date</ th >
73- < th scope ="col " class ="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider " i18n ="@@galleryTableStatus "> Status</ th >
74- < th scope ="col " class ="relative px-6 py-3 ">
75- < span class ="sr-only " i18n ="@@galleryTableActions "> Actions</ span >
76- </ th >
77- </ tr >
78- </ thead >
79- < tbody class ="bg-white divide-y divide-gray-100 ">
80- @for(image of filteredImages(); track image.id; let i = $index) {
81- < tr class ="hover:bg-gray-50/50 transition-colors duration-200 reveal-item " [style.animation-delay.ms] ="i * 50 ">
82- < td class ="px-6 py-4 whitespace-nowrap ">
83- < img [src] ="image.imageUrl " [alt] ="image.alt " width ="64 " height ="64 " class ="w-16 h-16 object-cover rounded-lg shadow-sm "/>
84- </ td >
85- < td class ="px-6 py-4 whitespace-nowrap ">
86- < div class ="text-sm font-medium text-gray-900 "> {{ image.title }}</ div >
87- </ td >
88- < td class ="px-6 py-4 whitespace-nowrap ">
89- < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 ">
90- {{ image.category }}
91- </ span >
92- </ td >
93- < td class ="px-6 py-4 whitespace-nowrap text-sm text-gray-500 ">
94- {{ image.createdAt | date:'mediumDate' }}
95- </ td >
96- < td class ="px-6 py-4 whitespace-nowrap ">
97- < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium "
98- [class] ="image.status === 'published' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800' ">
99- {{ image.status }}
100- </ span >
101- </ td >
102- < td class ="px-6 py-4 whitespace-nowrap text-right text-sm font-medium space-x-4 ">
103- < button (click) ="openModal(image) " class ="text-primary hover:text-primary-hover transition-colors " i18n ="@@galleryActionEdit "> Edit</ button >
104- < button (click) ="deleteImage(image.id) " class ="text-red-500 hover:text-red-700 transition-colors " i18n ="@@galleryActionDelete "> Delete</ button >
105- </ td >
106- </ tr >
107- }
108- </ tbody >
109- </ table >
110- </ div >
64+ < div class ="animate-page-enter ">
65+ < app-list-view
66+ [items] ="filteredImages() "
67+ [columns] ="columns() "
68+ (edit) ="openModal($event) "
69+ (delete) ="deleteImage($event.toString()) "
70+ (view) ="openImageModal($event) "
71+ > </ app-list-view >
11172 </ div >
11273 }
11374</ div >
@@ -123,41 +84,7 @@ <h2 class="font-serif text-4xl text-gray-900 mb-2" i18n="@@galleryTitle">Gallery
12384}
12485
12586<!-- Image Modal -->
126- @if (selectedImage()) {
127- < div class ="fixed inset-0 z-[100] flex items-center justify-center " role ="dialog " aria-modal ="true ">
128- <!-- Backdrop -->
129- < div class ="absolute inset-0 bg-black/80 backdrop-blur-md transition-opacity animate-fade-in " (click) ="closeImageModal() "> </ div >
130-
131- <!-- Close Button -->
132- < button (click) ="closeImageModal() " class ="fixed top-6 right-6 z-[110] text-white/50 hover:text-white transition-colors p-2 hover:bg-white/10 rounded-full cursor-pointer ">
133- < span class ="sr-only "> Close</ span >
134- < svg xmlns ="http://www.w3.org/2000/svg " width ="36 " height ="36 " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 " stroke-linecap ="round " stroke-linejoin ="round "> < line x1 ="18 " y1 ="6 " x2 ="6 " y2 ="18 "> </ line > < line x1 ="6 " y1 ="6 " x2 ="18 " y2 ="18 "> </ line > </ svg >
135- </ button >
136-
137- <!-- Modal Content -->
138- < div class ="relative z-[105] w-full h-full p-4 md:p-12 flex flex-col items-center justify-center pointer-events-none ">
139- < div class ="pointer-events-auto relative rounded-lg overflow-hidden shadow-2xl bg-transparent animate-slide-up flex items-center justify-center min-w-[300px] min-h-[300px] ">
140-
141- <!-- Loading State -->
142- @if (isImageLoading()) {
143- < div class ="absolute inset-0 z-20 flex flex-col items-center justify-center bg-black/40 backdrop-blur-sm ">
144- < div class ="w-12 h-12 border-4 border-white/20 border-t-gold rounded-full animate-spin mb-3 "> </ div >
145- < p class ="text-white/60 text-[10px] uppercase tracking-[0.2em] font-medium animate-pulse " i18n ="@@galleryLoading "> Loading Asset</ p >
146- </ div >
147- }
148-
149- < img [src] ="selectedImage() "
150- (load) ="onImageLoad() "
151- alt ="Gallery image full screen view "
152- class ="max-w-full max-h-[85vh] object-contain shadow-2xl transition-all duration-700 ease-out "
153- [class.opacity-0] ="isImageLoading() "
154- [class.scale-95] ="isImageLoading() "
155- [class.opacity-100] ="!isImageLoading() "
156- [class.scale-100] ="!isImageLoading() "
157- >
158- </ div >
159-
160- < p class ="text-white/40 text-xs mt-6 font-medium tracking-[0.3em] uppercase animate-fade-in text-center " i18n ="@@galleryFooter "> Mavluda Beauty • Portfolio</ p >
161- </ div >
162- </ div >
163- }
87+ < app-image-popup
88+ [imageUrl] ="selectedImage() "
89+ (close) ="closeImageModal() "
90+ > </ app-image-popup >
0 commit comments