Skip to content

Commit 6c6b8a1

Browse files
committed
refactor to simplify logic
1 parent 50455a3 commit 6c6b8a1

File tree

3 files changed

+104
-84
lines changed

3 files changed

+104
-84
lines changed

src/components/docImage.tsx

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,42 @@ export default function DocImage({
5454
}
5555

5656
// parse the size from the URL hash (set by remark-image-size.js)
57-
const srcURL = new URL(src, 'https://example.com');
58-
const imgPath = srcURL.pathname;
59-
const dimensions = srcURL.hash // #wxh
60-
.slice(1)
61-
.split('x')
62-
.map(s => parseInt(s, 10));
57+
let srcURL: URL;
58+
let imgPath: string;
59+
let dimensions: number[] = [];
60+
61+
try {
62+
srcURL = new URL(src, 'https://example.com');
63+
imgPath = srcURL.pathname;
64+
dimensions = srcURL.hash // #wxh
65+
.slice(1)
66+
.split('x')
67+
.map(s => {
68+
const parsed = parseInt(s, 10);
69+
return isNaN(parsed) ? 0 : parsed;
70+
});
71+
} catch (_error) {
72+
// Failed to parse URL, fallback to using src directly
73+
imgPath = src;
74+
dimensions = [];
75+
}
76+
77+
// Helper function to safely parse dimension values
78+
const parseDimension = (
79+
value: string | number | undefined,
80+
fallback: number = 800
81+
): number => {
82+
if (typeof value === 'number' && value > 0) return value;
83+
if (typeof value === 'string') {
84+
const parsed = parseInt(value, 10);
85+
return parsed > 0 ? parsed : fallback;
86+
}
87+
return fallback;
88+
};
6389

6490
// Use parsed dimensions, fallback to props, then default to 800
65-
const width = !isNaN(dimensions[0])
66-
? dimensions[0]
67-
: typeof propsWidth === 'number'
68-
? propsWidth
69-
: typeof propsWidth === 'string'
70-
? parseInt(propsWidth, 10) || 800
71-
: 800;
72-
const height = !isNaN(dimensions[1])
73-
? dimensions[1]
74-
: typeof propsHeight === 'number'
75-
? propsHeight
76-
: typeof propsHeight === 'string'
77-
? parseInt(propsHeight, 10) || 800
78-
: 800;
91+
const width = dimensions[0] > 0 ? dimensions[0] : parseDimension(propsWidth);
92+
const height = dimensions[1] > 0 ? dimensions[1] : parseDimension(propsHeight);
7993

8094
return (
8195
<DocImageClient

src/components/docImageClient.tsx

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
'use client';
22

3-
import Image from 'next/image';
4-
53
import {ImageLightbox} from './imageLightbox';
64

75
interface DocImageClientProps
@@ -25,59 +23,16 @@ export function DocImageClient({
2523
className,
2624
...props
2725
}: DocImageClientProps) {
28-
// Check if dimensions are valid (not NaN) for Next.js Image
29-
const isValidDimensions = !isNaN(width) && !isNaN(height) && width > 0 && height > 0;
30-
31-
// For images with invalid dimensions, fall back to regular img tag
32-
if (!isValidDimensions) {
33-
const handleClick = () => {
34-
// Always open image in new tab
35-
const url = src.startsWith('http') ? src : imgPath;
36-
const newWindow = window.open(url, '_blank');
37-
if (newWindow) {
38-
newWindow.opener = null; // Security: prevent opener access
39-
}
40-
};
41-
42-
return (
43-
<div onClick={handleClick} className="cursor-pointer">
44-
{/* eslint-disable-next-line @next/next/no-img-element */}
45-
<img
46-
src={src}
47-
alt={alt ?? ''}
48-
style={{
49-
width: '100%',
50-
height: 'auto',
51-
...style,
52-
}}
53-
className={className}
54-
{...props}
55-
/>
56-
</div>
57-
);
58-
}
59-
6026
return (
6127
<ImageLightbox
6228
src={src}
6329
alt={alt ?? ''}
6430
width={width}
6531
height={height}
6632
imgPath={imgPath}
67-
>
68-
<Image
69-
src={src}
70-
width={width}
71-
height={height}
72-
style={{
73-
width: '100%',
74-
height: 'auto',
75-
...style,
76-
}}
77-
className={className}
78-
alt={alt ?? ''}
79-
{...props}
80-
/>
81-
</ImageLightbox>
33+
style={style}
34+
className={className}
35+
{...props}
36+
/>
8237
);
8338
}

src/components/imageLightbox.tsx

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import Image from 'next/image';
77

88
interface ImageLightboxProps {
99
alt: string;
10-
children: React.ReactNode;
1110
height: number;
1211
imgPath: string;
1312
src: string;
1413
width: number;
14+
className?: string;
15+
style?: React.CSSProperties;
1516
}
1617

1718
export function ImageLightbox({
@@ -20,10 +21,14 @@ export function ImageLightbox({
2021
width,
2122
height,
2223
imgPath,
23-
children,
24+
style,
25+
className,
2426
}: ImageLightboxProps) {
2527
const [open, setOpen] = useState(false);
2628

29+
// Check if dimensions are valid (not NaN) for Next.js Image
30+
const isValidDimensions = !isNaN(width) && !isNaN(height) && width > 0 && height > 0;
31+
2732
const handleClick = (e: React.MouseEvent) => {
2833
// If Ctrl/Cmd+click, open image in new tab
2934
if (e.ctrlKey || e.metaKey) {
@@ -56,6 +61,39 @@ export function ImageLightbox({
5661
}
5762
};
5863

64+
// Render the appropriate image component based on dimension validity
65+
const renderImage = () => {
66+
if (isValidDimensions) {
67+
return (
68+
<Image
69+
src={src}
70+
width={width}
71+
height={height}
72+
style={{
73+
width: '100%',
74+
height: 'auto',
75+
...style,
76+
}}
77+
className={className}
78+
alt={alt}
79+
/>
80+
);
81+
}
82+
return (
83+
/* eslint-disable-next-line @next/next/no-img-element */
84+
<img
85+
src={src}
86+
alt={alt}
87+
style={{
88+
width: '100%',
89+
height: 'auto',
90+
...style,
91+
}}
92+
className={className}
93+
/>
94+
);
95+
};
96+
5997
return (
6098
<Dialog.Root open={open} onOpenChange={setOpen}>
6199
{/* Custom trigger that handles modifier keys properly */}
@@ -67,7 +105,7 @@ export function ImageLightbox({
67105
onKeyDown={handleKeyDown}
68106
aria-label={`View image: ${alt}`}
69107
>
70-
{children}
108+
{renderImage()}
71109
</div>
72110

73111
<Dialog.Portal>
@@ -82,18 +120,31 @@ export function ImageLightbox({
82120

83121
{/* Image container */}
84122
<div className="relative flex items-center justify-center">
85-
<Image
86-
src={src}
87-
alt={alt}
88-
width={width}
89-
height={height}
90-
className="max-h-[90vh] max-w-[90vw] object-contain"
91-
style={{
92-
width: 'auto',
93-
height: 'auto',
94-
}}
95-
priority
96-
/>
123+
{isValidDimensions ? (
124+
<Image
125+
src={src}
126+
alt={alt}
127+
width={width}
128+
height={height}
129+
className="max-h-[90vh] max-w-[90vw] object-contain"
130+
style={{
131+
width: 'auto',
132+
height: 'auto',
133+
}}
134+
priority
135+
/>
136+
) : (
137+
/* eslint-disable-next-line @next/next/no-img-element */
138+
<img
139+
src={src}
140+
alt={alt}
141+
className="max-h-[90vh] max-w-[90vw] object-contain"
142+
style={{
143+
width: 'auto',
144+
height: 'auto',
145+
}}
146+
/>
147+
)}
97148
</div>
98149
</Dialog.Content>
99150
</Dialog.Portal>

0 commit comments

Comments
 (0)