diff --git a/apps/web/src/content/mdx.tsx b/apps/web/src/content/mdx.tsx index 667a0bf2a..6eef37e44 100644 --- a/apps/web/src/content/mdx.tsx +++ b/apps/web/src/content/mdx.tsx @@ -1,5 +1,6 @@ import { existsSync } from "node:fs"; import { join } from "node:path"; +import { getImageDimensions } from "@/lib/image-dimensions"; import { cn } from "@/lib/utils"; import { Button } from "@openstatus/ui"; import { MDXRemote, type MDXRemoteProps } from "next-mdx-remote/rsc"; @@ -241,7 +242,7 @@ function CustomImage({ className, ...props }: React.ComponentProps) { - const { src, alt, ...rest } = props; + const { src, alt, width, height, ...rest } = props; if (!src || typeof src !== "string") { return ( @@ -256,10 +257,9 @@ function CustomImage({ className={className} src={src} alt={alt ?? "image"} - width={0} - height={0} + fill sizes="100vw" - style={{ width: "100%", height: "auto" }} + style={{ objectFit: "contain" }} {...rest} /> @@ -268,6 +268,11 @@ function CustomImage({ ); } + // Get actual image dimensions from filesystem + const dimensions = getImageDimensions(src); + const imageWidth = width || dimensions?.width || 1200; + const imageHeight = height || dimensions?.height || 630; + // Generate dark mode image path by adding .dark before extension const getDarkImagePath = (path: string) => { const match = path.match(/^(.+)(\.[^.]+)$/); @@ -304,8 +309,8 @@ function CustomImage({ {...rest} src={src} alt={alt ?? ""} - width={0} - height={0} + width={imageWidth} + height={imageHeight} sizes="100vw" style={{ width: "100%", height: "auto" }} className={cn("block dark:hidden", className)} @@ -321,8 +326,8 @@ function CustomImage({ {...rest} src={useDarkImage ? darkSrc : src} alt={alt ?? ""} - width={0} - height={0} + width={imageWidth} + height={imageHeight} sizes="100vw" style={{ width: "100%", height: "auto" }} className={cn("hidden dark:block", className)} @@ -359,19 +364,25 @@ export const components = { }, }; +function MDXContent(props: MDXRemoteProps) { + return ( + + ); +} + export function CustomMDX(props: MDXRemoteProps) { return ( - + }> - + ); diff --git a/apps/web/src/content/pages/home.mdx b/apps/web/src/content/pages/home.mdx index a47fedb35..31d8450ba 100644 --- a/apps/web/src/content/pages/home.mdx +++ b/apps/web/src/content/pages/home.mdx @@ -15,7 +15,7 @@ category: "Product" /> -dashboard monitor overview +dashboard monitor overview ## Used by awesome folks diff --git a/apps/web/src/lib/image-dimensions.ts b/apps/web/src/lib/image-dimensions.ts new file mode 100644 index 000000000..2597b0582 --- /dev/null +++ b/apps/web/src/lib/image-dimensions.ts @@ -0,0 +1,75 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +interface ImageDimensions { + width: number; + height: number; +} + +/** + * Get image dimensions from PNG file + * PNG spec: width and height are stored at bytes 16-23 as 4-byte integers + */ +function getPngDimensions(buffer: Buffer): ImageDimensions { + const width = buffer.readUInt32BE(16); + const height = buffer.readUInt32BE(20); + return { width, height }; +} + +/** + * Get image dimensions from JPEG file + */ +function getJpegDimensions(buffer: Buffer): ImageDimensions { + let offset = 2; // Skip SOI marker + + while (offset < buffer.length) { + // Check for marker + if (buffer[offset] !== 0xff) break; + + const marker = buffer[offset + 1]; + offset += 2; + + // SOF markers (Start of Frame) + if ( + marker >= 0xc0 && + marker <= 0xcf && + marker !== 0xc4 && + marker !== 0xc8 && + marker !== 0xcc + ) { + const height = buffer.readUInt16BE(offset + 3); + const width = buffer.readUInt16BE(offset + 5); + return { width, height }; + } + + // Skip to next marker + const segmentLength = buffer.readUInt16BE(offset); + offset += segmentLength; + } + + throw new Error("Could not find JPEG dimensions"); +} + +/** + * Get dimensions for an image in the public directory + */ +export function getImageDimensions(publicPath: string): ImageDimensions | null { + try { + const fullPath = join(process.cwd(), "public", publicPath); + const buffer = readFileSync(fullPath); + + // Check file signature + if (buffer[0] === 0x89 && buffer.toString("ascii", 1, 4) === "PNG") { + return getPngDimensions(buffer); + } + + if (buffer[0] === 0xff && buffer[1] === 0xd8) { + return getJpegDimensions(buffer); + } + + return null; + } catch (error) { + console.warn(`Failed to get dimensions for ${publicPath}:`, error); + return null; + } +}