Skip to content

Commit 1db9393

Browse files
committed
feat: preview images on gallery
1 parent a05cade commit 1db9393

File tree

2 files changed

+87
-30
lines changed

2 files changed

+87
-30
lines changed

apps/web/components/Camera.tsx

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function Camera() {
4747
}
4848
};
4949
pollImages();
50-
// eslint-disable-next-line react-hooks/exhaustive-deps
50+
// eslint-disable-next-line react-hooks/exhaustive-deps
5151
}, [images]);
5252

5353
const fetchImages = async () => {
@@ -128,11 +128,24 @@ export function Camera() {
128128
</motion.div>
129129
))
130130
: images.map((image, index) => (
131-
<ImageCard
132-
id={image.id}
133-
imageUrl={image.imageUrl}
134-
status={image.status}
135-
/>
131+
<div
132+
key={image.id}
133+
className="cursor-pointer transition-transform hover:scale-[1.02]"
134+
onClick={() => handleImageClick(image, index)}
135+
role="button"
136+
tabIndex={0}
137+
onKeyDown={(e) => {
138+
if (e.key === "Enter" || e.key === " ") {
139+
handleImageClick(image, index);
140+
}
141+
}}
142+
>
143+
<ImageCard
144+
id={image.id}
145+
imageUrl={image.imageUrl}
146+
status={image.status}
147+
/>
148+
</div>
136149
))}
137150
</motion.div>
138151

@@ -148,50 +161,69 @@ export function Camera() {
148161
open={!!selectedImage}
149162
onOpenChange={() => setSelectedImage(null)}
150163
>
151-
<DialogContent className="max-w-4xl w-full bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
152-
<DialogHeader>
153-
<DialogTitle>{selectedImage?.prompt}</DialogTitle>
154-
<DialogDescription>
164+
<DialogContent className="max-w-7xl w-[95vw] p-6 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
165+
<DialogHeader className="mb-4">
166+
<DialogTitle className="text-2xl font-bold tracking-tight">
167+
{selectedImage?.prompt}
168+
</DialogTitle>
169+
<DialogDescription className="text-sm text-muted-foreground">
155170
Generated on{" "}
156171
{selectedImage?.createdAt
157-
? new Date(selectedImage.createdAt).toLocaleDateString()
172+
? new Date(selectedImage.createdAt).toLocaleDateString(
173+
undefined,
174+
{
175+
year: "numeric",
176+
month: "long",
177+
day: "numeric",
178+
}
179+
)
158180
: ""}
159181
</DialogDescription>
160182
</DialogHeader>
161183

162-
<div className="relative aspect-square w-full overflow-hidden rounded-lg">
184+
<div className="relative w-full h-[70vh] overflow-hidden rounded-lg bg-muted/30">
163185
{selectedImage && (
164-
<Image
165-
src={selectedImage.imageUrl}
166-
alt={selectedImage.prompt || "Generated image"}
167-
fill
168-
className="object-cover"
169-
priority
170-
/>
186+
<div className="group relative w-full h-full flex items-center justify-center">
187+
<Image
188+
src={selectedImage.imageUrl}
189+
alt={selectedImage.prompt || "Generated image"}
190+
fill
191+
className="object-contain transition-all duration-300 group-hover:scale-[1.02]"
192+
priority
193+
sizes="(max-width: 768px) 95vw, (max-width: 1200px) 85vw, 75vw"
194+
quality={100}
195+
/>
196+
<div className="absolute inset-0 bg-gradient-to-b from-black/5 to-black/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
197+
</div>
171198
)}
172199
</div>
173200

174-
<div className="flex justify-between items-center mt-4">
175-
<div className="flex gap-2">
201+
<div className="mt-6 flex justify-between items-center">
202+
<div className="flex gap-3">
176203
<Button
177204
variant="outline"
178205
size="icon"
179206
onClick={handlePrevious}
180207
disabled={currentImageIndex === 0}
208+
className="hover:bg-muted/80"
181209
>
182-
<ChevronLeft className="h-4 w-4" />
210+
<ChevronLeft className="h-5 w-5" />
183211
</Button>
184212
<Button
185213
variant="outline"
186214
size="icon"
187215
onClick={handleNext}
188216
disabled={currentImageIndex === images.length - 1}
217+
className="hover:bg-muted/80"
189218
>
190-
<ChevronRight className="h-4 w-4" />
219+
<ChevronRight className="h-5 w-5" />
191220
</Button>
192221
</div>
193222

194-
<div className="flex gap-2">
223+
<div className="flex items-center gap-3">
224+
<span className="text-sm text-muted-foreground">
225+
{currentImageIndex + 1} of {images.length}
226+
</span>
195227
<Button
196228
variant="outline"
197229
onClick={() =>
@@ -201,6 +233,7 @@ export function Camera() {
201233
selectedImage.prompt || "generated-image"
202234
)
203235
}
236+
className="hover:bg-muted/80"
204237
>
205238
<Download className="h-4 w-4 mr-2" />
206239
Download
@@ -209,6 +242,7 @@ export function Camera() {
209242
variant="outline"
210243
size="icon"
211244
onClick={() => setSelectedImage(null)}
245+
className="hover:bg-muted/80"
212246
>
213247
<X className="h-4 w-4" />
214248
</Button>

apps/web/next.config.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
11
/** @type {import('next').NextConfig} */
22
const nextConfig = {
33
images: {
4-
domains: [
5-
"r2-us-west.photoai.com",
6-
"r2-us-east.photoai.com",
7-
"i0.wp.com",
8-
"encrypted-tbn1.gstatic.com",
9-
"v3.fal.media",
4+
remotePatterns: [
5+
{
6+
protocol: "https",
7+
hostname: "r2-us-west.photoai.com",
8+
},
9+
{
10+
protocol: "https",
11+
hostname: "r2-us-east.photoai.com",
12+
},
13+
{
14+
protocol: "https",
15+
hostname: "i0.wp.com",
16+
},
17+
{
18+
protocol: "https",
19+
hostname: "encrypted-tbn1.gstatic.com",
20+
},
21+
{
22+
protocol: "https",
23+
hostname: "v3.fal.media",
24+
},
25+
{
26+
protocol: "https",
27+
hostname: "avatars.githubusercontent.com",
28+
},
29+
{
30+
protocol: "https",
31+
hostname: "cloudflare-ipfs.com",
32+
},
1033
],
1134
},
1235
};

0 commit comments

Comments
 (0)