Skip to content

Commit c64dc5d

Browse files
committed
v3 updates
1 parent df6ed42 commit c64dc5d

15 files changed

Lines changed: 1770 additions & 331 deletions

app/global.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,8 @@ figure:has(> pre) {
8282

8383
:is(.dark .shadow-2xl) {
8484
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
85+
}
86+
87+
button[type="button"] {
88+
cursor: pointer;
8589
}

components/screenshot.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import Link from 'next/link'
5+
6+
interface ScreenshotProps extends React.ImgHTMLAttributes<HTMLImageElement> {
7+
src: string
8+
alt?: string
9+
href?: string
10+
}
11+
12+
export function Screenshot({ src, alt, href, className, ...props }: ScreenshotProps) {
13+
const [isOpen, setIsOpen] = useState(false)
14+
15+
const imgClasses = `rounded-lg hover:shadow border border-gray-200 dark:border-gray-700 ${className || ''}`
16+
17+
const img = (
18+
<img
19+
src={src}
20+
alt={alt}
21+
className={imgClasses}
22+
{...props}
23+
/>
24+
)
25+
26+
// If href is provided, wrap in a link
27+
if (href) {
28+
const isExternal = href.startsWith('https://') || href.startsWith('http://')
29+
30+
if (isExternal) {
31+
return (
32+
<a href={href} target="_blank" rel="noopener noreferrer" className="not-prose">
33+
{img}
34+
</a>
35+
)
36+
}
37+
38+
return (
39+
<Link href={href} className="not-prose">
40+
{img}
41+
</Link>
42+
)
43+
}
44+
45+
// Otherwise, make it clickable to open in a modal
46+
return (
47+
<>
48+
<button
49+
onClick={() => setIsOpen(true)}
50+
className="not-prose cursor-zoom-in block"
51+
aria-label="Open image in full size"
52+
>
53+
{img}
54+
</button>
55+
56+
{isOpen && (
57+
<div
58+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 p-4"
59+
onClick={() => setIsOpen(false)}
60+
>
61+
<div className="relative max-h-full max-w-full">
62+
<img
63+
src={src}
64+
alt={alt}
65+
className="max-h-[90vh] max-w-full object-contain"
66+
onClick={(e) => e.stopPropagation()}
67+
/>
68+
<button
69+
onClick={() => setIsOpen(false)}
70+
className="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold"
71+
aria-label="Close"
72+
>
73+
×
74+
</button>
75+
</div>
76+
</div>
77+
)}
78+
</>
79+
)
80+
}

components/screenshots-gallery.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export function ScreenshotsGallery({ images, className, gridClass }: Screenshots
7676
}, [lightboxOpen, closeLightbox, nextImage, previousImage, imageKeys.length]);
7777

7878
return (
79-
<div className={className ?? "not-prose my-16"}>
79+
<div className={className ?? "not-prose my-8"}>
8080
{/* Gallery Grid */}
8181
<div className={gridClass || 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8'}>
8282
{Object.entries(images).map(([title, imageUrl]) => (

0 commit comments

Comments
 (0)