diff --git a/README.md b/README.md index f5c1af6..4d51e91 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,22 @@ export default defineConfig({ ![](assets/presets/brandedLogo.png) +### `customProperty` + +```diff +import opengraphImages, { presets } from "astro-opengraph-images"; + +export default defineConfig({ + integrations: [ + opengraphImages({ ++ render: presets.customProperty, + }), + ], +}); +``` + +![](assets/presets/customProperty.png) + ### `gradients` ```diff diff --git a/assets/presets/customProperty.png b/assets/presets/customProperty.png new file mode 100644 index 0000000..b6f7cc1 Binary files /dev/null and b/assets/presets/customProperty.png differ diff --git a/example/astro.config.mjs b/example/astro.config.mjs index 797dcb8..e064394 100644 --- a/example/astro.config.mjs +++ b/example/astro.config.mjs @@ -16,7 +16,7 @@ export default defineConfig({ }, ], }, - render: presets.blackAndWhite, + render: presets.customProperty, }), ], }); diff --git a/src/hook.ts b/src/hook.ts index 0bc33ba..3ee6679 100644 --- a/src/hook.ts +++ b/src/hook.ts @@ -41,7 +41,7 @@ async function handlePage({ page, options, render, dir, logger }: HandlePageInpu const html = fs.readFileSync(htmlFile).toString(); const pageDetails = extract(html); - const reactNode = await render({ ...page, ...pageDetails }); + const reactNode = await render({ ...page, ...pageDetails, dir: dir }); const svg = await satori(reactNode, options); const resvg = new Resvg(svg, { font: { diff --git a/src/presets/customProperty.tsx b/src/presets/customProperty.tsx new file mode 100644 index 0000000..74fdb24 --- /dev/null +++ b/src/presets/customProperty.tsx @@ -0,0 +1,32 @@ +import { fileURLToPath } from "url"; +import { sanitizeHtml } from "../extract.js"; +import type { RenderFunctionInput } from "../types.js"; +import { getFilePath } from "../util.js"; +import * as jsdom from "jsdom"; +import * as fs from "fs"; + +// This preset demonstrates how to extract arbitrary content from an HTML file +// and render it in an opengraph image. +export async function customProperty({ title, pathname, dir }: RenderFunctionInput): Promise { + const htmlFile = getFilePath({ dir: fileURLToPath(dir), page: pathname }); + const html = fs.readFileSync(htmlFile).toString(); + const htmlDoc = new jsdom.JSDOM(sanitizeHtml(html)).window.document; + + // extract the body + const body = htmlDoc.querySelector("body")?.textContent ?? ""; + // truncate the body to 50 characters, add ellipsis if truncated + const bodyTruncated = body.substring(0, 50) + (body.length > 50 ? "..." : ""); + + const twj = (await import("tw-to-css")).twj; + + return ( +
+
+
+

{title}

+
{bodyTruncated}
+
+
+
+ ); +} diff --git a/src/presets/index.ts b/src/presets/index.ts index c4ae1ee..0111bd1 100644 --- a/src/presets/index.ts +++ b/src/presets/index.ts @@ -1,6 +1,7 @@ import { backgroundImage } from "./backgroundImage.js"; import { blackAndWhite } from "./blackAndWhite.js"; import { brandedLogo } from "./brandedLogo.js"; +import { customProperty } from "./customProperty.js"; import { gradients } from "./gradients.js"; import { podcast } from "./podcast.js"; import { rauchg } from "./rauchg.js"; @@ -20,4 +21,5 @@ export const presets = { podcast, simpleBlog, waveSvg, + customProperty, }; diff --git a/src/presets/renderExamples.ts b/src/presets/renderExamples.ts index 58e4c59..7a66e18 100644 --- a/src/presets/renderExamples.ts +++ b/src/presets/renderExamples.ts @@ -13,7 +13,8 @@ async function renderExamples() { url: "https://example.com/3d-graphics", type: "article", image: "https://example.com/3d-graphics.png", - pathname: "empty", + pathname: "dist/index/", + dir: new URL("../../example", import.meta.url), }; const options: SatoriOptions = { diff --git a/src/types.ts b/src/types.ts index c4bbb5d..9dc39eb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -35,6 +35,7 @@ export interface AstroBuildDoneHookInput { /** The input arguments to a `RenderFunction` */ export type RenderFunctionInput = { pathname: string; + dir: URL; } & PageDetails; /** A function that renders some page input to React */