Skip to content

Instantly share code, notes, and snippets.

@haxibami
Created October 3, 2023 05:44
Show Gist options
  • Save haxibami/92fcacf891bb1af4c3b476c52385a529 to your computer and use it in GitHub Desktop.
Save haxibami/92fcacf891bb1af4c3b476c52385a529 to your computer and use it in GitHub Desktop.
A rehype plugin to wrap images inserted by markdown image directive (`![alt](src)`), within Astro contents
import { visit } from "unist-util-visit";
import { isMdxJsxAttribute, isMdxJsxFlowElement } from "./hast-util-node-is";
import type { Root } from "hast";
import type { Plugin } from "unified";
interface RehypeAstroFigureOptions {
/**
* Class names to add to the figure element.
* @default ["astro-figure"]
* */
figureClassName?: string[];
/**
* Class names to add to the div element wrapping the astro-image.
* @default ["astro-image-container"]
* */
imageContainerClassName?: string[];
/**
*
* Class names to add to the figcaption element.
* @default ["astro-figure-caption"]
* */
figCaptionClassName?: string[];
}
/**
* A rehype plugin to wrap astro-image elements in a figure element with a figcaption.
* @param options - Options to customize the class names of the figure, div, and figcaption elements.
* @returns A rehype plugin.
*/
const rehypeAstroFigure: Plugin<[RehypeAstroFigureOptions?], Root> = (
options,
) => {
const { figureClassName, imageContainerClassName, figCaptionClassName } = {
figureClassName: ["astro-figure"],
imageContainerClassName: ["astro-image-container"],
figCaptionClassName: ["astro-figure-caption"],
...options,
};
return (tree) => {
visit(tree, "element", (node, index, parent) => {
if (
node.tagName !== "p" ||
!parent ||
typeof index !== "number" ||
node.children.length !== 1 ||
!node.children[0] ||
!isMdxJsxFlowElement(node.children[0])
) {
return;
}
const child = node.children[0];
if (
!Object.hasOwn(child, "name") ||
!Object.hasOwn(child, "attributes") ||
child.type !== "mdxJsxFlowElement" ||
child.name !== "astro-image"
) {
return;
}
const alt = child.attributes
.find((attr) => isMdxJsxAttribute(attr) && attr.name === "alt")
?.value?.toString();
if (!alt) {
return;
}
parent.children[index] = {
type: "element",
tagName: "figure",
properties: {
className: figureClassName,
},
children: [
{
type: "element",
tagName: "div",
properties: {
className: imageContainerClassName,
},
children: [child],
},
{
type: "element",
tagName: "figcaption",
properties: {
className: figCaptionClassName,
},
children: [
{
type: "text",
value: alt,
},
],
},
],
};
});
};
};
export default rehypeAstroFigure;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment