From c5c1b15013e0249e4bda6e0658094f4ea525c3bd Mon Sep 17 00:00:00 2001 From: Stefan Imhoff Date: Sat, 24 Jan 2026 15:36:55 +0100 Subject: [PATCH] feat: add basic image component using the picture of Astro --- src/components/BasicImage.astro | 120 ++++++++++++++++++++++++++++++++ src/mdx-components.ts | 35 +++++----- 2 files changed, 139 insertions(+), 16 deletions(-) create mode 100644 src/components/BasicImage.astro diff --git a/src/components/BasicImage.astro b/src/components/BasicImage.astro new file mode 100644 index 0000000..a13c5a1 --- /dev/null +++ b/src/components/BasicImage.astro @@ -0,0 +1,120 @@ +--- +import { Picture } from 'astro:assets'; +import type { ImageMetadata } from 'astro'; +import TextLink from './TextLink.astro'; + +interface Props { + alt?: string; + caption?: string; + class?: string; + decoding?: 'async' | 'sync' | 'auto'; + height?: string | number; + loading?: 'lazy' | 'eager'; + noSpacing?: boolean; + quality?: number; + size?: 'regular' | 'wide' | 'fullsize'; + source?: string; + sourceUrl?: string; + src: string; + width?: string | number; +} + +const { + alt, + caption, + class: className, + decoding = 'async', + height, + loading = 'lazy', + noSpacing, + quality, + size, + source, + sourceUrl, + src, + width, + ...props +} = Astro.props; + +// Normalize dimensions +const parseDim = (dim: string | number | undefined) => (dim ? Number(dim) : undefined); +const parsedWidth = parseDim(width); +const parsedHeight = parseDim(height); + +// Resolve Image Source +let localImage: ImageMetadata | undefined; +let remoteImage: string = src; + +// Get all the image metadata +const images = import.meta.glob<{ default: ImageMetadata }>('/src/images/**/*'); + +if (src.startsWith('/images')) { + const key = '/src' + src; + const loader = images[key as keyof typeof images]; + + if (typeof loader === 'function') { + const mod = await loader(); + localImage = mod.default; + } +} + +// Define sizes attribute for responsive images +const sizes = '(max-width: 440px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 85vw, 1100px'; +--- + +
+
+ { + localImage ? ( + + ) : ( + {alt + ) + } +
+ { + (caption || source) && ( +
+ {caption} + {caption && source ? '–' : ''} + {source && + (sourceUrl ? ( + + {source} + + ) : ( + {source} + ))} +
+ ) + } +
diff --git a/src/mdx-components.ts b/src/mdx-components.ts index c698765..6cb3d72 100644 --- a/src/mdx-components.ts +++ b/src/mdx-components.ts @@ -3,6 +3,7 @@ import { YouTube } from '@astro-community/astro-embed-youtube'; import AmazonBook from './components/AmazonBook.astro'; import AppleTVFlag from './components/AppleTVFlag.astro'; import Banner from './components/Banner.astro'; +import BasicImage from './components/BasicImage.astro'; import Blockquote from './components/Blockquote.astro'; import Book from './components/Book.astro'; import Bookshelf from './components/Bookshelf.astro'; @@ -38,13 +39,11 @@ import UnorderedList from './components/UnorderedList.astro'; import Verse from './components/Verse.astro'; export const mapping = { - a: TextLink, - ProductLink, AmazonBook, AppleTVFlag, Banner, + BasicImage, Blockquote, - blockquote: Blockquote, Book, Bookshelf, ColorStack, @@ -54,6 +53,22 @@ export const mapping = { EmailLink, Figure, Flag, + Image, + MarkdownImage, + MoreLink, + NetflixFlag, + OdyseeVideo, + PrimeVideoFlag, + ProductLink, + ProjectIntro, + Pullquote, + Ruby, + Spotify, + ThemeBox, + Verse, + YouTube, + a: TextLink, + blockquote: Blockquote, h1: Title, h2: Headline, h3: Subheadline, @@ -61,24 +76,11 @@ export const mapping = { h5: Subsubheadline, h6: Subsubheadline, hr: Divider, - Image, img: MarkdownImage, li: ListItem, - MarkdownImage, - MoreLink, - NetflixFlag, - OdyseeVideo, ol: OrderedList, p: Text, - PrimeVideoFlag, - ProjectIntro, - Pullquote, - Ruby, - Spotify, - ThemeBox, ul: UnorderedList, - Verse, - YouTube, }; // Mapping for RSS feed to reduce the size of the feed @@ -86,6 +88,7 @@ export const rssMapping = { AmazonBook, AppleTVFlag, Banner, + BasicImage, Blockquote, Book, Bookshelf,